]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
treeview: Update adjustment usage for sealing
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include "config.h"
22
23 #include <math.h>
24 #include <string.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmainprivate.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtkalignment.h"
36 #include "gtklabel.h"
37 #include "gtkhbox.h"
38 #include "gtkvbox.h"
39 #include "gtkarrow.h"
40 #include "gtkintl.h"
41 #include "gtkbindings.h"
42 #include "gtkcontainer.h"
43 #include "gtkentry.h"
44 #include "gtkframe.h"
45 #include "gtktreemodelsort.h"
46 #include "gtktooltip.h"
47 #include "gtkscrollable.h"
48 #include "gtkcelllayout.h"
49 #include "gtkprivate.h"
50 #include "gtkwidgetprivate.h"
51 #include "gtkentryprivate.h"
52 #include "gtktypebuiltins.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 void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
607                                                     GtkWidget        *child);
608 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
609                                                     GdkEventFocus    *event);
610 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
611                                                     GtkDirectionType  direction);
612 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
613 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
614                                                     GtkStyle         *previous_style);
615 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
616                                                     gboolean          was_grabbed);
617 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
618                                                     GtkStateType      previous_state);
619
620 /* container signals */
621 static void     gtk_tree_view_remove               (GtkContainer     *container,
622                                                     GtkWidget        *widget);
623 static void     gtk_tree_view_forall               (GtkContainer     *container,
624                                                     gboolean          include_internals,
625                                                     GtkCallback       callback,
626                                                     gpointer          callback_data);
627
628 /* Source side drag signals */
629 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
630                                             GdkDragContext   *context);
631 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
632                                             GdkDragContext   *context);
633 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
634                                             GdkDragContext   *context,
635                                             GtkSelectionData *selection_data,
636                                             guint             info,
637                                             guint             time);
638 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
639                                             GdkDragContext   *context);
640
641 /* Target side drag signals */
642 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
643                                                   GdkDragContext   *context,
644                                                   guint             time);
645 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
646                                                   GdkDragContext   *context,
647                                                   gint              x,
648                                                   gint              y,
649                                                   guint             time);
650 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
651                                                   GdkDragContext   *context,
652                                                   gint              x,
653                                                   gint              y,
654                                                   guint             time);
655 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
656                                                   GdkDragContext   *context,
657                                                   gint              x,
658                                                   gint              y,
659                                                   GtkSelectionData *selection_data,
660                                                   guint             info,
661                                                   guint             time);
662
663 /* tree_model signals */
664 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
665                                                            GtkAdjustment   *adjustment);
666 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
667                                                            GtkAdjustment   *adjustment);
668 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
669                                                            GtkMovementStep  step,
670                                                            gint             count);
671 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
672 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
673 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
674                                                            gboolean         start_editing);
675 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
676 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
677                                                                gboolean         logical,
678                                                                gboolean         expand,
679                                                                gboolean         open_all);
680 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
681 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
682                                                            GtkTreePath     *path,
683                                                            GtkTreeIter     *iter,
684                                                            gpointer         data);
685 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
686                                                            GtkTreePath     *path,
687                                                            GtkTreeIter     *iter,
688                                                            gpointer         data);
689 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
690                                                            GtkTreePath     *path,
691                                                            GtkTreeIter     *iter,
692                                                            gpointer         data);
693 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
694                                                            GtkTreePath     *path,
695                                                            gpointer         data);
696 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
697                                                            GtkTreePath     *parent,
698                                                            GtkTreeIter     *iter,
699                                                            gint            *new_order,
700                                                            gpointer         data);
701
702 /* Incremental reflow */
703 static gboolean validate_row             (GtkTreeView *tree_view,
704                                           GtkRBTree   *tree,
705                                           GtkRBNode   *node,
706                                           GtkTreeIter *iter,
707                                           GtkTreePath *path);
708 static void     validate_visible_area    (GtkTreeView *tree_view);
709 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
710 static gboolean do_validate_rows         (GtkTreeView *tree_view,
711                                           gboolean     size_request);
712 static gboolean validate_rows            (GtkTreeView *tree_view);
713 static gboolean presize_handler_callback (gpointer     data);
714 static void     install_presize_handler  (GtkTreeView *tree_view);
715 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
716 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
717                                              GtkTreePath *path,
718                                              gint         offset);
719 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
720 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
721 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
722
723 /* Internal functions */
724 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
725                                                               GtkTreeViewColumn  *column);
726 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
727 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
728                                                               guint               keyval,
729                                                               guint               modmask,
730                                                               gboolean            add_shifted_binding,
731                                                               GtkMovementStep     step,
732                                                               gint                count);
733 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
734                                                               GtkRBTree          *tree);
735 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
736                                                               GtkTreePath        *path,
737                                                               const GdkRectangle *clip_rect);
738 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
739                                                               GtkRBTree          *tree,
740                                                               GtkRBNode          *node);
741 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
742                                                               cairo_t            *cr,
743                                                               GtkRBTree          *tree,
744                                                               GtkRBNode          *node,
745                                                               gint                x,
746                                                               gint                y);
747 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
748                                                               GtkRBTree          *tree,
749                                                               gint               *x1,
750                                                               gint               *x2);
751 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
752                                                               gint                i,
753                                                               gint               *x);
754 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
755                                                               GtkTreeView        *tree_view);
756 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
757                                                               GtkRBTree          *tree,
758                                                               GtkTreeIter        *iter,
759                                                               gint                depth,
760                                                               gboolean            recurse);
761 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
762                                                               GtkRBTree          *tree,
763                                                               GtkRBNode          *node);
764 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
765                                                               GtkTreeViewColumn  *column,
766                                                               gboolean            focus_to_cell);
767 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
768                                                               GdkEventMotion     *event);
769 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
770 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
771                                                               gint                count);
772 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
773                                                               gint                count);
774 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
775                                                               gint                count);
776 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
777                                                               gint                count);
778 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
779                                                               GtkTreePath        *path,
780                                                               GtkRBTree          *tree,
781                                                               GtkRBNode          *node,
782                                                               gboolean            animate);
783 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
784                                                               GtkTreePath        *path,
785                                                               GtkRBTree          *tree,
786                                                               GtkRBNode          *node,
787                                                               gboolean            open_all,
788                                                               gboolean            animate);
789 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
790                                                               GtkTreePath        *path,
791                                                               gboolean            clear_and_select,
792                                                               gboolean            clamp_node);
793 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
794 static void     column_sizing_notify                         (GObject            *object,
795                                                               GParamSpec         *pspec,
796                                                               gpointer            data);
797 static gboolean expand_collapse_timeout                      (gpointer            data);
798 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
799                                                               GtkRBTree          *tree,
800                                                               GtkRBNode          *node,
801                                                               gboolean            expand);
802 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
803 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
804 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
805 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
806 static void     update_prelight                              (GtkTreeView        *tree_view,
807                                                               int                 x,
808                                                               int                 y);
809
810 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
811
812 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
813                                                               GtkRBTree   *tree,
814                                                               GtkRBNode   *node,
815                                                               gint         vertical_separator);
816 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
817                                                               GtkRBNode   *node,
818                                                               gint         vertical_separator);
819
820 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
821                                                               GtkRBTree   *tree,
822                                                               GtkRBNode   *node);
823 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
824                                                               GtkRBNode   *node);
825
826 /* interactive search */
827 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
828 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
829                                                          GtkTreeView      *tree_view,
830                                                          GdkDevice        *device);
831 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
832                                                          GtkWidget        *search_dialog,
833                                                          gpointer          user_data);
834 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
835                                                          GtkMenu          *menu,
836                                                          gpointer          data);
837 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
838                                                          GtkTreeView      *tree_view);
839 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
840                                                          GtkTreeView      *tree_view);
841 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
842 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
843                                                          gpointer          data);
844 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
845                                                          GdkEventAny      *event,
846                                                          GtkTreeView      *tree_view);
847 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
848                                                          GdkEventButton   *event,
849                                                          GtkTreeView      *tree_view);
850 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
851                                                          GdkEventScroll   *event,
852                                                          GtkTreeView      *tree_view);
853 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
854                                                          GdkEventKey      *event,
855                                                          GtkTreeView      *tree_view);
856 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
857                                                          GtkTreeView      *tree_view,
858                                                          gboolean          up);
859 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
860                                                          gint              column,
861                                                          const gchar      *key,
862                                                          GtkTreeIter      *iter,
863                                                          gpointer          search_data);
864 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
865                                                          GtkTreeSelection *selection,
866                                                          GtkTreeIter      *iter,
867                                                          const gchar      *text,
868                                                          gint             *count,
869                                                          gint              n);
870 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
871                                                          GtkTreeView      *tree_view);
872 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
873                                                          GtkWidget        *child_widget,
874                                                          gint              x,
875                                                          gint              y,
876                                                          gint              width,
877                                                          gint              height);
878 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
879                                                          GtkTreePath      *cursor_path,
880                                                          gboolean          edit_only);
881 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
882                                                          gboolean     cancel_editing);
883 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
884                                                              GdkDevice   *device,
885                                                              gboolean     keybinding);
886 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
887 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
888                                                          GtkTreeViewColumn *column,
889                                                          gint               drop_position);
890
891 /* GtkBuildable */
892 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
893                                                             GtkBuilder        *builder,
894                                                             GObject           *child,
895                                                             const gchar       *type);
896 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
897                                                             GtkBuilder        *builder,
898                                                             const gchar       *childname);
899 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
900
901
902 static gboolean scroll_row_timeout                   (gpointer     data);
903 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
904 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
905
906 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
907
908 \f
909
910 /* GType Methods
911  */
912
913 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
914                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
915                                                 gtk_tree_view_buildable_init)
916                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
917
918 static void
919 gtk_tree_view_class_init (GtkTreeViewClass *class)
920 {
921   GObjectClass *o_class;
922   GtkWidgetClass *widget_class;
923   GtkContainerClass *container_class;
924   GtkBindingSet *binding_set;
925
926   binding_set = gtk_binding_set_by_class (class);
927
928   o_class = (GObjectClass *) class;
929   widget_class = (GtkWidgetClass *) class;
930   container_class = (GtkContainerClass *) class;
931
932   /* GObject signals */
933   o_class->set_property = gtk_tree_view_set_property;
934   o_class->get_property = gtk_tree_view_get_property;
935   o_class->finalize = gtk_tree_view_finalize;
936
937   /* GtkWidget signals */
938   widget_class->destroy = gtk_tree_view_destroy;
939   widget_class->map = gtk_tree_view_map;
940   widget_class->realize = gtk_tree_view_realize;
941   widget_class->unrealize = gtk_tree_view_unrealize;
942   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
943   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
944   widget_class->size_allocate = gtk_tree_view_size_allocate;
945   widget_class->button_press_event = gtk_tree_view_button_press;
946   widget_class->button_release_event = gtk_tree_view_button_release;
947   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
948   /*widget_class->configure_event = gtk_tree_view_configure;*/
949   widget_class->motion_notify_event = gtk_tree_view_motion;
950   widget_class->draw = gtk_tree_view_draw;
951   widget_class->key_press_event = gtk_tree_view_key_press;
952   widget_class->key_release_event = gtk_tree_view_key_release;
953   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
954   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
955   widget_class->focus_out_event = gtk_tree_view_focus_out;
956   widget_class->drag_begin = gtk_tree_view_drag_begin;
957   widget_class->drag_end = gtk_tree_view_drag_end;
958   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
959   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
960   widget_class->drag_leave = gtk_tree_view_drag_leave;
961   widget_class->drag_motion = gtk_tree_view_drag_motion;
962   widget_class->drag_drop = gtk_tree_view_drag_drop;
963   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
964   widget_class->focus = gtk_tree_view_focus;
965   widget_class->grab_focus = gtk_tree_view_grab_focus;
966   widget_class->style_set = gtk_tree_view_style_set;
967   widget_class->grab_notify = gtk_tree_view_grab_notify;
968   widget_class->state_changed = gtk_tree_view_state_changed;
969
970   /* GtkContainer signals */
971   container_class->remove = gtk_tree_view_remove;
972   container_class->forall = gtk_tree_view_forall;
973   container_class->set_focus_child = gtk_tree_view_set_focus_child;
974
975   class->move_cursor = gtk_tree_view_real_move_cursor;
976   class->select_all = gtk_tree_view_real_select_all;
977   class->unselect_all = gtk_tree_view_real_unselect_all;
978   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
979   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
980   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
981   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
982   class->start_interactive_search = gtk_tree_view_start_interactive_search;
983
984   /* Properties */
985
986   g_object_class_install_property (o_class,
987                                    PROP_MODEL,
988                                    g_param_spec_object ("model",
989                                                         P_("TreeView Model"),
990                                                         P_("The model for the tree view"),
991                                                         GTK_TYPE_TREE_MODEL,
992                                                         GTK_PARAM_READWRITE));
993
994   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
995   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
996   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
997   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
998
999   g_object_class_install_property (o_class,
1000                                    PROP_HEADERS_VISIBLE,
1001                                    g_param_spec_boolean ("headers-visible",
1002                                                          P_("Headers Visible"),
1003                                                          P_("Show the column header buttons"),
1004                                                          TRUE,
1005                                                          GTK_PARAM_READWRITE));
1006
1007   g_object_class_install_property (o_class,
1008                                    PROP_HEADERS_CLICKABLE,
1009                                    g_param_spec_boolean ("headers-clickable",
1010                                                          P_("Headers Clickable"),
1011                                                          P_("Column headers respond to click events"),
1012                                                          TRUE,
1013                                                          GTK_PARAM_READWRITE));
1014
1015   g_object_class_install_property (o_class,
1016                                    PROP_EXPANDER_COLUMN,
1017                                    g_param_spec_object ("expander-column",
1018                                                         P_("Expander Column"),
1019                                                         P_("Set the column for the expander column"),
1020                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1021                                                         GTK_PARAM_READWRITE));
1022
1023   g_object_class_install_property (o_class,
1024                                    PROP_REORDERABLE,
1025                                    g_param_spec_boolean ("reorderable",
1026                                                          P_("Reorderable"),
1027                                                          P_("View is reorderable"),
1028                                                          FALSE,
1029                                                          GTK_PARAM_READWRITE));
1030
1031   g_object_class_install_property (o_class,
1032                                    PROP_RULES_HINT,
1033                                    g_param_spec_boolean ("rules-hint",
1034                                                          P_("Rules Hint"),
1035                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1036                                                          FALSE,
1037                                                          GTK_PARAM_READWRITE));
1038
1039     g_object_class_install_property (o_class,
1040                                      PROP_ENABLE_SEARCH,
1041                                      g_param_spec_boolean ("enable-search",
1042                                                            P_("Enable Search"),
1043                                                            P_("View allows user to search through columns interactively"),
1044                                                            TRUE,
1045                                                            GTK_PARAM_READWRITE));
1046
1047     g_object_class_install_property (o_class,
1048                                      PROP_SEARCH_COLUMN,
1049                                      g_param_spec_int ("search-column",
1050                                                        P_("Search Column"),
1051                                                        P_("Model column to search through during interactive search"),
1052                                                        -1,
1053                                                        G_MAXINT,
1054                                                        -1,
1055                                                        GTK_PARAM_READWRITE));
1056
1057     /**
1058      * GtkTreeView:fixed-height-mode:
1059      *
1060      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1061      * #GtkTreeView by assuming that all rows have the same height. 
1062      * Only enable this option if all rows are the same height.  
1063      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1064      * information on this option.
1065      *
1066      * Since: 2.4
1067      **/
1068     g_object_class_install_property (o_class,
1069                                      PROP_FIXED_HEIGHT_MODE,
1070                                      g_param_spec_boolean ("fixed-height-mode",
1071                                                            P_("Fixed Height Mode"),
1072                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1073                                                            FALSE,
1074                                                            GTK_PARAM_READWRITE));
1075     
1076     /**
1077      * GtkTreeView:hover-selection:
1078      * 
1079      * Enables or disables the hover selection mode of @tree_view.
1080      * Hover selection makes the selected row follow the pointer.
1081      * Currently, this works only for the selection modes 
1082      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1083      *
1084      * This mode is primarily intended for treeviews in popups, e.g.
1085      * in #GtkComboBox or #GtkEntryCompletion.
1086      *
1087      * Since: 2.6
1088      */
1089     g_object_class_install_property (o_class,
1090                                      PROP_HOVER_SELECTION,
1091                                      g_param_spec_boolean ("hover-selection",
1092                                                            P_("Hover Selection"),
1093                                                            P_("Whether the selection should follow the pointer"),
1094                                                            FALSE,
1095                                                            GTK_PARAM_READWRITE));
1096
1097     /**
1098      * GtkTreeView:hover-expand:
1099      * 
1100      * Enables or disables the hover expansion mode of @tree_view.
1101      * Hover expansion makes rows expand or collapse if the pointer moves 
1102      * over them.
1103      *
1104      * This mode is primarily intended for treeviews in popups, e.g.
1105      * in #GtkComboBox or #GtkEntryCompletion.
1106      *
1107      * Since: 2.6
1108      */
1109     g_object_class_install_property (o_class,
1110                                      PROP_HOVER_EXPAND,
1111                                      g_param_spec_boolean ("hover-expand",
1112                                                            P_("Hover Expand"),
1113                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1114                                                            FALSE,
1115                                                            GTK_PARAM_READWRITE));
1116
1117     /**
1118      * GtkTreeView:show-expanders:
1119      *
1120      * %TRUE if the view has expanders.
1121      *
1122      * Since: 2.12
1123      */
1124     g_object_class_install_property (o_class,
1125                                      PROP_SHOW_EXPANDERS,
1126                                      g_param_spec_boolean ("show-expanders",
1127                                                            P_("Show Expanders"),
1128                                                            P_("View has expanders"),
1129                                                            TRUE,
1130                                                            GTK_PARAM_READWRITE));
1131
1132     /**
1133      * GtkTreeView:level-indentation:
1134      *
1135      * Extra indentation for each level.
1136      *
1137      * Since: 2.12
1138      */
1139     g_object_class_install_property (o_class,
1140                                      PROP_LEVEL_INDENTATION,
1141                                      g_param_spec_int ("level-indentation",
1142                                                        P_("Level Indentation"),
1143                                                        P_("Extra indentation for each level"),
1144                                                        0,
1145                                                        G_MAXINT,
1146                                                        0,
1147                                                        GTK_PARAM_READWRITE));
1148
1149     g_object_class_install_property (o_class,
1150                                      PROP_RUBBER_BANDING,
1151                                      g_param_spec_boolean ("rubber-banding",
1152                                                            P_("Rubber Banding"),
1153                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1154                                                            FALSE,
1155                                                            GTK_PARAM_READWRITE));
1156
1157     g_object_class_install_property (o_class,
1158                                      PROP_ENABLE_GRID_LINES,
1159                                      g_param_spec_enum ("enable-grid-lines",
1160                                                         P_("Enable Grid Lines"),
1161                                                         P_("Whether grid lines should be drawn in the tree view"),
1162                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1163                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1164                                                         GTK_PARAM_READWRITE));
1165
1166     g_object_class_install_property (o_class,
1167                                      PROP_ENABLE_TREE_LINES,
1168                                      g_param_spec_boolean ("enable-tree-lines",
1169                                                            P_("Enable Tree Lines"),
1170                                                            P_("Whether tree lines should be drawn in the tree view"),
1171                                                            FALSE,
1172                                                            GTK_PARAM_READWRITE));
1173
1174     g_object_class_install_property (o_class,
1175                                      PROP_TOOLTIP_COLUMN,
1176                                      g_param_spec_int ("tooltip-column",
1177                                                        P_("Tooltip Column"),
1178                                                        P_("The column in the model containing the tooltip texts for the rows"),
1179                                                        -1,
1180                                                        G_MAXINT,
1181                                                        -1,
1182                                                        GTK_PARAM_READWRITE));
1183
1184   /* Style properties */
1185 #define _TREE_VIEW_EXPANDER_SIZE 12
1186 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1187 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1188
1189   gtk_widget_class_install_style_property (widget_class,
1190                                            g_param_spec_int ("expander-size",
1191                                                              P_("Expander Size"),
1192                                                              P_("Size of the expander arrow"),
1193                                                              0,
1194                                                              G_MAXINT,
1195                                                              _TREE_VIEW_EXPANDER_SIZE,
1196                                                              GTK_PARAM_READABLE));
1197
1198   gtk_widget_class_install_style_property (widget_class,
1199                                            g_param_spec_int ("vertical-separator",
1200                                                              P_("Vertical Separator Width"),
1201                                                              P_("Vertical space between cells.  Must be an even number"),
1202                                                              0,
1203                                                              G_MAXINT,
1204                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1205                                                              GTK_PARAM_READABLE));
1206
1207   gtk_widget_class_install_style_property (widget_class,
1208                                            g_param_spec_int ("horizontal-separator",
1209                                                              P_("Horizontal Separator Width"),
1210                                                              P_("Horizontal space between cells.  Must be an even number"),
1211                                                              0,
1212                                                              G_MAXINT,
1213                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1214                                                              GTK_PARAM_READABLE));
1215
1216   gtk_widget_class_install_style_property (widget_class,
1217                                            g_param_spec_boolean ("allow-rules",
1218                                                                  P_("Allow Rules"),
1219                                                                  P_("Allow drawing of alternating color rows"),
1220                                                                  TRUE,
1221                                                                  GTK_PARAM_READABLE));
1222
1223   gtk_widget_class_install_style_property (widget_class,
1224                                            g_param_spec_boolean ("indent-expanders",
1225                                                                  P_("Indent Expanders"),
1226                                                                  P_("Make the expanders indented"),
1227                                                                  TRUE,
1228                                                                  GTK_PARAM_READABLE));
1229
1230   gtk_widget_class_install_style_property (widget_class,
1231                                            g_param_spec_boxed ("even-row-color",
1232                                                                P_("Even Row Color"),
1233                                                                P_("Color to use for even rows"),
1234                                                                GDK_TYPE_COLOR,
1235                                                                GTK_PARAM_READABLE));
1236
1237   gtk_widget_class_install_style_property (widget_class,
1238                                            g_param_spec_boxed ("odd-row-color",
1239                                                                P_("Odd Row Color"),
1240                                                                P_("Color to use for odd rows"),
1241                                                                GDK_TYPE_COLOR,
1242                                                                GTK_PARAM_READABLE));
1243
1244   gtk_widget_class_install_style_property (widget_class,
1245                                            g_param_spec_int ("grid-line-width",
1246                                                              P_("Grid line width"),
1247                                                              P_("Width, in pixels, of the tree view grid lines"),
1248                                                              0, G_MAXINT, 1,
1249                                                              GTK_PARAM_READABLE));
1250
1251   gtk_widget_class_install_style_property (widget_class,
1252                                            g_param_spec_int ("tree-line-width",
1253                                                              P_("Tree line width"),
1254                                                              P_("Width, in pixels, of the tree view lines"),
1255                                                              0, G_MAXINT, 1,
1256                                                              GTK_PARAM_READABLE));
1257
1258   gtk_widget_class_install_style_property (widget_class,
1259                                            g_param_spec_string ("grid-line-pattern",
1260                                                                 P_("Grid line pattern"),
1261                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1262                                                                 "\1\1",
1263                                                                 GTK_PARAM_READABLE));
1264
1265   gtk_widget_class_install_style_property (widget_class,
1266                                            g_param_spec_string ("tree-line-pattern",
1267                                                                 P_("Tree line pattern"),
1268                                                                 P_("Dash pattern used to draw the tree view lines"),
1269                                                                 "\1\1",
1270                                                                 GTK_PARAM_READABLE));
1271
1272   /* Signals */
1273   /**
1274    * GtkTreeView::row-activated:
1275    * @tree_view: the object on which the signal is emitted
1276    * @path: the #GtkTreePath for the activated row
1277    * @column: the #GtkTreeViewColumn in which the activation occurred
1278    *
1279    * The "row-activated" signal is emitted when the method
1280    * gtk_tree_view_row_activated() is called or the user double clicks 
1281    * a treeview row. It is also emitted when a non-editable row is 
1282    * selected and one of the keys: Space, Shift+Space, Return or 
1283    * Enter is pressed.
1284    * 
1285    * For selection handling refer to the <link linkend="TreeWidget">tree 
1286    * widget conceptual overview</link> as well as #GtkTreeSelection.
1287    */
1288   tree_view_signals[ROW_ACTIVATED] =
1289     g_signal_new (I_("row-activated"),
1290                   G_TYPE_FROM_CLASS (o_class),
1291                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1292                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1293                   NULL, NULL,
1294                   _gtk_marshal_VOID__BOXED_OBJECT,
1295                   G_TYPE_NONE, 2,
1296                   GTK_TYPE_TREE_PATH,
1297                   GTK_TYPE_TREE_VIEW_COLUMN);
1298
1299   /**
1300    * GtkTreeView::test-expand-row:
1301    * @tree_view: the object on which the signal is emitted
1302    * @iter: the tree iter of the row to expand
1303    * @path: a tree path that points to the row 
1304    * 
1305    * The given row is about to be expanded (show its children nodes). Use this
1306    * signal if you need to control the expandability of individual rows.
1307    *
1308    * Returns: %FALSE to allow expansion, %TRUE to reject
1309    */
1310   tree_view_signals[TEST_EXPAND_ROW] =
1311     g_signal_new (I_("test-expand-row"),
1312                   G_TYPE_FROM_CLASS (o_class),
1313                   G_SIGNAL_RUN_LAST,
1314                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1315                   _gtk_boolean_handled_accumulator, NULL,
1316                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1317                   G_TYPE_BOOLEAN, 2,
1318                   GTK_TYPE_TREE_ITER,
1319                   GTK_TYPE_TREE_PATH);
1320
1321   /**
1322    * GtkTreeView::test-collapse-row:
1323    * @tree_view: the object on which the signal is emitted
1324    * @iter: the tree iter of the row to collapse
1325    * @path: a tree path that points to the row 
1326    * 
1327    * The given row is about to be collapsed (hide its children nodes). Use this
1328    * signal if you need to control the collapsibility of individual rows.
1329    *
1330    * Returns: %FALSE to allow collapsing, %TRUE to reject
1331    */
1332   tree_view_signals[TEST_COLLAPSE_ROW] =
1333     g_signal_new (I_("test-collapse-row"),
1334                   G_TYPE_FROM_CLASS (o_class),
1335                   G_SIGNAL_RUN_LAST,
1336                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1337                   _gtk_boolean_handled_accumulator, NULL,
1338                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1339                   G_TYPE_BOOLEAN, 2,
1340                   GTK_TYPE_TREE_ITER,
1341                   GTK_TYPE_TREE_PATH);
1342
1343   /**
1344    * GtkTreeView::row-expanded:
1345    * @tree_view: the object on which the signal is emitted
1346    * @iter: the tree iter of the expanded row
1347    * @path: a tree path that points to the row 
1348    * 
1349    * The given row has been expanded (child nodes are shown).
1350    */
1351   tree_view_signals[ROW_EXPANDED] =
1352     g_signal_new (I_("row-expanded"),
1353                   G_TYPE_FROM_CLASS (o_class),
1354                   G_SIGNAL_RUN_LAST,
1355                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1356                   NULL, NULL,
1357                   _gtk_marshal_VOID__BOXED_BOXED,
1358                   G_TYPE_NONE, 2,
1359                   GTK_TYPE_TREE_ITER,
1360                   GTK_TYPE_TREE_PATH);
1361
1362   /**
1363    * GtkTreeView::row-collapsed:
1364    * @tree_view: the object on which the signal is emitted
1365    * @iter: the tree iter of the collapsed row
1366    * @path: a tree path that points to the row 
1367    * 
1368    * The given row has been collapsed (child nodes are hidden).
1369    */
1370   tree_view_signals[ROW_COLLAPSED] =
1371     g_signal_new (I_("row-collapsed"),
1372                   G_TYPE_FROM_CLASS (o_class),
1373                   G_SIGNAL_RUN_LAST,
1374                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1375                   NULL, NULL,
1376                   _gtk_marshal_VOID__BOXED_BOXED,
1377                   G_TYPE_NONE, 2,
1378                   GTK_TYPE_TREE_ITER,
1379                   GTK_TYPE_TREE_PATH);
1380
1381   /**
1382    * GtkTreeView::columns-changed:
1383    * @tree_view: the object on which the signal is emitted 
1384    * 
1385    * The number of columns of the treeview has changed.
1386    */
1387   tree_view_signals[COLUMNS_CHANGED] =
1388     g_signal_new (I_("columns-changed"),
1389                   G_TYPE_FROM_CLASS (o_class),
1390                   G_SIGNAL_RUN_LAST,
1391                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1392                   NULL, NULL,
1393                   _gtk_marshal_VOID__VOID,
1394                   G_TYPE_NONE, 0);
1395
1396   /**
1397    * GtkTreeView::cursor-changed:
1398    * @tree_view: the object on which the signal is emitted
1399    * 
1400    * The position of the cursor (focused cell) has changed.
1401    */
1402   tree_view_signals[CURSOR_CHANGED] =
1403     g_signal_new (I_("cursor-changed"),
1404                   G_TYPE_FROM_CLASS (o_class),
1405                   G_SIGNAL_RUN_LAST,
1406                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1407                   NULL, NULL,
1408                   _gtk_marshal_VOID__VOID,
1409                   G_TYPE_NONE, 0);
1410
1411   tree_view_signals[MOVE_CURSOR] =
1412     g_signal_new (I_("move-cursor"),
1413                   G_TYPE_FROM_CLASS (o_class),
1414                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1415                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1416                   NULL, NULL,
1417                   _gtk_marshal_BOOLEAN__ENUM_INT,
1418                   G_TYPE_BOOLEAN, 2,
1419                   GTK_TYPE_MOVEMENT_STEP,
1420                   G_TYPE_INT);
1421
1422   tree_view_signals[SELECT_ALL] =
1423     g_signal_new (I_("select-all"),
1424                   G_TYPE_FROM_CLASS (o_class),
1425                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1426                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1427                   NULL, NULL,
1428                   _gtk_marshal_BOOLEAN__VOID,
1429                   G_TYPE_BOOLEAN, 0);
1430
1431   tree_view_signals[UNSELECT_ALL] =
1432     g_signal_new (I_("unselect-all"),
1433                   G_TYPE_FROM_CLASS (o_class),
1434                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1435                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1436                   NULL, NULL,
1437                   _gtk_marshal_BOOLEAN__VOID,
1438                   G_TYPE_BOOLEAN, 0);
1439
1440   tree_view_signals[SELECT_CURSOR_ROW] =
1441     g_signal_new (I_("select-cursor-row"),
1442                   G_TYPE_FROM_CLASS (o_class),
1443                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1444                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1445                   NULL, NULL,
1446                   _gtk_marshal_BOOLEAN__BOOLEAN,
1447                   G_TYPE_BOOLEAN, 1,
1448                   G_TYPE_BOOLEAN);
1449
1450   tree_view_signals[TOGGLE_CURSOR_ROW] =
1451     g_signal_new (I_("toggle-cursor-row"),
1452                   G_TYPE_FROM_CLASS (o_class),
1453                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1454                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1455                   NULL, NULL,
1456                   _gtk_marshal_BOOLEAN__VOID,
1457                   G_TYPE_BOOLEAN, 0);
1458
1459   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1460     g_signal_new (I_("expand-collapse-cursor-row"),
1461                   G_TYPE_FROM_CLASS (o_class),
1462                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1463                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1464                   NULL, NULL,
1465                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1466                   G_TYPE_BOOLEAN, 3,
1467                   G_TYPE_BOOLEAN,
1468                   G_TYPE_BOOLEAN,
1469                   G_TYPE_BOOLEAN);
1470
1471   tree_view_signals[SELECT_CURSOR_PARENT] =
1472     g_signal_new (I_("select-cursor-parent"),
1473                   G_TYPE_FROM_CLASS (o_class),
1474                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1475                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1476                   NULL, NULL,
1477                   _gtk_marshal_BOOLEAN__VOID,
1478                   G_TYPE_BOOLEAN, 0);
1479
1480   tree_view_signals[START_INTERACTIVE_SEARCH] =
1481     g_signal_new (I_("start-interactive-search"),
1482                   G_TYPE_FROM_CLASS (o_class),
1483                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1484                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1485                   NULL, NULL,
1486                   _gtk_marshal_BOOLEAN__VOID,
1487                   G_TYPE_BOOLEAN, 0);
1488
1489   /* Key bindings */
1490   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1491                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1492   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1493                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1494
1495   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1496                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1497   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1498                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1499
1500   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1501                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1502
1503   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1504                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1505
1506   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1507                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1508   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1509                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1510
1511   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1512                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1513   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1514                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1515
1516   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1517                                   GTK_MOVEMENT_PAGES, -1);
1518   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1519                                   GTK_MOVEMENT_PAGES, -1);
1520
1521   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1522                                   GTK_MOVEMENT_PAGES, 1);
1523   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1524                                   GTK_MOVEMENT_PAGES, 1);
1525
1526
1527   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1528                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1529                                 G_TYPE_INT, 1);
1530
1531   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1532                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1533                                 G_TYPE_INT, -1);
1534
1535   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1536                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1537                                 G_TYPE_INT, 1);
1538
1539   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "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_Right, 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_Left, 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_Right, 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_KP_Left, GDK_CONTROL_MASK,
1559                                 "move-cursor", 2,
1560                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1561                                 G_TYPE_INT, -1);
1562
1563   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1564   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1565
1566   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1567   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1568
1569   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1570   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1571
1572   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1573                                 G_TYPE_BOOLEAN, TRUE);
1574   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1575                                 G_TYPE_BOOLEAN, TRUE);
1576
1577   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1578                                 G_TYPE_BOOLEAN, TRUE);
1579   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1580                                 G_TYPE_BOOLEAN, TRUE);
1581   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1582                                 G_TYPE_BOOLEAN, TRUE);
1583   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1584                                 G_TYPE_BOOLEAN, TRUE);
1585   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1586                                 G_TYPE_BOOLEAN, TRUE);
1587
1588   /* expand and collapse rows */
1589   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1590                                 G_TYPE_BOOLEAN, TRUE,
1591                                 G_TYPE_BOOLEAN, TRUE,
1592                                 G_TYPE_BOOLEAN, FALSE);
1593
1594   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1595                                 "expand-collapse-cursor-row", 3,
1596                                 G_TYPE_BOOLEAN, TRUE,
1597                                 G_TYPE_BOOLEAN, TRUE,
1598                                 G_TYPE_BOOLEAN, TRUE);
1599   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1600                                 "expand-collapse-cursor-row", 3,
1601                                 G_TYPE_BOOLEAN, TRUE,
1602                                 G_TYPE_BOOLEAN, TRUE,
1603                                 G_TYPE_BOOLEAN, TRUE);
1604
1605   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1606                                 "expand-collapse-cursor-row", 3,
1607                                 G_TYPE_BOOLEAN, TRUE,
1608                                 G_TYPE_BOOLEAN, FALSE,
1609                                 G_TYPE_BOOLEAN, FALSE);
1610   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1611                                 "expand-collapse-cursor-row", 3,
1612                                 G_TYPE_BOOLEAN, TRUE,
1613                                 G_TYPE_BOOLEAN, FALSE,
1614                                 G_TYPE_BOOLEAN, FALSE);
1615
1616   /* Not doable on US keyboards */
1617   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1618                                 G_TYPE_BOOLEAN, TRUE,
1619                                 G_TYPE_BOOLEAN, TRUE,
1620                                 G_TYPE_BOOLEAN, TRUE);
1621   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1622                                 G_TYPE_BOOLEAN, TRUE,
1623                                 G_TYPE_BOOLEAN, TRUE,
1624                                 G_TYPE_BOOLEAN, FALSE);
1625   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1626                                 G_TYPE_BOOLEAN, TRUE,
1627                                 G_TYPE_BOOLEAN, TRUE,
1628                                 G_TYPE_BOOLEAN, TRUE);
1629   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1630                                 G_TYPE_BOOLEAN, TRUE,
1631                                 G_TYPE_BOOLEAN, TRUE,
1632                                 G_TYPE_BOOLEAN, TRUE);
1633   gtk_binding_entry_add_signal (binding_set, GDK_KEY_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_KP_Right, GDK_SHIFT_MASK,
1639                                 "expand-collapse-cursor-row", 3,
1640                                 G_TYPE_BOOLEAN, FALSE,
1641                                 G_TYPE_BOOLEAN, TRUE,
1642                                 G_TYPE_BOOLEAN, TRUE);
1643   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1644                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1645                                 "expand-collapse-cursor-row", 3,
1646                                 G_TYPE_BOOLEAN, FALSE,
1647                                 G_TYPE_BOOLEAN, TRUE,
1648                                 G_TYPE_BOOLEAN, TRUE);
1649   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1650                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1651                                 "expand-collapse-cursor-row", 3,
1652                                 G_TYPE_BOOLEAN, FALSE,
1653                                 G_TYPE_BOOLEAN, TRUE,
1654                                 G_TYPE_BOOLEAN, TRUE);
1655
1656   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1657                                 G_TYPE_BOOLEAN, TRUE,
1658                                 G_TYPE_BOOLEAN, FALSE,
1659                                 G_TYPE_BOOLEAN, FALSE);
1660   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1661                                 G_TYPE_BOOLEAN, TRUE,
1662                                 G_TYPE_BOOLEAN, FALSE,
1663                                 G_TYPE_BOOLEAN, TRUE);
1664   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1665                                 G_TYPE_BOOLEAN, TRUE,
1666                                 G_TYPE_BOOLEAN, FALSE,
1667                                 G_TYPE_BOOLEAN, FALSE);
1668   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1669                                 G_TYPE_BOOLEAN, TRUE,
1670                                 G_TYPE_BOOLEAN, FALSE,
1671                                 G_TYPE_BOOLEAN, TRUE);
1672   gtk_binding_entry_add_signal (binding_set, GDK_KEY_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_KP_Left, GDK_SHIFT_MASK,
1678                                 "expand-collapse-cursor-row", 3,
1679                                 G_TYPE_BOOLEAN, FALSE,
1680                                 G_TYPE_BOOLEAN, FALSE,
1681                                 G_TYPE_BOOLEAN, TRUE);
1682   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1683                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1684                                 "expand-collapse-cursor-row", 3,
1685                                 G_TYPE_BOOLEAN, FALSE,
1686                                 G_TYPE_BOOLEAN, FALSE,
1687                                 G_TYPE_BOOLEAN, TRUE);
1688   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1689                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1690                                 "expand-collapse-cursor-row", 3,
1691                                 G_TYPE_BOOLEAN, FALSE,
1692                                 G_TYPE_BOOLEAN, FALSE,
1693                                 G_TYPE_BOOLEAN, TRUE);
1694
1695   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1696   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1697
1698   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1699
1700   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1701
1702   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1703 }
1704
1705 static void
1706 gtk_tree_view_init (GtkTreeView *tree_view)
1707 {
1708   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1709
1710   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1711   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1712
1713   tree_view->priv->show_expanders = TRUE;
1714   tree_view->priv->draw_keyfocus = TRUE;
1715   tree_view->priv->headers_visible = TRUE;
1716
1717   /* We need some padding */
1718   tree_view->priv->dy = 0;
1719   tree_view->priv->cursor_offset = 0;
1720   tree_view->priv->n_columns = 0;
1721   tree_view->priv->header_height = 1;
1722   tree_view->priv->x_drag = 0;
1723   tree_view->priv->drag_pos = -1;
1724   tree_view->priv->header_has_focus = FALSE;
1725   tree_view->priv->pressed_button = -1;
1726   tree_view->priv->press_start_x = -1;
1727   tree_view->priv->press_start_y = -1;
1728   tree_view->priv->reorderable = FALSE;
1729   tree_view->priv->presize_handler_timer = 0;
1730   tree_view->priv->scroll_sync_timer = 0;
1731   tree_view->priv->fixed_height = -1;
1732   tree_view->priv->fixed_height_mode = FALSE;
1733   tree_view->priv->fixed_height_check = 0;
1734   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1735   tree_view->priv->enable_search = TRUE;
1736   tree_view->priv->search_column = -1;
1737   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1738   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1739   tree_view->priv->search_custom_entry_set = FALSE;
1740   tree_view->priv->typeselect_flush_timeout = 0;
1741   tree_view->priv->init_hadjust_value = TRUE;    
1742   tree_view->priv->width = 0;
1743           
1744   tree_view->priv->hover_selection = FALSE;
1745   tree_view->priv->hover_expand = FALSE;
1746
1747   tree_view->priv->level_indentation = 0;
1748
1749   tree_view->priv->rubber_banding_enable = FALSE;
1750
1751   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1752   tree_view->priv->tree_lines_enabled = FALSE;
1753
1754   tree_view->priv->tooltip_column = -1;
1755
1756   tree_view->priv->post_validation_flag = FALSE;
1757
1758   tree_view->priv->last_button_x = -1;
1759   tree_view->priv->last_button_y = -1;
1760
1761   tree_view->priv->event_last_x = -10000;
1762   tree_view->priv->event_last_y = -10000;
1763
1764   gtk_tree_view_set_vadjustment (tree_view, NULL);
1765   gtk_tree_view_set_hadjustment (tree_view, NULL);
1766 }
1767
1768 \f
1769
1770 /* GObject Methods
1771  */
1772
1773 static void
1774 gtk_tree_view_set_property (GObject         *object,
1775                             guint            prop_id,
1776                             const GValue    *value,
1777                             GParamSpec      *pspec)
1778 {
1779   GtkTreeView *tree_view;
1780
1781   tree_view = GTK_TREE_VIEW (object);
1782
1783   switch (prop_id)
1784     {
1785     case PROP_MODEL:
1786       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1787       break;
1788     case PROP_HADJUSTMENT:
1789       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1790       break;
1791     case PROP_VADJUSTMENT:
1792       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1793       break;
1794     case PROP_HSCROLL_POLICY:
1795       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1796       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1797       break;
1798     case PROP_VSCROLL_POLICY:
1799       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1800       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1801       break;
1802     case PROP_HEADERS_VISIBLE:
1803       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1804       break;
1805     case PROP_HEADERS_CLICKABLE:
1806       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1807       break;
1808     case PROP_EXPANDER_COLUMN:
1809       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1810       break;
1811     case PROP_REORDERABLE:
1812       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1813       break;
1814     case PROP_RULES_HINT:
1815       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1816       break;
1817     case PROP_ENABLE_SEARCH:
1818       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1819       break;
1820     case PROP_SEARCH_COLUMN:
1821       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1822       break;
1823     case PROP_FIXED_HEIGHT_MODE:
1824       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1825       break;
1826     case PROP_HOVER_SELECTION:
1827       tree_view->priv->hover_selection = g_value_get_boolean (value);
1828       break;
1829     case PROP_HOVER_EXPAND:
1830       tree_view->priv->hover_expand = g_value_get_boolean (value);
1831       break;
1832     case PROP_SHOW_EXPANDERS:
1833       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1834       break;
1835     case PROP_LEVEL_INDENTATION:
1836       tree_view->priv->level_indentation = g_value_get_int (value);
1837       break;
1838     case PROP_RUBBER_BANDING:
1839       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1840       break;
1841     case PROP_ENABLE_GRID_LINES:
1842       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1843       break;
1844     case PROP_ENABLE_TREE_LINES:
1845       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1846       break;
1847     case PROP_TOOLTIP_COLUMN:
1848       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1849       break;
1850     default:
1851       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1852       break;
1853     }
1854 }
1855
1856 static void
1857 gtk_tree_view_get_property (GObject    *object,
1858                             guint       prop_id,
1859                             GValue     *value,
1860                             GParamSpec *pspec)
1861 {
1862   GtkTreeView *tree_view;
1863
1864   tree_view = GTK_TREE_VIEW (object);
1865
1866   switch (prop_id)
1867     {
1868     case PROP_MODEL:
1869       g_value_set_object (value, tree_view->priv->model);
1870       break;
1871     case PROP_HADJUSTMENT:
1872       g_value_set_object (value, tree_view->priv->hadjustment);
1873       break;
1874     case PROP_VADJUSTMENT:
1875       g_value_set_object (value, tree_view->priv->vadjustment);
1876       break;
1877     case PROP_HSCROLL_POLICY:
1878       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1879       break;
1880     case PROP_VSCROLL_POLICY:
1881       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1882       break;
1883     case PROP_HEADERS_VISIBLE:
1884       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1885       break;
1886     case PROP_HEADERS_CLICKABLE:
1887       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1888       break;
1889     case PROP_EXPANDER_COLUMN:
1890       g_value_set_object (value, tree_view->priv->expander_column);
1891       break;
1892     case PROP_REORDERABLE:
1893       g_value_set_boolean (value, tree_view->priv->reorderable);
1894       break;
1895     case PROP_RULES_HINT:
1896       g_value_set_boolean (value, tree_view->priv->has_rules);
1897       break;
1898     case PROP_ENABLE_SEARCH:
1899       g_value_set_boolean (value, tree_view->priv->enable_search);
1900       break;
1901     case PROP_SEARCH_COLUMN:
1902       g_value_set_int (value, tree_view->priv->search_column);
1903       break;
1904     case PROP_FIXED_HEIGHT_MODE:
1905       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1906       break;
1907     case PROP_HOVER_SELECTION:
1908       g_value_set_boolean (value, tree_view->priv->hover_selection);
1909       break;
1910     case PROP_HOVER_EXPAND:
1911       g_value_set_boolean (value, tree_view->priv->hover_expand);
1912       break;
1913     case PROP_SHOW_EXPANDERS:
1914       g_value_set_boolean (value, tree_view->priv->show_expanders);
1915       break;
1916     case PROP_LEVEL_INDENTATION:
1917       g_value_set_int (value, tree_view->priv->level_indentation);
1918       break;
1919     case PROP_RUBBER_BANDING:
1920       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1921       break;
1922     case PROP_ENABLE_GRID_LINES:
1923       g_value_set_enum (value, tree_view->priv->grid_lines);
1924       break;
1925     case PROP_ENABLE_TREE_LINES:
1926       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1927       break;
1928     case PROP_TOOLTIP_COLUMN:
1929       g_value_set_int (value, tree_view->priv->tooltip_column);
1930       break;
1931     default:
1932       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1933       break;
1934     }
1935 }
1936
1937 static void
1938 gtk_tree_view_finalize (GObject *object)
1939 {
1940   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1941 }
1942
1943
1944 static GtkBuildableIface *parent_buildable_iface;
1945
1946 static void
1947 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1948 {
1949   parent_buildable_iface = g_type_interface_peek_parent (iface);
1950   iface->add_child = gtk_tree_view_buildable_add_child;
1951   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1952 }
1953
1954 static void
1955 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1956                                    GtkBuilder  *builder,
1957                                    GObject     *child,
1958                                    const gchar *type)
1959 {
1960   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1961 }
1962
1963 static GObject *
1964 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1965                                             GtkBuilder        *builder,
1966                                             const gchar       *childname)
1967 {
1968     if (strcmp (childname, "selection") == 0)
1969       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1970     
1971     return parent_buildable_iface->get_internal_child (buildable,
1972                                                        builder,
1973                                                        childname);
1974 }
1975
1976 /* GtkWidget Methods
1977  */
1978
1979 static void
1980 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1981 {
1982   _gtk_rbtree_free (tree_view->priv->tree);
1983   
1984   tree_view->priv->tree = NULL;
1985   tree_view->priv->button_pressed_node = NULL;
1986   tree_view->priv->button_pressed_tree = NULL;
1987   tree_view->priv->prelight_tree = NULL;
1988   tree_view->priv->prelight_node = NULL;
1989   tree_view->priv->expanded_collapsed_node = NULL;
1990   tree_view->priv->expanded_collapsed_tree = NULL;
1991 }
1992
1993 static void
1994 gtk_tree_view_destroy (GtkWidget *widget)
1995 {
1996   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1997   GList *list;
1998
1999   gtk_tree_view_stop_editing (tree_view, TRUE);
2000
2001   if (tree_view->priv->columns != NULL)
2002     {
2003       list = tree_view->priv->columns;
2004       while (list)
2005         {
2006           GtkTreeViewColumn *column;
2007           column = GTK_TREE_VIEW_COLUMN (list->data);
2008           list = list->next;
2009           gtk_tree_view_remove_column (tree_view, column);
2010         }
2011       tree_view->priv->columns = NULL;
2012     }
2013
2014   if (tree_view->priv->tree != NULL)
2015     {
2016       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2017
2018       gtk_tree_view_free_rbtree (tree_view);
2019     }
2020
2021   if (tree_view->priv->selection != NULL)
2022     {
2023       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2024       g_object_unref (tree_view->priv->selection);
2025       tree_view->priv->selection = NULL;
2026     }
2027
2028   if (tree_view->priv->scroll_to_path != NULL)
2029     {
2030       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2031       tree_view->priv->scroll_to_path = NULL;
2032     }
2033
2034   if (tree_view->priv->drag_dest_row != NULL)
2035     {
2036       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2037       tree_view->priv->drag_dest_row = NULL;
2038     }
2039
2040   if (tree_view->priv->top_row != NULL)
2041     {
2042       gtk_tree_row_reference_free (tree_view->priv->top_row);
2043       tree_view->priv->top_row = NULL;
2044     }
2045
2046   if (tree_view->priv->column_drop_func_data &&
2047       tree_view->priv->column_drop_func_data_destroy)
2048     {
2049       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2050       tree_view->priv->column_drop_func_data = NULL;
2051     }
2052
2053   if (tree_view->priv->destroy_count_destroy &&
2054       tree_view->priv->destroy_count_data)
2055     {
2056       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2057       tree_view->priv->destroy_count_data = NULL;
2058     }
2059
2060   gtk_tree_row_reference_free (tree_view->priv->cursor);
2061   tree_view->priv->cursor = NULL;
2062
2063   gtk_tree_row_reference_free (tree_view->priv->anchor);
2064   tree_view->priv->anchor = NULL;
2065
2066   /* destroy interactive search dialog */
2067   if (tree_view->priv->search_window)
2068     {
2069       gtk_widget_destroy (tree_view->priv->search_window);
2070       tree_view->priv->search_window = NULL;
2071       tree_view->priv->search_entry = NULL;
2072       if (tree_view->priv->typeselect_flush_timeout)
2073         {
2074           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2075           tree_view->priv->typeselect_flush_timeout = 0;
2076         }
2077     }
2078
2079   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2080     {
2081       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2082       tree_view->priv->search_user_data = NULL;
2083     }
2084
2085   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2086     {
2087       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2088       tree_view->priv->search_position_user_data = NULL;
2089     }
2090
2091   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2092     {
2093       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2094       tree_view->priv->row_separator_data = NULL;
2095     }
2096   
2097   gtk_tree_view_set_model (tree_view, NULL);
2098
2099   if (tree_view->priv->hadjustment)
2100     {
2101       g_object_unref (tree_view->priv->hadjustment);
2102       tree_view->priv->hadjustment = NULL;
2103     }
2104   if (tree_view->priv->vadjustment)
2105     {
2106       g_object_unref (tree_view->priv->vadjustment);
2107       tree_view->priv->vadjustment = NULL;
2108     }
2109
2110   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2111 }
2112
2113 /* GtkWidget::map helper */
2114 static void
2115 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2116 {
2117   GList *list;
2118
2119   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2120
2121   if (tree_view->priv->headers_visible)
2122     {
2123       GtkTreeViewColumn *column;
2124       GtkWidget         *button;
2125       GdkWindow         *window;
2126
2127       for (list = tree_view->priv->columns; list; list = list->next)
2128         {
2129           column = list->data;
2130           button = gtk_tree_view_column_get_button (column);
2131
2132           if (gtk_tree_view_column_get_visible (column) && button)
2133             gtk_widget_show_now (button);
2134
2135           if (gtk_widget_get_visible (button) &&
2136               !gtk_widget_get_mapped (button))
2137             gtk_widget_map (button);
2138         }
2139       for (list = tree_view->priv->columns; list; list = list->next)
2140         {
2141           column = list->data;
2142           if (gtk_tree_view_column_get_visible (column) == FALSE)
2143             continue;
2144
2145           window = _gtk_tree_view_column_get_window (column);
2146           if (gtk_tree_view_column_get_resizable (column))
2147             {
2148               gdk_window_raise (window);
2149               gdk_window_show (window);
2150             }
2151           else
2152             gdk_window_hide (window);
2153         }
2154       gdk_window_show (tree_view->priv->header_window);
2155     }
2156 }
2157
2158 static void
2159 gtk_tree_view_map (GtkWidget *widget)
2160 {
2161   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2162   GList *tmp_list;
2163
2164   gtk_widget_set_mapped (widget, TRUE);
2165
2166   tmp_list = tree_view->priv->children;
2167   while (tmp_list)
2168     {
2169       GtkTreeViewChild *child = tmp_list->data;
2170       tmp_list = tmp_list->next;
2171
2172       if (gtk_widget_get_visible (child->widget))
2173         {
2174           if (!gtk_widget_get_mapped (child->widget))
2175             gtk_widget_map (child->widget);
2176         }
2177     }
2178   gdk_window_show (tree_view->priv->bin_window);
2179
2180   gtk_tree_view_map_buttons (tree_view);
2181
2182   gdk_window_show (gtk_widget_get_window (widget));
2183 }
2184
2185 static void
2186 gtk_tree_view_realize (GtkWidget *widget)
2187 {
2188   GtkAllocation allocation;
2189   GtkStyle *style;
2190   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2191   GdkWindow *window;
2192   GdkWindowAttr attributes;
2193   GList *tmp_list;
2194   gint attributes_mask;
2195
2196   gtk_widget_set_realized (widget, TRUE);
2197
2198   gtk_widget_get_allocation (widget, &allocation);
2199
2200   /* Make the main, clipping window */
2201   attributes.window_type = GDK_WINDOW_CHILD;
2202   attributes.x = allocation.x;
2203   attributes.y = allocation.y;
2204   attributes.width = allocation.width;
2205   attributes.height = allocation.height;
2206   attributes.wclass = GDK_INPUT_OUTPUT;
2207   attributes.visual = gtk_widget_get_visual (widget);
2208   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2209
2210   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2211
2212   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2213                            &attributes, attributes_mask);
2214   gtk_widget_set_window (widget, window);
2215   gdk_window_set_user_data (window, widget);
2216
2217   gtk_widget_get_allocation (widget, &allocation);
2218
2219   /* Make the window for the tree */
2220   attributes.x = 0;
2221   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2222   attributes.width = MAX (tree_view->priv->width, allocation.width);
2223   attributes.height = allocation.height;
2224   attributes.event_mask = (GDK_EXPOSURE_MASK |
2225                            GDK_SCROLL_MASK |
2226                            GDK_POINTER_MOTION_MASK |
2227                            GDK_ENTER_NOTIFY_MASK |
2228                            GDK_LEAVE_NOTIFY_MASK |
2229                            GDK_BUTTON_PRESS_MASK |
2230                            GDK_BUTTON_RELEASE_MASK |
2231                            gtk_widget_get_events (widget));
2232
2233   tree_view->priv->bin_window = gdk_window_new (window,
2234                                                 &attributes, attributes_mask);
2235   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2236
2237   gtk_widget_get_allocation (widget, &allocation);
2238
2239   /* Make the column header window */
2240   attributes.x = 0;
2241   attributes.y = 0;
2242   attributes.width = MAX (tree_view->priv->width, allocation.width);
2243   attributes.height = tree_view->priv->header_height;
2244   attributes.event_mask = (GDK_EXPOSURE_MASK |
2245                            GDK_SCROLL_MASK |
2246                            GDK_ENTER_NOTIFY_MASK |
2247                            GDK_LEAVE_NOTIFY_MASK |
2248                            GDK_BUTTON_PRESS_MASK |
2249                            GDK_BUTTON_RELEASE_MASK |
2250                            GDK_KEY_PRESS_MASK |
2251                            GDK_KEY_RELEASE_MASK |
2252                            gtk_widget_get_events (widget));
2253
2254   tree_view->priv->header_window = gdk_window_new (window,
2255                                                    &attributes, attributes_mask);
2256   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2257
2258   /* Add them all up. */
2259   gtk_widget_style_attach (widget);
2260   style = gtk_widget_get_style (widget);
2261   gdk_window_set_background (tree_view->priv->bin_window,
2262                              &style->base[gtk_widget_get_state (widget)]);
2263   gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
2264
2265   tmp_list = tree_view->priv->children;
2266   while (tmp_list)
2267     {
2268       GtkTreeViewChild *child = tmp_list->data;
2269       tmp_list = tmp_list->next;
2270
2271       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2272     }
2273
2274   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2275     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2276
2277   /* Need to call those here, since they create GCs */
2278   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2279   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2280
2281   install_presize_handler (tree_view); 
2282 }
2283
2284 static void
2285 gtk_tree_view_unrealize (GtkWidget *widget)
2286 {
2287   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2288   GtkTreeViewPrivate *priv = tree_view->priv;
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   remove_expand_collapse_timeout (tree_view);
2310   
2311   if (priv->presize_handler_timer != 0)
2312     {
2313       g_source_remove (priv->presize_handler_timer);
2314       priv->presize_handler_timer = 0;
2315     }
2316
2317   if (priv->validate_rows_timer != 0)
2318     {
2319       g_source_remove (priv->validate_rows_timer);
2320       priv->validate_rows_timer = 0;
2321     }
2322
2323   if (priv->scroll_sync_timer != 0)
2324     {
2325       g_source_remove (priv->scroll_sync_timer);
2326       priv->scroll_sync_timer = 0;
2327     }
2328
2329   if (priv->typeselect_flush_timeout)
2330     {
2331       g_source_remove (priv->typeselect_flush_timeout);
2332       priv->typeselect_flush_timeout = 0;
2333     }
2334   
2335   for (list = priv->columns; list; list = list->next)
2336     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2337
2338   gdk_window_set_user_data (priv->bin_window, NULL);
2339   gdk_window_destroy (priv->bin_window);
2340   priv->bin_window = NULL;
2341
2342   gdk_window_set_user_data (priv->header_window, NULL);
2343   gdk_window_destroy (priv->header_window);
2344   priv->header_window = NULL;
2345
2346   if (priv->drag_window)
2347     {
2348       gdk_window_set_user_data (priv->drag_window, NULL);
2349       gdk_window_destroy (priv->drag_window);
2350       priv->drag_window = NULL;
2351     }
2352
2353   if (priv->drag_highlight_window)
2354     {
2355       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2356       gdk_window_destroy (priv->drag_highlight_window);
2357       priv->drag_highlight_window = NULL;
2358     }
2359
2360   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2361 }
2362
2363 /* GtkWidget::size_request helper */
2364 static void
2365 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2366 {
2367   GList *list;
2368
2369   tree_view->priv->header_height = 0;
2370
2371   if (tree_view->priv->model)
2372     {
2373       for (list = tree_view->priv->columns; list; list = list->next)
2374         {
2375           GtkRequisition     requisition;
2376           GtkTreeViewColumn *column = list->data;
2377           GtkWidget         *button = gtk_tree_view_column_get_button (column);
2378
2379           if (button == NULL)
2380             continue;
2381
2382           column = list->data;
2383
2384           gtk_widget_get_preferred_size (button, &requisition, NULL);
2385           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2386         }
2387     }
2388 }
2389
2390
2391 /* Called only by ::size_request */
2392 static void
2393 gtk_tree_view_update_size (GtkTreeView *tree_view)
2394 {
2395   GList *list;
2396   GtkTreeViewColumn *column;
2397   gint i;
2398
2399   if (tree_view->priv->model == NULL)
2400     {
2401       tree_view->priv->width = 0;
2402       tree_view->priv->prev_width = 0;                   
2403       tree_view->priv->height = 0;
2404       return;
2405     }
2406
2407   tree_view->priv->prev_width = tree_view->priv->width;  
2408   tree_view->priv->width = 0;
2409
2410   /* keep this in sync with size_allocate below */
2411   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2412     {
2413       column = list->data;
2414       if (!gtk_tree_view_column_get_visible (column))
2415         continue;
2416
2417       tree_view->priv->width += _gtk_tree_view_column_request_width (column);
2418     }
2419
2420   if (tree_view->priv->tree == NULL)
2421     tree_view->priv->height = 0;
2422   else
2423     tree_view->priv->height = tree_view->priv->tree->root->offset;
2424 }
2425
2426 static void
2427 gtk_tree_view_size_request (GtkWidget      *widget,
2428                             GtkRequisition *requisition,
2429                             gboolean        may_validate)
2430 {
2431   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2432   GList *tmp_list;
2433
2434   if (may_validate)
2435     {
2436       /* we validate some rows initially just to make sure we have some size.
2437        * In practice, with a lot of static lists, this should get a good width.
2438        */
2439       do_validate_rows (tree_view, FALSE);
2440     }
2441
2442   gtk_tree_view_size_request_columns (tree_view);
2443   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2444
2445   requisition->width = tree_view->priv->width;
2446   requisition->height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2447
2448   tmp_list = tree_view->priv->children;
2449 }
2450
2451 static void
2452 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2453                                    gint      *minimum,
2454                                    gint      *natural)
2455 {
2456   GtkRequisition requisition;
2457
2458   gtk_tree_view_size_request (widget, &requisition, TRUE);
2459
2460   *minimum = *natural = requisition.width;
2461 }
2462
2463 static void
2464 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2465                                     gint      *minimum,
2466                                     gint      *natural)
2467 {
2468   GtkRequisition requisition;
2469
2470   gtk_tree_view_size_request (widget, &requisition, TRUE);
2471
2472   *minimum = *natural = requisition.height;
2473 }
2474
2475 static int
2476 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2477 {
2478   int width = 0;
2479   GList *list;
2480   gboolean rtl;
2481
2482   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2483   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2484        list->data != tree_view->priv->expander_column;
2485        list = (rtl ? list->prev : list->next))
2486     {
2487       GtkTreeViewColumn *column = list->data;
2488
2489       width += gtk_tree_view_column_get_width (column);
2490     }
2491
2492   return width;
2493 }
2494
2495 static void
2496 invalidate_column (GtkTreeView       *tree_view,
2497                    GtkTreeViewColumn *column)
2498 {
2499   gint column_offset = 0;
2500   GList *list;
2501   GtkWidget *widget = GTK_WIDGET (tree_view);
2502   gboolean rtl;
2503
2504   if (!gtk_widget_get_realized (widget))
2505     return;
2506
2507   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2508   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2509        list;
2510        list = (rtl ? list->prev : list->next))
2511     {
2512       GtkTreeViewColumn *tmpcolumn = list->data;
2513       if (tmpcolumn == column)
2514         {
2515           GtkAllocation allocation;
2516           GdkRectangle invalid_rect;
2517
2518           gtk_widget_get_allocation (widget, &allocation);
2519           invalid_rect.x = column_offset;
2520           invalid_rect.y = 0;
2521           invalid_rect.width = gtk_tree_view_column_get_width (column);
2522           invalid_rect.height = allocation.height;
2523
2524           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2525           break;
2526         }
2527
2528       column_offset += gtk_tree_view_column_get_width (tmpcolumn);
2529     }
2530 }
2531
2532 static void
2533 invalidate_last_column (GtkTreeView *tree_view)
2534 {
2535   GList *last_column;
2536   gboolean rtl;
2537
2538   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2539
2540   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2541        last_column;
2542        last_column = (rtl ? last_column->next : last_column->prev))
2543     {
2544       if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)))
2545         {
2546           invalidate_column (tree_view, last_column->data);
2547           return;
2548         }
2549     }
2550 }
2551
2552 /* GtkWidget::size_allocate helper */
2553 static void
2554 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2555                                      gboolean  *width_changed)
2556 {
2557   GtkTreeView *tree_view;
2558   GList *list, *first_column, *last_column;
2559   GtkTreeViewColumn *column;
2560   GtkAllocation widget_allocation;
2561   gint width = 0;
2562   gint extra, extra_per_column, extra_for_last;
2563   gint full_requested_width = 0;
2564   gint number_of_expand_columns = 0;
2565   gboolean column_changed = FALSE;
2566   gboolean rtl;
2567   gboolean update_expand;
2568   
2569   tree_view = GTK_TREE_VIEW (widget);
2570
2571   for (last_column = g_list_last (tree_view->priv->columns);
2572        last_column &&
2573        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2574        last_column = last_column->prev)
2575     ;
2576   if (last_column == NULL)
2577     return;
2578
2579   for (first_column = g_list_first (tree_view->priv->columns);
2580        first_column &&
2581        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2582        first_column = first_column->next)
2583     ;
2584
2585   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2586
2587   /* find out how many extra space and expandable columns we have */
2588   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2589     {
2590       column = (GtkTreeViewColumn *)list->data;
2591
2592       if (!gtk_tree_view_column_get_visible (column))
2593         continue;
2594
2595       full_requested_width += _gtk_tree_view_column_request_width (column);
2596
2597       if (gtk_tree_view_column_get_expand (column))
2598         number_of_expand_columns++;
2599     }
2600
2601   /* Only update the expand value if the width of the widget has changed,
2602    * or the number of expand columns has changed, or if there are no expand
2603    * columns, or if we didn't have an size-allocation yet after the
2604    * last validated node.
2605    */
2606   update_expand = (width_changed && *width_changed == TRUE)
2607       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2608       || number_of_expand_columns == 0
2609       || tree_view->priv->post_validation_flag == TRUE;
2610
2611   tree_view->priv->post_validation_flag = FALSE;
2612
2613   gtk_widget_get_allocation (widget, &widget_allocation);
2614   if (!update_expand)
2615     {
2616       extra = tree_view->priv->last_extra_space;
2617       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2618     }
2619   else
2620     {
2621       extra = MAX (widget_allocation.width - full_requested_width, 0);
2622       extra_for_last = 0;
2623
2624       tree_view->priv->last_extra_space = extra;
2625     }
2626
2627   if (number_of_expand_columns > 0)
2628     extra_per_column = extra/number_of_expand_columns;
2629   else
2630     extra_per_column = 0;
2631
2632   if (update_expand)
2633     {
2634       tree_view->priv->last_extra_space_per_column = extra_per_column;
2635       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2636     }
2637
2638   for (list = (rtl ? last_column : first_column); 
2639        list != (rtl ? first_column->prev : last_column->next);
2640        list = (rtl ? list->prev : list->next)) 
2641     {
2642       gint old_width, column_width;
2643
2644       column = list->data;
2645       old_width = gtk_tree_view_column_get_width (column);
2646
2647       if (!gtk_tree_view_column_get_visible (column))
2648         continue;
2649
2650       /* We need to handle the dragged button specially.
2651        */
2652       if (column == tree_view->priv->drag_column)
2653         {
2654           GtkAllocation drag_allocation;
2655           GtkWidget    *button;
2656
2657           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2658
2659           drag_allocation.x = 0;
2660           drag_allocation.y = 0;
2661           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2662           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2663           gtk_widget_size_allocate (button, &drag_allocation);
2664           width += drag_allocation.width;
2665           continue;
2666         }
2667
2668       column_width = _gtk_tree_view_column_request_width (column);
2669
2670       if (gtk_tree_view_column_get_expand (column))
2671         {
2672           if (number_of_expand_columns == 1)
2673             {
2674               /* We add the remander to the last column as
2675                * */
2676               column_width += extra;
2677             }
2678           else
2679             {
2680               column_width += extra_per_column;
2681               extra -= extra_per_column;
2682               number_of_expand_columns --;
2683             }
2684         }
2685       else if (number_of_expand_columns == 0 &&
2686                list == last_column)
2687         {
2688           column_width += extra;
2689         }
2690
2691       /* In addition to expand, the last column can get even more
2692        * extra space so all available space is filled up.
2693        */
2694       if (extra_for_last > 0 && list == last_column)
2695         column_width += extra_for_last;
2696
2697       _gtk_tree_view_column_allocate (column, width, column_width);
2698
2699       width += column_width;
2700
2701       if (column_width > old_width)
2702         column_changed = TRUE;
2703     }
2704
2705   /* We change the width here.  The user might have been resizing columns,
2706    * so the total width of the tree view changes.
2707    */
2708   tree_view->priv->width = width;
2709   if (width_changed)
2710     *width_changed = TRUE;
2711
2712   if (column_changed)
2713     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2714 }
2715
2716
2717 static void
2718 gtk_tree_view_size_allocate (GtkWidget     *widget,
2719                              GtkAllocation *allocation)
2720 {
2721   GtkAllocation widget_allocation;
2722   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2723   GList *tmp_list;
2724   gboolean width_changed = FALSE;
2725   gint old_width;
2726
2727   gtk_widget_get_allocation (widget, &widget_allocation);
2728   old_width = widget_allocation.width;
2729   if (allocation->width != widget_allocation.width)
2730     width_changed = TRUE;
2731
2732   gtk_widget_set_allocation (widget, allocation);
2733
2734   tmp_list = tree_view->priv->children;
2735
2736   while (tmp_list)
2737     {
2738       GtkAllocation allocation;
2739
2740       GtkTreeViewChild *child = tmp_list->data;
2741       tmp_list = tmp_list->next;
2742
2743       /* totally ignore our child's requisition */
2744       allocation.x = child->x;
2745       allocation.y = child->y;
2746       allocation.width = child->width;
2747       allocation.height = child->height;
2748       gtk_widget_size_allocate (child->widget, &allocation);
2749     }
2750
2751   /* We size-allocate the columns first because the width of the
2752    * tree view (used in updating the adjustments below) might change.
2753    */
2754   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2755
2756   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2757   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2758                                 allocation->width);
2759   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2760                                      allocation->width * 0.9);
2761   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2762                                      allocation->width * 0.1);
2763   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2764   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2765                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2766                                  tree_view->priv->width));
2767   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2768
2769   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2770     {
2771       if (allocation->width < tree_view->priv->width)
2772         {
2773           if (tree_view->priv->init_hadjust_value)
2774             {
2775               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2776                                         MAX (tree_view->priv->width -
2777                                              allocation->width, 0));
2778               tree_view->priv->init_hadjust_value = FALSE;
2779             }
2780           else if (allocation->width != old_width)
2781             {
2782               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2783                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2784                                                0,
2785                                                tree_view->priv->width - allocation->width));
2786             }
2787           else
2788             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2789                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)),
2790                                              0,
2791                                              tree_view->priv->width - allocation->width));
2792         }
2793       else
2794         {
2795           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2796           tree_view->priv->init_hadjust_value = TRUE;
2797         }
2798     }
2799   else
2800     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2801       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2802                                 MAX (tree_view->priv->width -
2803                                      allocation->width, 0));
2804
2805   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2806   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2807                                 allocation->height -
2808                                 gtk_tree_view_get_effective_header_height (tree_view));
2809   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2810                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2811   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2812                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2813   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2814   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2815                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2816                                  tree_view->priv->height));
2817   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2818
2819   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2820   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2821     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2822   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2823     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2824                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2825   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2826     gtk_tree_view_top_row_to_dy (tree_view);
2827   else
2828     gtk_tree_view_dy_to_top_row (tree_view);
2829   
2830   if (gtk_widget_get_realized (widget))
2831     {
2832       gdk_window_move_resize (gtk_widget_get_window (widget),
2833                               allocation->x, allocation->y,
2834                               allocation->width, allocation->height);
2835       gdk_window_move_resize (tree_view->priv->header_window,
2836                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2837                               0,
2838                               MAX (tree_view->priv->width, allocation->width),
2839                               tree_view->priv->header_height);
2840       gdk_window_move_resize (tree_view->priv->bin_window,
2841                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2842                               gtk_tree_view_get_effective_header_height (tree_view),
2843                               MAX (tree_view->priv->width, allocation->width),
2844                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2845     }
2846
2847   if (tree_view->priv->tree == NULL)
2848     invalidate_empty_focus (tree_view);
2849
2850   if (gtk_widget_get_realized (widget))
2851     {
2852       gboolean has_expand_column = FALSE;
2853       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2854         {
2855           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2856             {
2857               has_expand_column = TRUE;
2858               break;
2859             }
2860         }
2861
2862       if (width_changed && tree_view->priv->expander_column)
2863         {
2864           /* Might seem awkward, but is the best heuristic I could come up
2865            * with.  Only if the width of the columns before the expander
2866            * changes, we will update the prelight status.  It is this
2867            * width that makes the expander move vertically.  Always updating
2868            * prelight status causes trouble with hover selections.
2869            */
2870           gint width_before_expander;
2871
2872           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2873
2874           if (tree_view->priv->prev_width_before_expander
2875               != width_before_expander)
2876               update_prelight (tree_view,
2877                                tree_view->priv->event_last_x,
2878                                tree_view->priv->event_last_y);
2879
2880           tree_view->priv->prev_width_before_expander = width_before_expander;
2881         }
2882
2883       /* This little hack only works if we have an LTR locale, and no column has the  */
2884       if (width_changed)
2885         {
2886           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2887               ! has_expand_column)
2888             invalidate_last_column (tree_view);
2889           else
2890             gtk_widget_queue_draw (widget);
2891         }
2892     }
2893 }
2894
2895 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2896 static void
2897 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2898 {
2899   GtkWidget *widget = GTK_WIDGET (tree_view);
2900
2901   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2902     gtk_widget_grab_focus (widget);
2903   tree_view->priv->draw_keyfocus = 0;
2904 }
2905
2906 static inline gboolean
2907 row_is_separator (GtkTreeView *tree_view,
2908                   GtkTreeIter *iter,
2909                   GtkTreePath *path)
2910 {
2911   gboolean is_separator = FALSE;
2912
2913   if (tree_view->priv->row_separator_func)
2914     {
2915       GtkTreeIter tmpiter;
2916
2917       if (iter)
2918         tmpiter = *iter;
2919       else
2920         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2921
2922       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2923                                                           &tmpiter,
2924                                                           tree_view->priv->row_separator_data);
2925     }
2926
2927   return is_separator;
2928 }
2929
2930 static gboolean
2931 gtk_tree_view_button_press (GtkWidget      *widget,
2932                             GdkEventButton *event)
2933 {
2934   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2935   GList *list;
2936   GtkTreeViewColumn *column = NULL;
2937   gint i;
2938   GdkRectangle background_area;
2939   GdkRectangle cell_area;
2940   gint vertical_separator;
2941   gint horizontal_separator;
2942   gboolean path_is_selectable;
2943   gboolean rtl;
2944
2945   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2946   gtk_tree_view_stop_editing (tree_view, FALSE);
2947   gtk_widget_style_get (widget,
2948                         "vertical-separator", &vertical_separator,
2949                         "horizontal-separator", &horizontal_separator,
2950                         NULL);
2951
2952
2953   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2954    * we're done handling the button press.
2955    */
2956
2957   if (event->window == tree_view->priv->bin_window)
2958     {
2959       GtkRBNode *node;
2960       GtkRBTree *tree;
2961       GtkTreePath *path;
2962       gint depth;
2963       gint new_y;
2964       gint y_offset;
2965       gint dval;
2966       gint pre_val, aft_val;
2967       GtkTreeViewColumn *column = NULL;
2968       gint column_handled_click = FALSE;
2969       gboolean row_double_click = FALSE;
2970       gboolean rtl;
2971       gboolean node_selected;
2972
2973       /* Empty tree? */
2974       if (tree_view->priv->tree == NULL)
2975         {
2976           grab_focus_and_unset_draw_keyfocus (tree_view);
2977           return TRUE;
2978         }
2979
2980       /* are we in an arrow? */
2981       if (tree_view->priv->prelight_node &&
2982           tree_view->priv->arrow_prelit &&
2983           gtk_tree_view_draw_expanders (tree_view))
2984         {
2985           if (event->button == 1)
2986             {
2987               gtk_grab_add (widget);
2988               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2989               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2990               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2991                                               tree_view->priv->prelight_tree,
2992                                               tree_view->priv->prelight_node);
2993             }
2994
2995           grab_focus_and_unset_draw_keyfocus (tree_view);
2996           return TRUE;
2997         }
2998
2999       /* find the node that was clicked */
3000       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
3001       if (new_y < 0)
3002         new_y = 0;
3003       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
3004
3005       if (node == NULL)
3006         {
3007           /* We clicked in dead space */
3008           grab_focus_and_unset_draw_keyfocus (tree_view);
3009           return TRUE;
3010         }
3011
3012       /* Get the path and the node */
3013       path = _gtk_tree_view_find_path (tree_view, tree, node);
3014       path_is_selectable = !row_is_separator (tree_view, NULL, path);
3015
3016       if (!path_is_selectable)
3017         {
3018           gtk_tree_path_free (path);
3019           grab_focus_and_unset_draw_keyfocus (tree_view);
3020           return TRUE;
3021         }
3022
3023       depth = gtk_tree_path_get_depth (path);
3024       background_area.y = y_offset + event->y;
3025       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
3026       background_area.x = 0;
3027
3028
3029       /* Let the column have a chance at selecting it. */
3030       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
3031       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
3032            list; list = (rtl ? list->prev : list->next))
3033         {
3034           GtkTreeViewColumn *candidate = list->data;
3035
3036           if (!gtk_tree_view_column_get_visible (candidate))
3037             continue;
3038
3039           background_area.width = gtk_tree_view_column_get_width (candidate);
3040           if ((background_area.x > (gint) event->x) ||
3041               (background_area.x + background_area.width <= (gint) event->x))
3042             {
3043               background_area.x += background_area.width;
3044               continue;
3045             }
3046
3047           /* we found the focus column */
3048           column = candidate;
3049           cell_area = background_area;
3050           cell_area.width -= horizontal_separator;
3051           cell_area.height -= vertical_separator;
3052           cell_area.x += horizontal_separator/2;
3053           cell_area.y += vertical_separator/2;
3054           if (gtk_tree_view_is_expander_column (tree_view, column))
3055             {
3056               if (!rtl)
3057                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
3058               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
3059
3060               if (gtk_tree_view_draw_expanders (tree_view))
3061                 {
3062                   if (!rtl)
3063                     cell_area.x += depth * tree_view->priv->expander_size;
3064                   cell_area.width -= depth * tree_view->priv->expander_size;
3065                 }
3066             }
3067           break;
3068         }
3069
3070       if (column == NULL)
3071         {
3072           gtk_tree_path_free (path);
3073           grab_focus_and_unset_draw_keyfocus (tree_view);
3074           return FALSE;
3075         }
3076
3077       tree_view->priv->focus_column = column;
3078
3079       /* decide if we edit */
3080       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
3081           !(event->state & gtk_accelerator_get_default_mod_mask ()))
3082         {
3083           GtkTreePath *anchor;
3084           GtkTreeIter iter;
3085
3086           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3087           gtk_tree_view_column_cell_set_cell_data (column,
3088                                                    tree_view->priv->model,
3089                                                    &iter,
3090                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3091                                                    node->children?TRUE:FALSE);
3092
3093           if (tree_view->priv->anchor)
3094             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3095           else
3096             anchor = NULL;
3097
3098           if ((anchor && !gtk_tree_path_compare (anchor, path))
3099               || !_gtk_tree_view_column_has_editable_cell (column))
3100             {
3101               GtkCellEditable *cell_editable = NULL;
3102
3103               /* FIXME: get the right flags */
3104               guint flags = 0;
3105
3106               if (_gtk_tree_view_column_cell_event (column,
3107                                                     (GdkEvent *)event,
3108                                                     &cell_area, flags))
3109                 {
3110                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3111                   cell_editable = gtk_cell_area_get_edit_widget (area);
3112
3113                   if (cell_editable != NULL)
3114                     {
3115                       gtk_tree_path_free (path);
3116                       gtk_tree_path_free (anchor);
3117                       return TRUE;
3118                     }
3119                   column_handled_click = TRUE;
3120                 }
3121             }
3122           if (anchor)
3123             gtk_tree_path_free (anchor);
3124         }
3125
3126       /* select */
3127       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3128       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3129
3130       /* we only handle selection modifications on the first button press
3131        */
3132       if (event->type == GDK_BUTTON_PRESS)
3133         {
3134           GtkCellRenderer *focus_cell;
3135
3136           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3137             tree_view->priv->ctrl_pressed = TRUE;
3138           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3139             tree_view->priv->shift_pressed = TRUE;
3140
3141           /* We update the focus cell here, this is also needed if the
3142            * column does not contain an editable cell.  In this case,
3143            * GtkCellArea did not receive the event for processing (and
3144            * could not update the focus cell).
3145            */
3146           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3147                                                               &cell_area,
3148                                                               &background_area,
3149                                                               event->x,
3150                                                               event->y);
3151
3152           if (focus_cell)
3153             gtk_tree_view_column_focus_cell (column, focus_cell);
3154
3155           if (event->state & GDK_CONTROL_MASK)
3156             {
3157               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3158               gtk_tree_view_real_toggle_cursor_row (tree_view);
3159             }
3160           else if (event->state & GDK_SHIFT_MASK)
3161             {
3162               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3163               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3164             }
3165           else
3166             {
3167               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
3168             }
3169
3170           tree_view->priv->ctrl_pressed = FALSE;
3171           tree_view->priv->shift_pressed = FALSE;
3172         }
3173
3174       /* the treeview may have been scrolled because of _set_cursor,
3175        * correct here
3176        */
3177
3178       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3179       dval = pre_val - aft_val;
3180
3181       cell_area.y += dval;
3182       background_area.y += dval;
3183
3184       /* Save press to possibly begin a drag
3185        */
3186       if (!column_handled_click &&
3187           !tree_view->priv->in_grab &&
3188           tree_view->priv->pressed_button < 0)
3189         {
3190           tree_view->priv->pressed_button = event->button;
3191           tree_view->priv->press_start_x = event->x;
3192           tree_view->priv->press_start_y = event->y;
3193
3194           if (tree_view->priv->rubber_banding_enable
3195               && !node_selected
3196               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3197             {
3198               tree_view->priv->press_start_y += tree_view->priv->dy;
3199               tree_view->priv->rubber_band_x = event->x;
3200               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3201               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3202
3203               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3204                 tree_view->priv->rubber_band_ctrl = TRUE;
3205               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3206                 tree_view->priv->rubber_band_shift = TRUE;
3207             }
3208         }
3209
3210       /* Test if a double click happened on the same row. */
3211       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
3212         {
3213           int double_click_time, double_click_distance;
3214
3215           g_object_get (gtk_settings_get_default (),
3216                         "gtk-double-click-time", &double_click_time,
3217                         "gtk-double-click-distance", &double_click_distance,
3218                         NULL);
3219
3220           /* Same conditions as _gdk_event_button_generate */
3221           if (tree_view->priv->last_button_x != -1 &&
3222               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3223               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3224               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3225             {
3226               /* We do no longer compare paths of this row and the
3227                * row clicked previously.  We use the double click
3228                * distance to decide whether this is a valid click,
3229                * allowing the mouse to slightly move over another row.
3230                */
3231               row_double_click = TRUE;
3232
3233               tree_view->priv->last_button_time = 0;
3234               tree_view->priv->last_button_x = -1;
3235               tree_view->priv->last_button_y = -1;
3236             }
3237           else
3238             {
3239               tree_view->priv->last_button_time = event->time;
3240               tree_view->priv->last_button_x = event->x;
3241               tree_view->priv->last_button_y = event->y;
3242             }
3243         }
3244
3245       if (row_double_click)
3246         {
3247           gtk_grab_remove (widget);
3248           gtk_tree_view_row_activated (tree_view, path, column);
3249
3250           if (tree_view->priv->pressed_button == event->button)
3251             tree_view->priv->pressed_button = -1;
3252         }
3253
3254       gtk_tree_path_free (path);
3255
3256       /* If we activated the row through a double click we don't want to grab
3257        * focus back, as moving focus to another widget is pretty common.
3258        */
3259       if (!row_double_click)
3260         grab_focus_and_unset_draw_keyfocus (tree_view);
3261
3262       return TRUE;
3263     }
3264
3265   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3266    */
3267   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3268     {
3269       column = list->data;
3270       if (event->window == _gtk_tree_view_column_get_window (column) &&
3271           gtk_tree_view_column_get_resizable (column) &&
3272           _gtk_tree_view_column_get_window (column))
3273         {
3274           GtkWidget *button;
3275           GtkAllocation button_allocation;
3276           gpointer drag_data;
3277
3278           if (event->type == GDK_2BUTTON_PRESS &&
3279               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3280             {
3281               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3282               _gtk_tree_view_column_autosize (tree_view, column);
3283               return TRUE;
3284             }
3285
3286           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3287                                _gtk_tree_view_column_get_window (column),
3288                                GDK_OWNERSHIP_NONE,
3289                                FALSE,
3290                                GDK_POINTER_MOTION_HINT_MASK
3291                                 | GDK_BUTTON1_MOTION_MASK
3292                                 | GDK_BUTTON_RELEASE_MASK,
3293                                NULL,
3294                                event->time) != GDK_GRAB_SUCCESS)
3295             return FALSE;
3296
3297           gtk_grab_add (widget);
3298           tree_view->priv->in_column_resize = TRUE;
3299
3300           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3301                                                    tree_view->priv->last_extra_space_per_column);
3302
3303           /* block attached dnd signal handler */
3304           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3305           if (drag_data)
3306             g_signal_handlers_block_matched (widget,
3307                                              G_SIGNAL_MATCH_DATA,
3308                                              0, 0, NULL, NULL,
3309                                              drag_data);
3310
3311           button = gtk_tree_view_column_get_button (column);
3312           gtk_widget_get_allocation (button, &button_allocation);
3313           tree_view->priv->drag_pos = i;
3314           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
3315
3316           if (!gtk_widget_has_focus (widget))
3317             gtk_widget_grab_focus (widget);
3318
3319           return TRUE;
3320         }
3321     }
3322   return FALSE;
3323 }
3324
3325 /* GtkWidget::button_release_event helper */
3326 static gboolean
3327 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3328                                           GdkEventButton *event)
3329 {
3330   GtkTreeView *tree_view;
3331   GtkWidget *button;
3332   GList *l;
3333   gboolean rtl;
3334   GdkDevice *device, *other;
3335
3336   tree_view = GTK_TREE_VIEW (widget);
3337
3338   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3339   device = gdk_event_get_device ((GdkEvent*)event);
3340   other = gdk_device_get_associated_device (device);
3341   gdk_device_ungrab (device, event->time);
3342   gdk_device_ungrab (other, event->time);
3343
3344   /* Move the button back */
3345   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3346   g_object_ref (button);
3347   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3348   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3349   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3350   g_object_unref (button);
3351   gtk_widget_queue_resize (widget);
3352   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3353     {
3354       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3355       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3356     }
3357   else
3358     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3359
3360   gtk_widget_grab_focus (button);
3361
3362   if (rtl)
3363     {
3364       if (tree_view->priv->cur_reorder &&
3365           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3366         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3367                                          tree_view->priv->cur_reorder->right_column);
3368     }
3369   else
3370     {
3371       if (tree_view->priv->cur_reorder &&
3372           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3373         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3374                                          tree_view->priv->cur_reorder->left_column);
3375     }
3376   tree_view->priv->drag_column = NULL;
3377   gdk_window_hide (tree_view->priv->drag_window);
3378
3379   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3380     g_slice_free (GtkTreeViewColumnReorder, l->data);
3381   g_list_free (tree_view->priv->column_drag_info);
3382   tree_view->priv->column_drag_info = NULL;
3383   tree_view->priv->cur_reorder = NULL;
3384
3385   if (tree_view->priv->drag_highlight_window)
3386     gdk_window_hide (tree_view->priv->drag_highlight_window);
3387
3388   /* Reset our flags */
3389   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3390   tree_view->priv->in_column_drag = FALSE;
3391
3392   return TRUE;
3393 }
3394
3395 /* GtkWidget::button_release_event helper */
3396 static gboolean
3397 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3398                                             GdkEventButton *event)
3399 {
3400   GtkTreeView *tree_view;
3401   gpointer drag_data;
3402
3403   tree_view = GTK_TREE_VIEW (widget);
3404
3405   tree_view->priv->drag_pos = -1;
3406
3407   /* unblock attached dnd signal handler */
3408   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3409   if (drag_data)
3410     g_signal_handlers_unblock_matched (widget,
3411                                        G_SIGNAL_MATCH_DATA,
3412                                        0, 0, NULL, NULL,
3413                                        drag_data);
3414
3415   tree_view->priv->in_column_resize = FALSE;
3416   gtk_grab_remove (widget);
3417   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3418   return TRUE;
3419 }
3420
3421 static gboolean
3422 gtk_tree_view_button_release (GtkWidget      *widget,
3423                               GdkEventButton *event)
3424 {
3425   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3426
3427   if (tree_view->priv->in_column_drag)
3428     return gtk_tree_view_button_release_drag_column (widget, event);
3429
3430   if (tree_view->priv->rubber_band_status)
3431     gtk_tree_view_stop_rubber_band (tree_view);
3432
3433   if (tree_view->priv->pressed_button == event->button)
3434     tree_view->priv->pressed_button = -1;
3435
3436   if (tree_view->priv->in_column_resize)
3437     return gtk_tree_view_button_release_column_resize (widget, event);
3438
3439   if (tree_view->priv->button_pressed_node == NULL)
3440     return FALSE;
3441
3442   if (event->button == 1)
3443     {
3444       gtk_grab_remove (widget);
3445       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3446           tree_view->priv->arrow_prelit)
3447         {
3448           GtkTreePath *path = NULL;
3449
3450           path = _gtk_tree_view_find_path (tree_view,
3451                                            tree_view->priv->button_pressed_tree,
3452                                            tree_view->priv->button_pressed_node);
3453           /* Actually activate the node */
3454           if (tree_view->priv->button_pressed_node->children == NULL)
3455             gtk_tree_view_real_expand_row (tree_view, path,
3456                                            tree_view->priv->button_pressed_tree,
3457                                            tree_view->priv->button_pressed_node,
3458                                            FALSE, TRUE);
3459           else
3460             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3461                                              tree_view->priv->button_pressed_tree,
3462                                              tree_view->priv->button_pressed_node, TRUE);
3463           gtk_tree_path_free (path);
3464         }
3465
3466       tree_view->priv->button_pressed_tree = NULL;
3467       tree_view->priv->button_pressed_node = NULL;
3468     }
3469
3470   return TRUE;
3471 }
3472
3473 static gboolean
3474 gtk_tree_view_grab_broken (GtkWidget          *widget,
3475                            GdkEventGrabBroken *event)
3476 {
3477   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3478
3479   if (tree_view->priv->in_column_drag)
3480     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3481
3482   if (tree_view->priv->in_column_resize)
3483     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3484
3485   return TRUE;
3486 }
3487
3488 #if 0
3489 static gboolean
3490 gtk_tree_view_configure (GtkWidget *widget,
3491                          GdkEventConfigure *event)
3492 {
3493   GtkTreeView *tree_view;
3494
3495   tree_view = GTK_TREE_VIEW (widget);
3496   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3497
3498   return FALSE;
3499 }
3500 #endif
3501
3502 /* GtkWidget::motion_event function set.
3503  */
3504
3505 static gboolean
3506 coords_are_over_arrow (GtkTreeView *tree_view,
3507                        GtkRBTree   *tree,
3508                        GtkRBNode   *node,
3509                        /* these are in bin window coords */
3510                        gint         x,
3511                        gint         y)
3512 {
3513   GdkRectangle arrow;
3514   gint x2;
3515
3516   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3517     return FALSE;
3518
3519   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3520     return FALSE;
3521
3522   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3523   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3524
3525   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3526
3527   arrow.width = x2 - arrow.x;
3528
3529   return (x >= arrow.x &&
3530           x < (arrow.x + arrow.width) &&
3531           y >= arrow.y &&
3532           y < (arrow.y + arrow.height));
3533 }
3534
3535 static gboolean
3536 auto_expand_timeout (gpointer data)
3537 {
3538   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3539   GtkTreePath *path;
3540
3541   if (tree_view->priv->prelight_node)
3542     {
3543       path = _gtk_tree_view_find_path (tree_view,
3544                                        tree_view->priv->prelight_tree,
3545                                        tree_view->priv->prelight_node);   
3546
3547       if (tree_view->priv->prelight_node->children)
3548         gtk_tree_view_collapse_row (tree_view, path);
3549       else
3550         gtk_tree_view_expand_row (tree_view, path, FALSE);
3551
3552       gtk_tree_path_free (path);
3553     }
3554
3555   tree_view->priv->auto_expand_timeout = 0;
3556
3557   return FALSE;
3558 }
3559
3560 static void
3561 remove_auto_expand_timeout (GtkTreeView *tree_view)
3562 {
3563   if (tree_view->priv->auto_expand_timeout != 0)
3564     {
3565       g_source_remove (tree_view->priv->auto_expand_timeout);
3566       tree_view->priv->auto_expand_timeout = 0;
3567     }
3568 }
3569
3570 static void
3571 do_prelight (GtkTreeView *tree_view,
3572              GtkRBTree   *tree,
3573              GtkRBNode   *node,
3574              /* these are in bin_window coords */
3575              gint         x,
3576              gint         y)
3577 {
3578   if (tree_view->priv->prelight_tree == tree &&
3579       tree_view->priv->prelight_node == node)
3580     {
3581       /*  We are still on the same node,
3582           but we might need to take care of the arrow  */
3583
3584       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3585         {
3586           gboolean over_arrow;
3587
3588           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3589
3590           if (over_arrow != tree_view->priv->arrow_prelit)
3591             {
3592               if (over_arrow)
3593                 tree_view->priv->arrow_prelit = TRUE;
3594               else
3595                 tree_view->priv->arrow_prelit = FALSE;
3596
3597               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3598             }
3599         }
3600
3601       return;
3602     }
3603
3604   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3605     {
3606       /*  Unprelight the old node and arrow  */
3607
3608       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3609                              GTK_RBNODE_IS_PRELIT);
3610
3611       if (tree_view->priv->arrow_prelit
3612           && gtk_tree_view_draw_expanders (tree_view))
3613         {
3614           tree_view->priv->arrow_prelit = FALSE;
3615           
3616           gtk_tree_view_queue_draw_arrow (tree_view,
3617                                           tree_view->priv->prelight_tree,
3618                                           tree_view->priv->prelight_node);
3619         }
3620
3621       _gtk_tree_view_queue_draw_node (tree_view,
3622                                       tree_view->priv->prelight_tree,
3623                                       tree_view->priv->prelight_node,
3624                                       NULL);
3625     }
3626
3627
3628   if (tree_view->priv->hover_expand)
3629     remove_auto_expand_timeout (tree_view);
3630
3631   /*  Set the new prelight values  */
3632   tree_view->priv->prelight_node = node;
3633   tree_view->priv->prelight_tree = tree;
3634
3635   if (!node || !tree)
3636     return;
3637
3638   /*  Prelight the new node and arrow  */
3639
3640   if (gtk_tree_view_draw_expanders (tree_view)
3641       && coords_are_over_arrow (tree_view, tree, node, x, y))
3642     {
3643       tree_view->priv->arrow_prelit = TRUE;
3644
3645       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3646     }
3647
3648   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3649
3650   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3651
3652   if (tree_view->priv->hover_expand)
3653     {
3654       tree_view->priv->auto_expand_timeout = 
3655         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3656     }
3657 }
3658
3659 static void
3660 prelight_or_select (GtkTreeView *tree_view,
3661                     GtkRBTree   *tree,
3662                     GtkRBNode   *node,
3663                     /* these are in bin_window coords */
3664                     gint         x,
3665                     gint         y)
3666 {
3667   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3668   
3669   if (tree_view->priv->hover_selection &&
3670       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3671       !(tree_view->priv->edited_column &&
3672         gtk_cell_area_get_edit_widget 
3673         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3674     {
3675       if (node)
3676         {
3677           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3678             {
3679               GtkTreePath *path;
3680               
3681               path = _gtk_tree_view_find_path (tree_view, tree, node);
3682               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3683               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3684                 {
3685                   tree_view->priv->draw_keyfocus = FALSE;
3686                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3687                 }
3688               gtk_tree_path_free (path);
3689             }
3690         }
3691
3692       else if (mode == GTK_SELECTION_SINGLE)
3693         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3694     }
3695
3696     do_prelight (tree_view, tree, node, x, y);
3697 }
3698
3699 static void
3700 ensure_unprelighted (GtkTreeView *tree_view)
3701 {
3702   do_prelight (tree_view,
3703                NULL, NULL,
3704                -1000, -1000); /* coords not possibly over an arrow */
3705
3706   g_assert (tree_view->priv->prelight_node == NULL);
3707 }
3708
3709 static void
3710 update_prelight (GtkTreeView *tree_view,
3711                  gint         x,
3712                  gint         y)
3713 {
3714   int new_y;
3715   GtkRBTree *tree;
3716   GtkRBNode *node;
3717
3718   if (tree_view->priv->tree == NULL)
3719     return;
3720
3721   if (x == -10000)
3722     {
3723       ensure_unprelighted (tree_view);
3724       return;
3725     }
3726
3727   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3728   if (new_y < 0)
3729     new_y = 0;
3730
3731   _gtk_rbtree_find_offset (tree_view->priv->tree,
3732                            new_y, &tree, &node);
3733
3734   if (node)
3735     prelight_or_select (tree_view, tree, node, x, y);
3736 }
3737
3738
3739
3740
3741 /* Our motion arrow is either a box (in the case of the original spot)
3742  * or an arrow.  It is expander_size wide.
3743  */
3744 /*
3745  * 11111111111111
3746  * 01111111111110
3747  * 00111111111100
3748  * 00011111111000
3749  * 00001111110000
3750  * 00000111100000
3751  * 00000111100000
3752  * 00000111100000
3753  * ~ ~ ~ ~ ~ ~ ~
3754  * 00000111100000
3755  * 00000111100000
3756  * 00000111100000
3757  * 00001111110000
3758  * 00011111111000
3759  * 00111111111100
3760  * 01111111111110
3761  * 11111111111111
3762  */
3763
3764 static void
3765 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3766 {
3767   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3768   GtkWidget *widget = GTK_WIDGET (tree_view);
3769   cairo_surface_t *mask_image;
3770   cairo_region_t *mask_region;
3771   gint x;
3772   gint y;
3773   gint width;
3774   gint height;
3775   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3776   GdkWindowAttr attributes;
3777   guint attributes_mask;
3778   cairo_t *cr;
3779
3780   if (!reorder ||
3781       reorder->left_column == tree_view->priv->drag_column ||
3782       reorder->right_column == tree_view->priv->drag_column)
3783     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3784   else if (reorder->left_column || reorder->right_column)
3785     {
3786       GtkAllocation left_allocation, right_allocation;
3787       GdkRectangle visible_rect;
3788       GtkWidget *button;
3789
3790       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3791       if (reorder->left_column)
3792         {
3793           button = gtk_tree_view_column_get_button (reorder->left_column);
3794           gtk_widget_get_allocation (button, &left_allocation);
3795           x = left_allocation.x + left_allocation.width;
3796         }
3797       else
3798         {
3799           button = gtk_tree_view_column_get_button (reorder->right_column);
3800           gtk_widget_get_allocation (button, &right_allocation);
3801           x = right_allocation.x;
3802         }
3803
3804       if (x < visible_rect.x)
3805         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3806       else if (x > visible_rect.x + visible_rect.width)
3807         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3808       else
3809         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3810     }
3811
3812   /* We want to draw the rectangle over the initial location. */
3813   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3814     {
3815       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3816         {
3817           GtkAllocation drag_allocation;
3818           GtkWidget    *button;
3819
3820           if (tree_view->priv->drag_highlight_window)
3821             {
3822               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3823                                         NULL);
3824               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3825             }
3826
3827           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3828           attributes.window_type = GDK_WINDOW_CHILD;
3829           attributes.wclass = GDK_INPUT_OUTPUT;
3830           attributes.x = tree_view->priv->drag_column_x;
3831           attributes.y = 0;
3832           gtk_widget_get_allocation (button, &drag_allocation);
3833           width = attributes.width = drag_allocation.width;
3834           height = attributes.height = drag_allocation.height;
3835           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3836           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3837           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3838           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3839           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3840
3841           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3842           cr = cairo_create (mask_image);
3843
3844           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3845           cairo_stroke (cr);
3846           cairo_destroy (cr);
3847
3848           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3849           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3850                                            mask_region, 0, 0);
3851
3852           cairo_region_destroy (mask_region);
3853           cairo_surface_destroy (mask_image);
3854
3855           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3856         }
3857     }
3858   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3859     {
3860       GtkAllocation button_allocation;
3861       GtkWidget    *button;
3862
3863       width = tree_view->priv->expander_size;
3864
3865       /* Get x, y, width, height of arrow */
3866       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3867       if (reorder->left_column)
3868         {
3869           button = gtk_tree_view_column_get_button (reorder->left_column);
3870           gtk_widget_get_allocation (button, &button_allocation);
3871           x += button_allocation.x + button_allocation.width - width/2;
3872           height = button_allocation.height;
3873         }
3874       else
3875         {
3876           button = gtk_tree_view_column_get_button (reorder->right_column);
3877           gtk_widget_get_allocation (button, &button_allocation);
3878           x += button_allocation.x - width/2;
3879           height = button_allocation.height;
3880         }
3881       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3882       height += tree_view->priv->expander_size;
3883
3884       /* Create the new window */
3885       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3886         {
3887           if (tree_view->priv->drag_highlight_window)
3888             {
3889               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3890                                         NULL);
3891               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3892             }
3893
3894           attributes.window_type = GDK_WINDOW_TEMP;
3895           attributes.wclass = GDK_INPUT_OUTPUT;
3896           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3897           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3898           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3899           attributes.x = x;
3900           attributes.y = y;
3901           attributes.width = width;
3902           attributes.height = height;
3903           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3904                                                                    &attributes, attributes_mask);
3905           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3906
3907           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3908
3909           cr = cairo_create (mask_image);
3910           cairo_move_to (cr, 0, 0);
3911           cairo_line_to (cr, width, 0);
3912           cairo_line_to (cr, width / 2., width / 2);
3913           cairo_move_to (cr, 0, height);
3914           cairo_line_to (cr, width, height);
3915           cairo_line_to (cr, width / 2., height - width / 2.);
3916           cairo_fill (cr);
3917           cairo_destroy (cr);
3918
3919           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3920           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3921                                            mask_region, 0, 0);
3922
3923           cairo_region_destroy (mask_region);
3924           cairo_surface_destroy (mask_image);
3925         }
3926
3927       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3928       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3929     }
3930   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3931            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3932     {
3933       GtkAllocation allocation;
3934       GtkWidget    *button;
3935
3936       width = tree_view->priv->expander_size;
3937
3938       /* Get x, y, width, height of arrow */
3939       width = width/2; /* remember, the arrow only takes half the available width */
3940       gdk_window_get_origin (gtk_widget_get_window (widget),
3941                              &x, &y);
3942       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3943         {
3944           gtk_widget_get_allocation (widget, &allocation);
3945           x += allocation.width - width;
3946         }
3947
3948       if (reorder->left_column)
3949         {
3950           button = gtk_tree_view_column_get_button (reorder->left_column);
3951           gtk_widget_get_allocation (button, &allocation);
3952           height = allocation.height;
3953         }
3954       else
3955         {
3956           button = gtk_tree_view_column_get_button (reorder->right_column);
3957           gtk_widget_get_allocation (button, &allocation);
3958           height = allocation.height;
3959         }
3960
3961       y -= tree_view->priv->expander_size;
3962       height += 2*tree_view->priv->expander_size;
3963
3964       /* Create the new window */
3965       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3966           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3967         {
3968           if (tree_view->priv->drag_highlight_window)
3969             {
3970               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3971                                         NULL);
3972               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3973             }
3974
3975           attributes.window_type = GDK_WINDOW_TEMP;
3976           attributes.wclass = GDK_INPUT_OUTPUT;
3977           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3978           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3979           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3980           attributes.x = x;
3981           attributes.y = y;
3982           attributes.width = width;
3983           attributes.height = height;
3984           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3985           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3986
3987           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3988
3989           cr = cairo_create (mask_image);
3990           /* mirror if we're on the left */
3991           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3992             {
3993               cairo_translate (cr, width, 0);
3994               cairo_scale (cr, -1, 1);
3995             }
3996           cairo_move_to (cr, 0, 0);
3997           cairo_line_to (cr, width, width);
3998           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3999           cairo_move_to (cr, 0, height);
4000           cairo_line_to (cr, width, height - width);
4001           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
4002           cairo_fill (cr);
4003           cairo_destroy (cr);
4004
4005           mask_region = gdk_cairo_region_create_from_surface (mask_image);
4006           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
4007                                            mask_region, 0, 0);
4008
4009           cairo_region_destroy (mask_region);
4010           cairo_surface_destroy (mask_image);
4011         }
4012
4013       tree_view->priv->drag_column_window_state = arrow_type;
4014       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
4015    }
4016   else
4017     {
4018       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
4019       gdk_window_hide (tree_view->priv->drag_highlight_window);
4020       return;
4021     }
4022
4023   gdk_window_show (tree_view->priv->drag_highlight_window);
4024   gdk_window_raise (tree_view->priv->drag_highlight_window);
4025 }
4026
4027 static gboolean
4028 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
4029                                     GdkEventMotion *event)
4030 {
4031   gint x;
4032   gint new_width;
4033   GtkTreeViewColumn *column;
4034   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4035
4036   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
4037
4038   if (event->is_hint || event->window != gtk_widget_get_window (widget))
4039     gtk_widget_get_pointer (widget, &x, NULL);
4040   else
4041     x = event->x;
4042
4043   if (tree_view->priv->hadjustment)
4044     x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
4045
4046   new_width = gtk_tree_view_new_column_width (tree_view,
4047                                               tree_view->priv->drag_pos, &x);
4048   if (x != tree_view->priv->x_drag &&
4049       (new_width != gtk_tree_view_column_get_fixed_width (column)))
4050     {
4051       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
4052
4053       if (gtk_tree_view_column_get_expand (column))
4054         new_width -= tree_view->priv->last_extra_space_per_column;
4055
4056       _gtk_tree_view_column_set_resized_width (column, new_width);
4057
4058
4059       gtk_widget_queue_resize (widget);
4060     }
4061
4062   return FALSE;
4063 }
4064
4065
4066 static void
4067 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
4068 {
4069   GtkTreeViewColumnReorder *reorder = NULL;
4070   GList *list;
4071   gint mouse_x;
4072
4073   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
4074   for (list = tree_view->priv->column_drag_info; list; list = list->next)
4075     {
4076       reorder = (GtkTreeViewColumnReorder *) list->data;
4077       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
4078         break;
4079       reorder = NULL;
4080     }
4081
4082   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
4083       return;*/
4084
4085   tree_view->priv->cur_reorder = reorder;
4086   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
4087 }
4088
4089 static void
4090 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4091 {
4092   GdkRectangle visible_rect;
4093   gint y;
4094   gint offset;
4095
4096   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
4097   y += tree_view->priv->dy;
4098
4099   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4100
4101   /* see if we are near the edge. */
4102   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4103   if (offset > 0)
4104     {
4105       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4106       if (offset < 0)
4107         return;
4108     }
4109
4110   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4111                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4112 }
4113
4114 static gboolean
4115 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
4116 {
4117   GdkRectangle visible_rect;
4118   gint x;
4119   gint offset;
4120
4121   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
4122
4123   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4124
4125   /* See if we are near the edge. */
4126   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4127   if (offset > 0)
4128     {
4129       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4130       if (offset < 0)
4131         return TRUE;
4132     }
4133   offset = offset/3;
4134
4135   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4136                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4137
4138   return TRUE;
4139
4140 }
4141
4142 static gboolean
4143 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4144                                   GdkEventMotion *event)
4145 {
4146   GtkAllocation allocation, button_allocation;
4147   GtkTreeView *tree_view = (GtkTreeView *) widget;
4148   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4149   GtkWidget *button;
4150   gint x, y;
4151
4152   /* Sanity Check */
4153   if ((column == NULL) ||
4154       (event->window != tree_view->priv->drag_window))
4155     return FALSE;
4156
4157   button = gtk_tree_view_column_get_button (column);
4158
4159   /* Handle moving the header */
4160   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4161   gtk_widget_get_allocation (widget, &allocation);
4162   gtk_widget_get_allocation (button, &button_allocation);
4163   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4164              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4165   gdk_window_move (tree_view->priv->drag_window, x, y);
4166   
4167   /* autoscroll, if needed */
4168   gtk_tree_view_horizontal_autoscroll (tree_view);
4169   /* Update the current reorder position and arrow; */
4170   gtk_tree_view_update_current_reorder (tree_view);
4171
4172   return TRUE;
4173 }
4174
4175 static void
4176 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4177 {
4178   remove_scroll_timeout (tree_view);
4179   gtk_grab_remove (GTK_WIDGET (tree_view));
4180
4181   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4182     {
4183       GtkTreePath *tmp_path;
4184
4185       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4186
4187       /* The anchor path should be set to the start path */
4188       tmp_path = _gtk_tree_view_find_path (tree_view,
4189                                            tree_view->priv->rubber_band_start_tree,
4190                                            tree_view->priv->rubber_band_start_node);
4191
4192       if (tree_view->priv->anchor)
4193         gtk_tree_row_reference_free (tree_view->priv->anchor);
4194
4195       tree_view->priv->anchor =
4196         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4197                                           tree_view->priv->model,
4198                                           tmp_path);
4199
4200       gtk_tree_path_free (tmp_path);
4201
4202       /* ... and the cursor to the end path */
4203       tmp_path = _gtk_tree_view_find_path (tree_view,
4204                                            tree_view->priv->rubber_band_end_tree,
4205                                            tree_view->priv->rubber_band_end_node);
4206       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
4207       gtk_tree_path_free (tmp_path);
4208
4209       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4210     }
4211
4212   /* Clear status variables */
4213   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4214   tree_view->priv->rubber_band_shift = 0;
4215   tree_view->priv->rubber_band_ctrl = 0;
4216
4217   tree_view->priv->rubber_band_start_node = NULL;
4218   tree_view->priv->rubber_band_start_tree = NULL;
4219   tree_view->priv->rubber_band_end_node = NULL;
4220   tree_view->priv->rubber_band_end_tree = NULL;
4221 }
4222
4223 static void
4224 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4225                                                  GtkRBTree   *start_tree,
4226                                                  GtkRBNode   *start_node,
4227                                                  GtkRBTree   *end_tree,
4228                                                  GtkRBNode   *end_node,
4229                                                  gboolean     select,
4230                                                  gboolean     skip_start,
4231                                                  gboolean     skip_end)
4232 {
4233   if (start_node == end_node)
4234     return;
4235
4236   /* We skip the first node and jump inside the loop */
4237   if (skip_start)
4238     goto skip_first;
4239
4240   do
4241     {
4242       /* Small optimization by assuming insensitive nodes are never
4243        * selected.
4244        */
4245       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4246         {
4247           GtkTreePath *path;
4248           gboolean selectable;
4249
4250           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
4251           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4252           gtk_tree_path_free (path);
4253
4254           if (!selectable)
4255             goto node_not_selectable;
4256         }
4257
4258       if (select)
4259         {
4260           if (tree_view->priv->rubber_band_shift)
4261             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4262           else if (tree_view->priv->rubber_band_ctrl)
4263             {
4264               /* Toggle the selection state */
4265               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4266                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4267               else
4268                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4269             }
4270           else
4271             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4272         }
4273       else
4274         {
4275           /* Mirror the above */
4276           if (tree_view->priv->rubber_band_shift)
4277             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4278           else if (tree_view->priv->rubber_band_ctrl)
4279             {
4280               /* Toggle the selection state */
4281               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4282                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4283               else
4284                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4285             }
4286           else
4287             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4288         }
4289
4290       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4291
4292 node_not_selectable:
4293       if (start_node == end_node)
4294         break;
4295
4296 skip_first:
4297
4298       if (start_node->children)
4299         {
4300           start_tree = start_node->children;
4301           start_node = start_tree->root;
4302           while (start_node->left != start_tree->nil)
4303             start_node = start_node->left;
4304         }
4305       else
4306         {
4307           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4308
4309           if (!start_tree)
4310             /* Ran out of tree */
4311             break;
4312         }
4313
4314       if (skip_end && start_node == end_node)
4315         break;
4316     }
4317   while (TRUE);
4318 }
4319
4320 static void
4321 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4322 {
4323   GtkRBTree *start_tree, *end_tree;
4324   GtkRBNode *start_node, *end_node;
4325
4326   _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);
4327   _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);
4328
4329   /* Handle the start area first */
4330   if (!tree_view->priv->rubber_band_start_node)
4331     {
4332       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4333                                                        start_tree,
4334                                                        start_node,
4335                                                        end_tree,
4336                                                        end_node,
4337                                                        TRUE,
4338                                                        FALSE,
4339                                                        FALSE);
4340     }
4341   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4342            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4343     {
4344       /* New node is above the old one; selection became bigger */
4345       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4346                                                        start_tree,
4347                                                        start_node,
4348                                                        tree_view->priv->rubber_band_start_tree,
4349                                                        tree_view->priv->rubber_band_start_node,
4350                                                        TRUE,
4351                                                        FALSE,
4352                                                        TRUE);
4353     }
4354   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4355            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4356     {
4357       /* New node is below the old one; selection became smaller */
4358       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4359                                                        tree_view->priv->rubber_band_start_tree,
4360                                                        tree_view->priv->rubber_band_start_node,
4361                                                        start_tree,
4362                                                        start_node,
4363                                                        FALSE,
4364                                                        FALSE,
4365                                                        TRUE);
4366     }
4367
4368   tree_view->priv->rubber_band_start_tree = start_tree;
4369   tree_view->priv->rubber_band_start_node = start_node;
4370
4371   /* Next, handle the end area */
4372   if (!tree_view->priv->rubber_band_end_node)
4373     {
4374       /* In the event this happens, start_node was also NULL; this case is
4375        * handled above.
4376        */
4377     }
4378   else if (!end_node)
4379     {
4380       /* Find the last node in the tree */
4381       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4382                                &end_tree, &end_node);
4383
4384       /* Selection reached end of the tree */
4385       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4386                                                        tree_view->priv->rubber_band_end_tree,
4387                                                        tree_view->priv->rubber_band_end_node,
4388                                                        end_tree,
4389                                                        end_node,
4390                                                        TRUE,
4391                                                        TRUE,
4392                                                        FALSE);
4393     }
4394   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4395            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4396     {
4397       /* New node is below the old one; selection became bigger */
4398       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4399                                                        tree_view->priv->rubber_band_end_tree,
4400                                                        tree_view->priv->rubber_band_end_node,
4401                                                        end_tree,
4402                                                        end_node,
4403                                                        TRUE,
4404                                                        TRUE,
4405                                                        FALSE);
4406     }
4407   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4408            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4409     {
4410       /* New node is above the old one; selection became smaller */
4411       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4412                                                        end_tree,
4413                                                        end_node,
4414                                                        tree_view->priv->rubber_band_end_tree,
4415                                                        tree_view->priv->rubber_band_end_node,
4416                                                        FALSE,
4417                                                        TRUE,
4418                                                        FALSE);
4419     }
4420
4421   tree_view->priv->rubber_band_end_tree = end_tree;
4422   tree_view->priv->rubber_band_end_node = end_node;
4423 }
4424
4425 static void
4426 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4427 {
4428   gint x, y;
4429   GdkRectangle old_area;
4430   GdkRectangle new_area;
4431   GdkRectangle common;
4432   cairo_region_t *invalid_region;
4433
4434   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4435   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4436   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4437   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4438
4439   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4440
4441   x = MAX (x, 0);
4442   y = MAX (y, 0) + tree_view->priv->dy;
4443
4444   new_area.x = MIN (tree_view->priv->press_start_x, x);
4445   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4446   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4447   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4448
4449   invalid_region = cairo_region_create_rectangle (&old_area);
4450   cairo_region_union_rectangle (invalid_region, &new_area);
4451
4452   gdk_rectangle_intersect (&old_area, &new_area, &common);
4453   if (common.width > 2 && common.height > 2)
4454     {
4455       cairo_region_t *common_region;
4456
4457       /* make sure the border is invalidated */
4458       common.x += 1;
4459       common.y += 1;
4460       common.width -= 2;
4461       common.height -= 2;
4462
4463       common_region = cairo_region_create_rectangle (&common);
4464
4465       cairo_region_subtract (invalid_region, common_region);
4466       cairo_region_destroy (common_region);
4467     }
4468
4469   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4470
4471   cairo_region_destroy (invalid_region);
4472
4473   tree_view->priv->rubber_band_x = x;
4474   tree_view->priv->rubber_band_y = y;
4475
4476   gtk_tree_view_update_rubber_band_selection (tree_view);
4477 }
4478
4479 static void
4480 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4481                                  cairo_t      *cr)
4482 {
4483   GdkRectangle rect;
4484   GtkStyle *style;
4485
4486   cairo_save (cr);
4487
4488   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4489   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4490   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4491   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4492
4493   cairo_set_line_width (cr, 1.0);
4494
4495   style = gtk_widget_get_style (GTK_WIDGET (tree_view));
4496
4497   gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
4498
4499   gdk_cairo_rectangle (cr, &rect);
4500   cairo_clip (cr);
4501   cairo_paint_with_alpha (cr, 0.25);
4502
4503   cairo_rectangle (cr,
4504                    rect.x + 0.5, rect.y + 0.5,
4505                    rect.width - 1, rect.height - 1);
4506   cairo_stroke (cr);
4507
4508   cairo_restore (cr);
4509 }
4510
4511 static gboolean
4512 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4513                                  GdkEventMotion *event)
4514 {
4515   GtkTreeView *tree_view;
4516   GtkRBTree *tree;
4517   GtkRBNode *node;
4518   gint new_y;
4519
4520   tree_view = (GtkTreeView *) widget;
4521
4522   if (tree_view->priv->tree == NULL)
4523     return FALSE;
4524
4525   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4526     {
4527       gtk_grab_add (GTK_WIDGET (tree_view));
4528       gtk_tree_view_update_rubber_band (tree_view);
4529
4530       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4531     }
4532   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4533     {
4534       gtk_tree_view_update_rubber_band (tree_view);
4535
4536       add_scroll_timeout (tree_view);
4537     }
4538
4539   /* only check for an initiated drag when a button is pressed */
4540   if (tree_view->priv->pressed_button >= 0
4541       && !tree_view->priv->rubber_band_status)
4542     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4543
4544   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4545   if (new_y < 0)
4546     new_y = 0;
4547
4548   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4549
4550   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4551   if ((tree_view->priv->button_pressed_node != NULL) &&
4552       (tree_view->priv->button_pressed_node != node))
4553     node = NULL;
4554
4555   tree_view->priv->event_last_x = event->x;
4556   tree_view->priv->event_last_y = event->y;
4557
4558   prelight_or_select (tree_view, tree, node, event->x, event->y);
4559
4560   return TRUE;
4561 }
4562
4563 static gboolean
4564 gtk_tree_view_motion (GtkWidget      *widget,
4565                       GdkEventMotion *event)
4566 {
4567   GtkTreeView *tree_view;
4568
4569   tree_view = (GtkTreeView *) widget;
4570
4571   /* Resizing a column */
4572   if (tree_view->priv->in_column_resize)
4573     return gtk_tree_view_motion_resize_column (widget, event);
4574
4575   /* Drag column */
4576   if (tree_view->priv->in_column_drag)
4577     return gtk_tree_view_motion_drag_column (widget, event);
4578
4579   /* Sanity check it */
4580   if (event->window == tree_view->priv->bin_window)
4581     return gtk_tree_view_motion_bin_window (widget, event);
4582
4583   return FALSE;
4584 }
4585
4586 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4587  * the tree is empty.
4588  */
4589 static void
4590 invalidate_empty_focus (GtkTreeView *tree_view)
4591 {
4592   GdkRectangle area;
4593
4594   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4595     return;
4596
4597   area.x = 0;
4598   area.y = 0;
4599   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4600   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4601   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4602 }
4603
4604 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4605  * is empty.
4606  */
4607 static void
4608 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4609 {
4610   GtkWidget *widget = GTK_WIDGET (tree_view);
4611   gint w, h;
4612
4613   if (!gtk_widget_has_focus (widget))
4614     return;
4615
4616   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4617   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4618
4619   if (w > 0 && h > 0)
4620     gtk_paint_focus (gtk_widget_get_style (widget),
4621                      cr,
4622                      gtk_widget_get_state (widget),
4623                      widget,
4624                      NULL,
4625                      1, 1, w, h);
4626 }
4627
4628 typedef enum {
4629   GTK_TREE_VIEW_GRID_LINE,
4630   GTK_TREE_VIEW_TREE_LINE,
4631   GTK_TREE_VIEW_FOREGROUND_LINE
4632 } GtkTreeViewLineType;
4633
4634 static void
4635 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4636                          cairo_t             *cr,
4637                          GtkTreeViewLineType  type,
4638                          int                  x1,
4639                          int                  y1,
4640                          int                  x2,
4641                          int                  y2)
4642 {
4643   cairo_save (cr);
4644
4645   switch (type)
4646     {
4647     case GTK_TREE_VIEW_TREE_LINE:
4648       cairo_set_source_rgb (cr, 0, 0, 0);
4649       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4650       if (tree_view->priv->tree_line_dashes[0])
4651         cairo_set_dash (cr, 
4652                         tree_view->priv->tree_line_dashes,
4653                         2, 0.5);
4654       break;
4655     case GTK_TREE_VIEW_GRID_LINE:
4656       cairo_set_source_rgb (cr, 0, 0, 0);
4657       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4658       if (tree_view->priv->grid_line_dashes[0])
4659         cairo_set_dash (cr, 
4660                         tree_view->priv->grid_line_dashes,
4661                         2, 0.5);
4662       break;
4663     default:
4664       g_assert_not_reached ();
4665       /* fall through */
4666     case GTK_TREE_VIEW_FOREGROUND_LINE:
4667       cairo_set_line_width (cr, 1.0);
4668       gdk_cairo_set_source_color (cr,
4669                                   &gtk_widget_get_style (GTK_WIDGET (tree_view))->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4670       break;
4671     }
4672
4673   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4674   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4675   cairo_stroke (cr);
4676
4677   cairo_restore (cr);
4678 }
4679                          
4680 static void
4681 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4682                                cairo_t        *cr,
4683                                gint            n_visible_columns)
4684 {
4685   GList *list = tree_view->priv->columns;
4686   gint i = 0;
4687   gint current_x = 0;
4688
4689   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4690       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4691     return;
4692
4693   /* Only draw the lines for visible rows and columns */
4694   for (list = tree_view->priv->columns; list; list = list->next, i++)
4695     {
4696       GtkTreeViewColumn *column = list->data;
4697
4698       /* We don't want a line for the last column */
4699       if (i == n_visible_columns - 1)
4700         break;
4701
4702       if (!gtk_tree_view_column_get_visible (column))
4703         continue;
4704
4705       current_x += gtk_tree_view_column_get_width (column);
4706
4707       gtk_tree_view_draw_line (tree_view, cr,
4708                                GTK_TREE_VIEW_GRID_LINE,
4709                                current_x - 1, 0,
4710                                current_x - 1, tree_view->priv->height);
4711     }
4712 }
4713
4714 /* Warning: Very scary function.
4715  * Modify at your own risk
4716  *
4717  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4718  * FIXME: It's not...
4719  */
4720 static gboolean
4721 gtk_tree_view_bin_draw (GtkWidget      *widget,
4722                         cairo_t        *cr)
4723 {
4724   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4725   GtkTreePath *path;
4726   GtkStyle *style;
4727   GtkRBTree *tree;
4728   GList *list;
4729   GtkRBNode *node;
4730   GtkRBNode *cursor = NULL;
4731   GtkRBTree *cursor_tree = NULL;
4732   GtkRBNode *drag_highlight = NULL;
4733   GtkRBTree *drag_highlight_tree = NULL;
4734   GtkTreeIter iter;
4735   gint new_y;
4736   gint y_offset, cell_offset;
4737   gint max_height;
4738   gint depth;
4739   GdkRectangle background_area;
4740   GdkRectangle cell_area;
4741   GdkRectangle clip;
4742   guint flags;
4743   gint highlight_x;
4744   gint expander_cell_width;
4745   gint bin_window_width;
4746   gint bin_window_height;
4747   GtkTreePath *cursor_path;
4748   GtkTreePath *drag_dest_path;
4749   GList *first_column, *last_column;
4750   gint vertical_separator;
4751   gint horizontal_separator;
4752   gint focus_line_width;
4753   gboolean allow_rules;
4754   gboolean has_can_focus_cell;
4755   gboolean rtl;
4756   gint n_visible_columns;
4757   gint pointer_x, pointer_y;
4758   gint grid_line_width;
4759   gboolean got_pointer = FALSE;
4760   gboolean draw_vgrid_lines, draw_hgrid_lines;
4761
4762   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4763
4764   gtk_widget_style_get (widget,
4765                         "horizontal-separator", &horizontal_separator,
4766                         "vertical-separator", &vertical_separator,
4767                         "allow-rules", &allow_rules,
4768                         "focus-line-width", &focus_line_width,
4769                         NULL);
4770
4771   if (tree_view->priv->tree == NULL)
4772     {
4773       draw_empty_focus (tree_view, cr);
4774       return TRUE;
4775     }
4776
4777   style = gtk_widget_get_style (widget);
4778
4779   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4780   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4781   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4782   cairo_clip (cr);
4783   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4784     return TRUE;
4785
4786   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4787
4788   if (new_y < 0)
4789     new_y = 0;
4790   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4791
4792   if (tree_view->priv->height < bin_window_height)
4793     {
4794       gtk_paint_flat_box (style,
4795                           cr,
4796                           gtk_widget_get_state (widget),
4797                           GTK_SHADOW_NONE,
4798                           widget,
4799                           "cell_even",
4800                           0, tree_view->priv->height,
4801                           bin_window_width,
4802                           bin_window_height - tree_view->priv->height);
4803     }
4804
4805   if (node == NULL)
4806     return TRUE;
4807
4808   /* find the path for the node */
4809   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4810                                    tree,
4811                                    node);
4812   gtk_tree_model_get_iter (tree_view->priv->model,
4813                            &iter,
4814                            path);
4815   depth = gtk_tree_path_get_depth (path);
4816   gtk_tree_path_free (path);
4817   
4818   cursor_path = NULL;
4819   drag_dest_path = NULL;
4820
4821   if (tree_view->priv->cursor)
4822     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4823
4824   if (cursor_path)
4825     _gtk_tree_view_find_node (tree_view, cursor_path,
4826                               &cursor_tree, &cursor);
4827
4828   if (tree_view->priv->drag_dest_row)
4829     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4830
4831   if (drag_dest_path)
4832     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4833                               &drag_highlight_tree, &drag_highlight);
4834
4835   draw_vgrid_lines =
4836     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4837     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4838   draw_hgrid_lines =
4839     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4840     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4841
4842   if (draw_vgrid_lines || draw_hgrid_lines)
4843     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4844   
4845   n_visible_columns = 0;
4846   for (list = tree_view->priv->columns; list; list = list->next)
4847     {
4848       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4849         continue;
4850       n_visible_columns ++;
4851     }
4852
4853   /* Find the last column */
4854   for (last_column = g_list_last (tree_view->priv->columns);
4855        last_column &&
4856        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4857        last_column = last_column->prev)
4858     ;
4859
4860   /* and the first */
4861   for (first_column = g_list_first (tree_view->priv->columns);
4862        first_column &&
4863        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4864        first_column = first_column->next)
4865     ;
4866
4867   /* Actually process the expose event.  To do this, we want to
4868    * start at the first node of the event, and walk the tree in
4869    * order, drawing each successive node.
4870    */
4871
4872   do
4873     {
4874       gboolean parity;
4875       gboolean is_separator = FALSE;
4876       gboolean is_first = FALSE;
4877       gboolean is_last = FALSE;
4878       
4879       is_separator = row_is_separator (tree_view, &iter, NULL);
4880
4881       max_height = gtk_tree_view_get_row_height (tree_view, node);
4882
4883       cell_offset = 0;
4884       highlight_x = 0; /* should match x coord of first cell */
4885       expander_cell_width = 0;
4886
4887       background_area.y = y_offset + clip.y;
4888       background_area.height = max_height;
4889
4890       flags = 0;
4891
4892       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4893         flags |= GTK_CELL_RENDERER_PRELIT;
4894
4895       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4896         flags |= GTK_CELL_RENDERER_SELECTED;
4897
4898       parity = _gtk_rbtree_node_find_parity (tree, node);
4899
4900       /* we *need* to set cell data on all cells before the call
4901        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4902        * return a correct value.
4903        */
4904       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4905            list;
4906            list = (rtl ? list->prev : list->next))
4907         {
4908           GtkTreeViewColumn *column = list->data;
4909           gtk_tree_view_column_cell_set_cell_data (column,
4910                                                    tree_view->priv->model,
4911                                                    &iter,
4912                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4913                                                    node->children?TRUE:FALSE);
4914         }
4915
4916       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4917
4918       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4919            list;
4920            list = (rtl ? list->prev : list->next))
4921         {
4922           GtkTreeViewColumn *column = list->data;
4923           const gchar *detail = NULL;
4924           gchar new_detail[128];
4925           gint width;
4926           GtkStateType state;
4927           gboolean draw_focus;
4928
4929           if (!gtk_tree_view_column_get_visible (column))
4930             continue;
4931
4932           width = gtk_tree_view_column_get_width (column);
4933
4934           if (cell_offset > clip.x + clip.width ||
4935               cell_offset + width < clip.x)
4936             {
4937               cell_offset += width;
4938               continue;
4939             }
4940
4941           if (gtk_tree_view_column_get_sort_indicator (column))
4942             flags |= GTK_CELL_RENDERER_SORTED;
4943           else
4944             flags &= ~GTK_CELL_RENDERER_SORTED;
4945
4946           if (cursor == node)
4947             flags |= GTK_CELL_RENDERER_FOCUSED;
4948           else
4949             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4950
4951           background_area.x = cell_offset;
4952           background_area.width = width;
4953
4954           cell_area = background_area;
4955           cell_area.y += vertical_separator / 2;
4956           cell_area.x += horizontal_separator / 2;
4957           cell_area.height -= vertical_separator;
4958           cell_area.width -= horizontal_separator;
4959
4960           if (draw_vgrid_lines)
4961             {
4962               if (list == first_column)
4963                 {
4964                   cell_area.width -= grid_line_width / 2;
4965                 }
4966               else if (list == last_column)
4967                 {
4968                   cell_area.x += grid_line_width / 2;
4969                   cell_area.width -= grid_line_width / 2;
4970                 }
4971               else
4972                 {
4973                   cell_area.x += grid_line_width / 2;
4974                   cell_area.width -= grid_line_width;
4975                 }
4976             }
4977
4978           if (draw_hgrid_lines)
4979             {
4980               cell_area.y += grid_line_width / 2;
4981               cell_area.height -= grid_line_width;
4982             }
4983
4984           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4985             {
4986               cell_offset += gtk_tree_view_column_get_width (column);
4987               continue;
4988             }
4989
4990           gtk_tree_view_column_cell_set_cell_data (column,
4991                                                    tree_view->priv->model,
4992                                                    &iter,
4993                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4994                                                    node->children?TRUE:FALSE);
4995
4996           /* Select the detail for drawing the cell.  relevant
4997            * factors are parity, sortedness, and whether to
4998            * display rules.
4999            */
5000           if (allow_rules && tree_view->priv->has_rules)
5001             {
5002               if ((flags & GTK_CELL_RENDERER_SORTED) &&
5003                   n_visible_columns >= 3)
5004                 {
5005                   if (parity)
5006                     detail = "cell_odd_ruled_sorted";
5007                   else
5008                     detail = "cell_even_ruled_sorted";
5009                 }
5010               else
5011                 {
5012                   if (parity)
5013                     detail = "cell_odd_ruled";
5014                   else
5015                     detail = "cell_even_ruled";
5016                 }
5017             }
5018           else
5019             {
5020               if ((flags & GTK_CELL_RENDERER_SORTED) &&
5021                   n_visible_columns >= 3)
5022                 {
5023                   if (parity)
5024                     detail = "cell_odd_sorted";
5025                   else
5026                     detail = "cell_even_sorted";
5027                 }
5028               else
5029                 {
5030                   if (parity)
5031                     detail = "cell_odd";
5032                   else
5033                     detail = "cell_even";
5034                 }
5035             }
5036
5037           g_assert (detail);
5038
5039           if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
5040             state = GTK_STATE_INSENSITIVE;          
5041           else if (flags & GTK_CELL_RENDERER_SELECTED)
5042             state = GTK_STATE_SELECTED;
5043           else
5044             state = GTK_STATE_NORMAL;
5045
5046           if (node == cursor && has_can_focus_cell
5047               && ((column == tree_view->priv->focus_column
5048                    && tree_view->priv->draw_keyfocus &&
5049                    gtk_widget_has_focus (widget))
5050                   || (column == tree_view->priv->edited_column)))
5051             draw_focus = TRUE;
5052           else
5053             draw_focus = FALSE;
5054
5055           /* Draw background */
5056           is_first = (rtl ? !list->next : !list->prev);
5057           is_last = (rtl ? !list->prev : !list->next);
5058
5059           /* (I don't like the snprintfs either, but couldn't find a
5060            * less messy way).
5061            */
5062           if (is_first && is_last)
5063             g_snprintf (new_detail, 127, "%s", detail);
5064           else if (is_first)
5065             g_snprintf (new_detail, 127, "%s_start", detail);
5066           else if (is_last)
5067             g_snprintf (new_detail, 127, "%s_end", detail);
5068           else
5069             g_snprintf (new_detail, 127, "%s_middle", detail);
5070
5071           gtk_paint_flat_box (style,
5072                               cr,
5073                               state,
5074                               GTK_SHADOW_NONE,
5075                               widget,
5076                               new_detail,
5077                               background_area.x,
5078                               background_area.y,
5079                               background_area.width,
5080                               background_area.height);
5081
5082           if (gtk_tree_view_is_expander_column (tree_view, column))
5083             {
5084               if (!rtl)
5085                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
5086               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
5087
5088               if (gtk_tree_view_draw_expanders (tree_view))
5089                 {
5090                   if (!rtl)
5091                     cell_area.x += depth * tree_view->priv->expander_size;
5092                   cell_area.width -= depth * tree_view->priv->expander_size;
5093                 }
5094
5095               /* If we have an expander column, the highlight underline
5096                * starts with that column, so that it indicates which
5097                * level of the tree we're dropping at.
5098                */
5099               highlight_x = cell_area.x;
5100               expander_cell_width = cell_area.width;
5101
5102               if (is_separator)
5103                 gtk_paint_hline (style,
5104                                  cr,
5105                                  state,
5106                                  widget,
5107                                  NULL,
5108                                  cell_area.x,
5109                                  cell_area.x + cell_area.width,
5110                                  cell_area.y + cell_area.height / 2);
5111               else
5112                 _gtk_tree_view_column_cell_render (column,
5113                                                    cr,
5114                                                    &background_area,
5115                                                    &cell_area,
5116                                                    flags,
5117                                                    draw_focus);
5118               if (gtk_tree_view_draw_expanders (tree_view)
5119                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5120                 {
5121                   if (!got_pointer)
5122                     {
5123                       gdk_window_get_pointer (tree_view->priv->bin_window, 
5124                                               &pointer_x, &pointer_y, NULL);
5125                       got_pointer = TRUE;
5126                     }
5127
5128                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5129                                             cr,
5130                                             tree,
5131                                             node,
5132                                             pointer_x, pointer_y);
5133                 }
5134             }
5135           else
5136             {
5137               if (is_separator)
5138                 gtk_paint_hline (style,
5139                                  cr,
5140                                  state,
5141                                  widget,
5142                                  NULL,
5143                                  cell_area.x,
5144                                  cell_area.x + cell_area.width,
5145                                  cell_area.y + cell_area.height / 2);
5146               else
5147                 _gtk_tree_view_column_cell_render (column,
5148                                                    cr,
5149                                                    &background_area,
5150                                                    &cell_area,
5151                                                    flags,
5152                                                    draw_focus);
5153             }
5154
5155           if (draw_hgrid_lines)
5156             {
5157               if (background_area.y > 0)
5158                 gtk_tree_view_draw_line (tree_view, cr,
5159                                          GTK_TREE_VIEW_GRID_LINE,
5160                                          background_area.x, background_area.y,
5161                                          background_area.x + background_area.width,
5162                                          background_area.y);
5163
5164               if (y_offset + max_height >= clip.height)
5165                 gtk_tree_view_draw_line (tree_view, cr,
5166                                          GTK_TREE_VIEW_GRID_LINE,
5167                                          background_area.x, background_area.y + max_height,
5168                                          background_area.x + background_area.width,
5169                                          background_area.y + max_height);
5170             }
5171
5172           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5173               tree_view->priv->tree_lines_enabled)
5174             {
5175               gint x = background_area.x;
5176               gint mult = rtl ? -1 : 1;
5177               gint y0 = background_area.y;
5178               gint y1 = background_area.y + background_area.height/2;
5179               gint y2 = background_area.y + background_area.height;
5180
5181               if (rtl)
5182                 x += background_area.width - 1;
5183
5184               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5185                   && depth > 1)
5186                 {
5187                   gtk_tree_view_draw_line (tree_view, cr,
5188                                            GTK_TREE_VIEW_TREE_LINE,
5189                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5190                                            y1,
5191                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
5192                                            y1);
5193                 }
5194               else if (depth > 1)
5195                 {
5196                   gtk_tree_view_draw_line (tree_view, cr,
5197                                            GTK_TREE_VIEW_TREE_LINE,
5198                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5199                                            y1,
5200                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
5201                                            y1);
5202                 }
5203
5204               if (depth > 1)
5205                 {
5206                   gint i;
5207                   GtkRBNode *tmp_node;
5208                   GtkRBTree *tmp_tree;
5209
5210                   if (!_gtk_rbtree_next (tree, node))
5211                     gtk_tree_view_draw_line (tree_view, cr,
5212                                              GTK_TREE_VIEW_TREE_LINE,
5213                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5214                                              y0,
5215                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5216                                              y1);
5217                   else
5218                     gtk_tree_view_draw_line (tree_view, cr,
5219                                              GTK_TREE_VIEW_TREE_LINE,
5220                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5221                                              y0,
5222                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5223                                              y2);
5224
5225                   tmp_node = tree->parent_node;
5226                   tmp_tree = tree->parent_tree;
5227
5228                   for (i = depth - 2; i > 0; i--)
5229                     {
5230                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5231                         gtk_tree_view_draw_line (tree_view, cr,
5232                                                  GTK_TREE_VIEW_TREE_LINE,
5233                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5234                                                  y0,
5235                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5236                                                  y2);
5237
5238                       tmp_node = tmp_tree->parent_node;
5239                       tmp_tree = tmp_tree->parent_tree;
5240                     }
5241                 }
5242             }
5243
5244           cell_offset += gtk_tree_view_column_get_width (column);
5245         }
5246
5247       if (node == drag_highlight)
5248         {
5249           /* Draw indicator for the drop
5250            */
5251           gint highlight_y = -1;
5252           GtkRBTree *tree = NULL;
5253           GtkRBNode *node = NULL;
5254
5255           switch (tree_view->priv->drag_dest_pos)
5256             {
5257             case GTK_TREE_VIEW_DROP_BEFORE:
5258               highlight_y = background_area.y - 1;
5259               if (highlight_y < 0)
5260                       highlight_y = 0;
5261               break;
5262
5263             case GTK_TREE_VIEW_DROP_AFTER:
5264               highlight_y = background_area.y + background_area.height - 1;
5265               break;
5266
5267             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5268             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5269               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5270
5271               if (tree == NULL)
5272                 break;
5273
5274               gtk_paint_focus (style,
5275                                cr,
5276                                gtk_widget_get_state (widget),
5277                                widget,
5278                                (is_first
5279                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
5280                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
5281                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node)
5282                                    - focus_line_width / 2,
5283                                 gdk_window_get_width (tree_view->priv->bin_window),
5284                                 gtk_tree_view_get_row_height (tree_view, node)
5285                                    - focus_line_width + 1);
5286               break;
5287             }
5288
5289           if (highlight_y >= 0)
5290             {
5291               gtk_tree_view_draw_line (tree_view, cr,
5292                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5293                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5294                                        highlight_y,
5295                                        rtl ? 0 : bin_window_width,
5296                                        highlight_y);
5297             }
5298         }
5299
5300       /* draw the big row-spanning focus rectangle, if needed */
5301       if (!has_can_focus_cell && node == cursor &&
5302           tree_view->priv->draw_keyfocus &&
5303           gtk_widget_has_focus (widget))
5304         {
5305           gint tmp_y, tmp_height;
5306           GtkStateType focus_rect_state;
5307
5308           focus_rect_state =
5309             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
5310             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
5311              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
5312               GTK_STATE_NORMAL));
5313
5314           if (draw_hgrid_lines)
5315             {
5316               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5317               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5318             }
5319           else
5320             {
5321               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5322               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5323             }
5324
5325           gtk_paint_focus (style,
5326                            cr,
5327                            focus_rect_state,
5328                            widget,
5329                            (is_first
5330                             ? (is_last ? "treeview" : "treeview-left" )
5331                             : (is_last ? "treeview-right" : "treeview-middle" )),
5332                            0, tmp_y,
5333                            gdk_window_get_width (tree_view->priv->bin_window),
5334                            tmp_height);
5335         }
5336
5337       y_offset += max_height;
5338       if (node->children)
5339         {
5340           GtkTreeIter parent = iter;
5341           gboolean has_child;
5342
5343           tree = node->children;
5344           node = tree->root;
5345
5346           g_assert (node != tree->nil);
5347
5348           while (node->left != tree->nil)
5349             node = node->left;
5350           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5351                                                     &iter,
5352                                                     &parent);
5353           depth++;
5354
5355           /* Sanity Check! */
5356           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5357         }
5358       else
5359         {
5360           gboolean done = FALSE;
5361
5362           do
5363             {
5364               node = _gtk_rbtree_next (tree, node);
5365               if (node != NULL)
5366                 {
5367                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5368                   done = TRUE;
5369
5370                   /* Sanity Check! */
5371                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5372                 }
5373               else
5374                 {
5375                   GtkTreeIter parent_iter = iter;
5376                   gboolean has_parent;
5377
5378                   node = tree->parent_node;
5379                   tree = tree->parent_tree;
5380                   if (tree == NULL)
5381                     /* we should go to done to free some memory */
5382                     goto done;
5383                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5384                                                            &iter,
5385                                                            &parent_iter);
5386                   depth--;
5387
5388                   /* Sanity check */
5389                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5390                 }
5391             }
5392           while (!done);
5393         }
5394     }
5395   while (y_offset < clip.height);
5396
5397 done:
5398   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5399
5400   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5401     gtk_tree_view_paint_rubber_band (tree_view, cr);
5402
5403   if (cursor_path)
5404     gtk_tree_path_free (cursor_path);
5405
5406   if (drag_dest_path)
5407     gtk_tree_path_free (drag_dest_path);
5408
5409   return FALSE;
5410 }
5411
5412 static gboolean
5413 gtk_tree_view_draw (GtkWidget *widget,
5414                     cairo_t   *cr)
5415 {
5416   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5417   GtkWidget   *button;
5418
5419   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5420     {
5421       GList *tmp_list;
5422
5423       cairo_save (cr);
5424
5425       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5426
5427       gtk_tree_view_bin_draw (widget, cr);
5428
5429       cairo_restore (cr);
5430
5431       /* We can't just chain up to Container::draw as it will try to send the
5432        * event to the headers, so we handle propagating it to our children
5433        * (eg. widgets being edited) ourselves.
5434        */
5435       tmp_list = tree_view->priv->children;
5436       while (tmp_list)
5437         {
5438           GtkTreeViewChild *child = tmp_list->data;
5439           tmp_list = tmp_list->next;
5440
5441           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5442         }
5443     }
5444
5445   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5446     {
5447       GList *list;
5448       
5449       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5450         {
5451           GtkTreeViewColumn *column = list->data;
5452
5453           if (column == tree_view->priv->drag_column)
5454             continue;
5455
5456           if (gtk_tree_view_column_get_visible (column))
5457             {
5458               button = gtk_tree_view_column_get_button (column);
5459               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5460                                             button, cr);
5461             }
5462         }
5463     }
5464   
5465   if (tree_view->priv->drag_window &&
5466       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5467     {
5468       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5469       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5470                                     button, cr);
5471     }
5472
5473   return TRUE;
5474 }
5475
5476 enum
5477 {
5478   DROP_HOME,
5479   DROP_RIGHT,
5480   DROP_LEFT,
5481   DROP_END
5482 };
5483
5484 /* returns 0x1 when no column has been found -- yes it's hackish */
5485 static GtkTreeViewColumn *
5486 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5487                                GtkTreeViewColumn *column,
5488                                gint               drop_position)
5489 {
5490   GtkTreeViewColumn *left_column = NULL;
5491   GtkTreeViewColumn *cur_column = NULL;
5492   GList *tmp_list;
5493
5494   if (!gtk_tree_view_column_get_reorderable (column))
5495     return (GtkTreeViewColumn *)0x1;
5496
5497   switch (drop_position)
5498     {
5499       case DROP_HOME:
5500         /* find first column where we can drop */
5501         tmp_list = tree_view->priv->columns;
5502         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5503           return (GtkTreeViewColumn *)0x1;
5504
5505         while (tmp_list)
5506           {
5507             g_assert (tmp_list);
5508
5509             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5510             tmp_list = tmp_list->next;
5511
5512             if (left_column &&
5513                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5514               continue;
5515
5516             if (!tree_view->priv->column_drop_func)
5517               return left_column;
5518
5519             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5520               {
5521                 left_column = cur_column;
5522                 continue;
5523               }
5524
5525             return left_column;
5526           }
5527
5528         if (!tree_view->priv->column_drop_func)
5529           return left_column;
5530
5531         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5532           return left_column;
5533         else
5534           return (GtkTreeViewColumn *)0x1;
5535         break;
5536
5537       case DROP_RIGHT:
5538         /* find first column after column where we can drop */
5539         tmp_list = tree_view->priv->columns;
5540
5541         for (; tmp_list; tmp_list = tmp_list->next)
5542           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5543             break;
5544
5545         if (!tmp_list || !tmp_list->next)
5546           return (GtkTreeViewColumn *)0x1;
5547
5548         tmp_list = tmp_list->next;
5549         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5550         tmp_list = tmp_list->next;
5551
5552         while (tmp_list)
5553           {
5554             g_assert (tmp_list);
5555
5556             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5557             tmp_list = tmp_list->next;
5558
5559             if (left_column &&
5560                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5561               {
5562                 left_column = cur_column;
5563                 if (tmp_list)
5564                   tmp_list = tmp_list->next;
5565                 continue;
5566               }
5567
5568             if (!tree_view->priv->column_drop_func)
5569               return left_column;
5570
5571             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5572               {
5573                 left_column = cur_column;
5574                 continue;
5575               }
5576
5577             return left_column;
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, NULL, tree_view->priv->column_drop_func_data))
5584           return left_column;
5585         else
5586           return (GtkTreeViewColumn *)0x1;
5587         break;
5588
5589       case DROP_LEFT:
5590         /* find first column before column where we can drop */
5591         tmp_list = tree_view->priv->columns;
5592
5593         for (; tmp_list; tmp_list = tmp_list->next)
5594           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5595             break;
5596
5597         if (!tmp_list || !tmp_list->prev)
5598           return (GtkTreeViewColumn *)0x1;
5599
5600         tmp_list = tmp_list->prev;
5601         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5602         tmp_list = tmp_list->prev;
5603
5604         while (tmp_list)
5605           {
5606             g_assert (tmp_list);
5607
5608             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5609
5610             if (left_column &&
5611                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5612               {
5613                 /*if (!tmp_list->prev)
5614                   return (GtkTreeViewColumn *)0x1;
5615                   */
5616 /*
5617                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5618                 tmp_list = tmp_list->prev->prev;
5619                 continue;*/
5620
5621                 cur_column = left_column;
5622                 if (tmp_list)
5623                   tmp_list = tmp_list->prev;
5624                 continue;
5625               }
5626
5627             if (!tree_view->priv->column_drop_func)
5628               return left_column;
5629
5630             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5631               return left_column;
5632
5633             cur_column = left_column;
5634             tmp_list = tmp_list->prev;
5635           }
5636
5637         if (!tree_view->priv->column_drop_func)
5638           return NULL;
5639
5640         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5641           return NULL;
5642         else
5643           return (GtkTreeViewColumn *)0x1;
5644         break;
5645
5646       case DROP_END:
5647         /* same as DROP_HOME case, but doing it backwards */
5648         tmp_list = g_list_last (tree_view->priv->columns);
5649         cur_column = NULL;
5650
5651         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5652           return (GtkTreeViewColumn *)0x1;
5653
5654         while (tmp_list)
5655           {
5656             g_assert (tmp_list);
5657
5658             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5659
5660             if (left_column &&
5661                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5662               {
5663                 cur_column = left_column;
5664                 tmp_list = tmp_list->prev;
5665               }
5666
5667             if (!tree_view->priv->column_drop_func)
5668               return left_column;
5669
5670             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5671               return left_column;
5672
5673             cur_column = left_column;
5674             tmp_list = tmp_list->prev;
5675           }
5676
5677         if (!tree_view->priv->column_drop_func)
5678           return NULL;
5679
5680         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5681           return NULL;
5682         else
5683           return (GtkTreeViewColumn *)0x1;
5684         break;
5685     }
5686
5687   return (GtkTreeViewColumn *)0x1;
5688 }
5689
5690 static gboolean
5691 gtk_tree_view_key_press (GtkWidget   *widget,
5692                          GdkEventKey *event)
5693 {
5694   GtkTreeView *tree_view = (GtkTreeView *) widget;
5695   GtkWidget   *button;
5696
5697   if (tree_view->priv->rubber_band_status)
5698     {
5699       if (event->keyval == GDK_KEY_Escape)
5700         gtk_tree_view_stop_rubber_band (tree_view);
5701
5702       return TRUE;
5703     }
5704
5705   if (tree_view->priv->in_column_drag)
5706     {
5707       if (event->keyval == GDK_KEY_Escape)
5708         {
5709           tree_view->priv->cur_reorder = NULL;
5710           gtk_tree_view_button_release_drag_column (widget, NULL);
5711         }
5712       return TRUE;
5713     }
5714
5715   if (tree_view->priv->headers_visible)
5716     {
5717       GList *focus_column;
5718       gboolean rtl;
5719
5720       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5721
5722       for (focus_column = tree_view->priv->columns;
5723            focus_column;
5724            focus_column = focus_column->next)
5725         {
5726           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5727           
5728           button = gtk_tree_view_column_get_button (column);
5729           if (gtk_widget_has_focus (button))
5730             break;
5731         }
5732
5733       if (focus_column &&
5734           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5735           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5736            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5737         {
5738           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5739           gint max_width, min_width;
5740
5741           if (!gtk_tree_view_column_get_resizable (column))
5742             {
5743               gtk_widget_error_bell (widget);
5744               return TRUE;
5745             }
5746
5747           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5748               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5749             {
5750               GtkRequisition button_req;
5751               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5752               gint new_width;
5753
5754               button = gtk_tree_view_column_get_button (column);
5755
5756               gtk_widget_get_preferred_size (button, &button_req, NULL);
5757
5758               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5759               new_width -= 2;
5760               if (new_width < 0)
5761                 new_width = 0;
5762
5763               _gtk_tree_view_column_set_resized_width (column, new_width);
5764
5765               min_width = gtk_tree_view_column_get_min_width (column);
5766               if (min_width == -1)
5767                 new_width = MAX (button_req.width, new_width);
5768               else
5769                 {
5770                   new_width = MAX (min_width, new_width);
5771                 }
5772
5773               max_width = gtk_tree_view_column_get_max_width (column);
5774               if (max_width != -1)
5775                 new_width = MIN (new_width, max_width);
5776
5777               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5778
5779               if (new_width != old_width)
5780                 {
5781                   _gtk_tree_view_column_set_resized_width (column, new_width);
5782                   gtk_widget_queue_resize (widget);
5783                 }
5784               else
5785                 gtk_widget_error_bell (widget);
5786             }
5787           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5788                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5789             {
5790               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5791               gint new_width;
5792
5793               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5794               new_width += 2;
5795
5796               max_width = gtk_tree_view_column_get_max_width (column);
5797               if (max_width != -1)
5798                 new_width = MIN (new_width, max_width);
5799
5800               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5801
5802               if (new_width != old_width)
5803                 {
5804                   _gtk_tree_view_column_set_resized_width (column, new_width);
5805                   gtk_widget_queue_resize (widget);
5806                 }
5807               else
5808                 gtk_widget_error_bell (widget);
5809             }
5810
5811           return TRUE;
5812         }
5813
5814       if (focus_column &&
5815           (event->state & GDK_MOD1_MASK) &&
5816           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5817            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5818            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5819            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5820         {
5821           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5822
5823           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5824               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5825             {
5826               GtkTreeViewColumn *col;
5827               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5828               if (col != (GtkTreeViewColumn *)0x1)
5829                 gtk_tree_view_move_column_after (tree_view, column, col);
5830               else
5831                 gtk_widget_error_bell (widget);
5832             }
5833           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5834                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5835             {
5836               GtkTreeViewColumn *col;
5837               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5838               if (col != (GtkTreeViewColumn *)0x1)
5839                 gtk_tree_view_move_column_after (tree_view, column, col);
5840               else
5841                 gtk_widget_error_bell (widget);
5842             }
5843           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5844             {
5845               GtkTreeViewColumn *col;
5846               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5847               if (col != (GtkTreeViewColumn *)0x1)
5848                 gtk_tree_view_move_column_after (tree_view, column, col);
5849               else
5850                 gtk_widget_error_bell (widget);
5851             }
5852           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5853             {
5854               GtkTreeViewColumn *col;
5855               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5856               if (col != (GtkTreeViewColumn *)0x1)
5857                 gtk_tree_view_move_column_after (tree_view, column, col);
5858               else
5859                 gtk_widget_error_bell (widget);
5860             }
5861
5862           return TRUE;
5863         }
5864     }
5865
5866   /* Chain up to the parent class.  It handles the keybindings. */
5867   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5868     return TRUE;
5869
5870   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5871     {
5872       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5873       return FALSE;
5874     }
5875
5876   /* We pass the event to the search_entry.  If its text changes, then we start
5877    * the typeahead find capabilities. */
5878   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5879       && tree_view->priv->enable_search
5880       && !tree_view->priv->search_custom_entry_set)
5881     {
5882       GdkEvent *new_event;
5883       char *old_text;
5884       const char *new_text;
5885       gboolean retval;
5886       GdkScreen *screen;
5887       gboolean text_modified;
5888       gulong popup_menu_id;
5889
5890       gtk_tree_view_ensure_interactive_directory (tree_view);
5891
5892       /* Make a copy of the current text */
5893       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5894       new_event = gdk_event_copy ((GdkEvent *) event);
5895       g_object_unref (((GdkEventKey *) new_event)->window);
5896       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5897       gtk_widget_realize (tree_view->priv->search_window);
5898
5899       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5900                                         "popup-menu", G_CALLBACK (gtk_true),
5901                                         NULL);
5902
5903       /* Move the entry off screen */
5904       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5905       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5906                        gdk_screen_get_width (screen) + 1,
5907                        gdk_screen_get_height (screen) + 1);
5908       gtk_widget_show (tree_view->priv->search_window);
5909
5910       /* Send the event to the window.  If the preedit_changed signal is emitted
5911        * during this event, we will set priv->imcontext_changed  */
5912       tree_view->priv->imcontext_changed = FALSE;
5913       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5914       gdk_event_free (new_event);
5915       gtk_widget_hide (tree_view->priv->search_window);
5916
5917       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5918                                    popup_menu_id);
5919
5920       /* We check to make sure that the entry tried to handle the text, and that
5921        * the text has changed.
5922        */
5923       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5924       text_modified = strcmp (old_text, new_text) != 0;
5925       g_free (old_text);
5926       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5927           (retval && text_modified))               /* ...or the text was modified */
5928         {
5929           if (gtk_tree_view_real_start_interactive_search (tree_view,
5930                                                            gdk_event_get_device ((GdkEvent *) event),
5931                                                            FALSE))
5932             {
5933               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5934               return TRUE;
5935             }
5936           else
5937             {
5938               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5939               return FALSE;
5940             }
5941         }
5942     }
5943
5944   return FALSE;
5945 }
5946
5947 static gboolean
5948 gtk_tree_view_key_release (GtkWidget   *widget,
5949                            GdkEventKey *event)
5950 {
5951   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5952
5953   if (tree_view->priv->rubber_band_status)
5954     return TRUE;
5955
5956   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5957 }
5958
5959 /* FIXME Is this function necessary? Can I get an enter_notify event
5960  * w/o either an expose event or a mouse motion event?
5961  */
5962 static gboolean
5963 gtk_tree_view_enter_notify (GtkWidget        *widget,
5964                             GdkEventCrossing *event)
5965 {
5966   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5967   GtkRBTree *tree;
5968   GtkRBNode *node;
5969   gint new_y;
5970
5971   /* Sanity check it */
5972   if (event->window != tree_view->priv->bin_window)
5973     return FALSE;
5974
5975   if (tree_view->priv->tree == NULL)
5976     return FALSE;
5977
5978   if (event->mode == GDK_CROSSING_GRAB ||
5979       event->mode == GDK_CROSSING_GTK_GRAB ||
5980       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5981       event->mode == GDK_CROSSING_STATE_CHANGED)
5982     return TRUE;
5983
5984   /* find the node internally */
5985   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5986   if (new_y < 0)
5987     new_y = 0;
5988   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5989
5990   tree_view->priv->event_last_x = event->x;
5991   tree_view->priv->event_last_y = event->y;
5992
5993   if ((tree_view->priv->button_pressed_node == NULL) ||
5994       (tree_view->priv->button_pressed_node == node))
5995     prelight_or_select (tree_view, tree, node, event->x, event->y);
5996
5997   return TRUE;
5998 }
5999
6000 static gboolean
6001 gtk_tree_view_leave_notify (GtkWidget        *widget,
6002                             GdkEventCrossing *event)
6003 {
6004   GtkTreeView *tree_view;
6005
6006   if (event->mode == GDK_CROSSING_GRAB)
6007     return TRUE;
6008
6009   tree_view = GTK_TREE_VIEW (widget);
6010
6011   if (tree_view->priv->prelight_node)
6012     _gtk_tree_view_queue_draw_node (tree_view,
6013                                    tree_view->priv->prelight_tree,
6014                                    tree_view->priv->prelight_node,
6015                                    NULL);
6016
6017   tree_view->priv->event_last_x = -10000;
6018   tree_view->priv->event_last_y = -10000;
6019
6020   prelight_or_select (tree_view,
6021                       NULL, NULL,
6022                       -1000, -1000); /* coords not possibly over an arrow */
6023
6024   return TRUE;
6025 }
6026
6027
6028 static gint
6029 gtk_tree_view_focus_out (GtkWidget     *widget,
6030                          GdkEventFocus *event)
6031 {
6032   GtkTreeView *tree_view;
6033
6034   tree_view = GTK_TREE_VIEW (widget);
6035
6036   gtk_widget_queue_draw (widget);
6037
6038   /* destroy interactive search dialog */
6039   if (tree_view->priv->search_window)
6040     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
6041                                       gdk_event_get_device ((GdkEvent *) event));
6042
6043   return FALSE;
6044 }
6045
6046
6047 /* Incremental Reflow
6048  */
6049
6050 static void
6051 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
6052                                  GtkRBTree   *tree,
6053                                  GtkRBNode   *node)
6054 {
6055   GtkAllocation allocation;
6056   gint y;
6057
6058   y = _gtk_rbtree_node_find_offset (tree, node)
6059     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
6060     + gtk_tree_view_get_effective_header_height (tree_view);
6061
6062   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6063   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
6064                               0, y,
6065                               allocation.width,
6066                               GTK_RBNODE_GET_HEIGHT (node));
6067 }
6068
6069 static gboolean
6070 node_is_visible (GtkTreeView *tree_view,
6071                  GtkRBTree   *tree,
6072                  GtkRBNode   *node)
6073 {
6074   int y;
6075   int height;
6076
6077   y = _gtk_rbtree_node_find_offset (tree, node);
6078   height = gtk_tree_view_get_row_height (tree_view, node);
6079
6080   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6081       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6082                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6083     return TRUE;
6084
6085   return FALSE;
6086 }
6087
6088 /* Returns TRUE if it updated the size
6089  */
6090 static gboolean
6091 validate_row (GtkTreeView *tree_view,
6092               GtkRBTree   *tree,
6093               GtkRBNode   *node,
6094               GtkTreeIter *iter,
6095               GtkTreePath *path)
6096 {
6097   GtkTreeViewColumn *column;
6098   GList *list, *first_column, *last_column;
6099   gint height = 0;
6100   gint horizontal_separator;
6101   gint vertical_separator;
6102   gint depth = gtk_tree_path_get_depth (path);
6103   gboolean retval = FALSE;
6104   gboolean is_separator = FALSE;
6105   gboolean draw_vgrid_lines, draw_hgrid_lines;
6106   gint focus_pad;
6107   gint grid_line_width;
6108   gboolean wide_separators;
6109   gint separator_height;
6110
6111   /* double check the row needs validating */
6112   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6113       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6114     return FALSE;
6115
6116   is_separator = row_is_separator (tree_view, iter, NULL);
6117
6118   gtk_widget_style_get (GTK_WIDGET (tree_view),
6119                         "focus-padding", &focus_pad,
6120                         "horizontal-separator", &horizontal_separator,
6121                         "vertical-separator", &vertical_separator,
6122                         "grid-line-width", &grid_line_width,
6123                         "wide-separators",  &wide_separators,
6124                         "separator-height", &separator_height,
6125                         NULL);
6126   
6127   draw_vgrid_lines =
6128     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6129     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6130   draw_hgrid_lines =
6131     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6132     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6133
6134   for (last_column = g_list_last (tree_view->priv->columns);
6135        last_column &&
6136        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6137        last_column = last_column->prev)
6138     ;
6139
6140   for (first_column = g_list_first (tree_view->priv->columns);
6141        first_column &&
6142        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6143        first_column = first_column->next)
6144     ;
6145
6146   for (list = tree_view->priv->columns; list; list = list->next)
6147     {
6148       gint padding = 0;
6149       gint original_width;
6150       gint new_width;
6151       gint row_height;
6152
6153       column = list->data;
6154
6155       if (!gtk_tree_view_column_get_visible (column))
6156         continue;
6157
6158       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6159           !_gtk_tree_view_column_cell_get_dirty (column))
6160         continue;
6161
6162       original_width = _gtk_tree_view_column_get_requested_width (column);
6163
6164       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6165                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6166                                                node->children?TRUE:FALSE);
6167       gtk_tree_view_column_cell_get_size (column,
6168                                           NULL, NULL, NULL,
6169                                           NULL, &row_height);
6170
6171       if (!is_separator)
6172         {
6173           row_height += vertical_separator;
6174           height = MAX (height, row_height);
6175           height = MAX (height, tree_view->priv->expander_size);
6176         }
6177       else
6178         {
6179           if (wide_separators)
6180             height = separator_height + 2 * focus_pad;
6181           else
6182             height = 2 + 2 * focus_pad;
6183         }
6184
6185       if (gtk_tree_view_is_expander_column (tree_view, column))
6186         {
6187           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6188
6189           if (gtk_tree_view_draw_expanders (tree_view))
6190             padding += depth * tree_view->priv->expander_size;
6191         }
6192       else
6193         padding += horizontal_separator;
6194
6195       if (draw_vgrid_lines)
6196         {
6197           if (list->data == first_column || list->data == last_column)
6198             padding += grid_line_width / 2.0;
6199           else
6200             padding += grid_line_width;
6201         }
6202
6203       /* Update the padding for the column */
6204       _gtk_tree_view_column_push_padding (column, padding);
6205       new_width = _gtk_tree_view_column_get_requested_width (column);
6206
6207       if (new_width > original_width)
6208         retval = TRUE;
6209     }
6210
6211   if (draw_hgrid_lines)
6212     height += grid_line_width;
6213
6214   if (height != GTK_RBNODE_GET_HEIGHT (node))
6215     {
6216       retval = TRUE;
6217       _gtk_rbtree_node_set_height (tree, node, height);
6218     }
6219   _gtk_rbtree_node_mark_valid (tree, node);
6220   tree_view->priv->post_validation_flag = TRUE;
6221
6222   return retval;
6223 }
6224
6225
6226 static void
6227 validate_visible_area (GtkTreeView *tree_view)
6228 {
6229   GtkAllocation allocation;
6230   GtkTreePath *path = NULL;
6231   GtkTreePath *above_path = NULL;
6232   GtkTreeIter iter;
6233   GtkRBTree *tree = NULL;
6234   GtkRBNode *node = NULL;
6235   gboolean need_redraw = FALSE;
6236   gboolean size_changed = FALSE;
6237   gint total_height;
6238   gint area_above = 0;
6239   gint area_below = 0;
6240
6241   if (tree_view->priv->tree == NULL)
6242     return;
6243
6244   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6245       tree_view->priv->scroll_to_path == NULL)
6246     return;
6247
6248   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6249   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6250
6251   if (total_height == 0)
6252     return;
6253
6254   /* First, we check to see if we need to scroll anywhere
6255    */
6256   if (tree_view->priv->scroll_to_path)
6257     {
6258       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6259       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6260         {
6261           /* we are going to scroll, and will update dy */
6262           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6263           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6264               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6265             {
6266               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6267               if (validate_row (tree_view, tree, node, &iter, path))
6268                 size_changed = TRUE;
6269             }
6270
6271           if (tree_view->priv->scroll_to_use_align)
6272             {
6273               gint height = gtk_tree_view_get_row_height (tree_view, node);
6274               area_above = (total_height - height) *
6275                 tree_view->priv->scroll_to_row_align;
6276               area_below = total_height - area_above - height;
6277               area_above = MAX (area_above, 0);
6278               area_below = MAX (area_below, 0);
6279             }
6280           else
6281             {
6282               /* two cases:
6283                * 1) row not visible
6284                * 2) row visible
6285                */
6286               gint dy;
6287               gint height = gtk_tree_view_get_row_height (tree_view, node);
6288
6289               dy = _gtk_rbtree_node_find_offset (tree, node);
6290
6291               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6292                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6293                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6294                 {
6295                   /* row visible: keep the row at the same position */
6296                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6297                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6298                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6299                                - dy - height;
6300                 }
6301               else
6302                 {
6303                   /* row not visible */
6304                   if (dy >= 0
6305                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6306                     {
6307                       /* row at the beginning -- fixed */
6308                       area_above = dy;
6309                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6310                                    - area_above - height;
6311                     }
6312                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6313                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6314                     {
6315                       /* row at the end -- fixed */
6316                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6317                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6318                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6319                                    area_above - height;
6320
6321                       if (area_below < 0)
6322                         {
6323                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6324                           area_below = 0;
6325                         }
6326                     }
6327                   else
6328                     {
6329                       /* row somewhere in the middle, bring it to the top
6330                        * of the view
6331                        */
6332                       area_above = 0;
6333                       area_below = total_height - height;
6334                     }
6335                 }
6336             }
6337         }
6338       else
6339         /* the scroll to isn't valid; ignore it.
6340          */
6341         {
6342           if (tree_view->priv->scroll_to_path && !path)
6343             {
6344               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6345               tree_view->priv->scroll_to_path = NULL;
6346             }
6347           if (path)
6348             gtk_tree_path_free (path);
6349           path = NULL;
6350         }      
6351     }
6352
6353   /* We didn't have a scroll_to set, so we just handle things normally
6354    */
6355   if (path == NULL)
6356     {
6357       gint offset;
6358
6359       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6360                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6361                                         &tree, &node);
6362       if (node == NULL)
6363         {
6364           /* In this case, nothing has been validated */
6365           path = gtk_tree_path_new_first ();
6366           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6367         }
6368       else
6369         {
6370           path = _gtk_tree_view_find_path (tree_view, tree, node);
6371           total_height += offset;
6372         }
6373
6374       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6375
6376       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6377           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6378         {
6379           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6380           if (validate_row (tree_view, tree, node, &iter, path))
6381             size_changed = TRUE;
6382         }
6383       area_above = 0;
6384       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6385     }
6386
6387   above_path = gtk_tree_path_copy (path);
6388
6389   /* if we do not validate any row above the new top_row, we will make sure
6390    * that the row immediately above top_row has been validated. (if we do not
6391    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6392    * when invalidated that row's height will be zero. and this will mess up
6393    * scrolling).
6394    */
6395   if (area_above == 0)
6396     {
6397       GtkRBTree *tmptree;
6398       GtkRBNode *tmpnode;
6399
6400       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6401       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6402
6403       if (tmpnode)
6404         {
6405           GtkTreePath *tmppath;
6406           GtkTreeIter tmpiter;
6407
6408           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6409           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6410
6411           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6412               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6413             {
6414               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6415               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6416                 size_changed = TRUE;
6417             }
6418
6419           gtk_tree_path_free (tmppath);
6420         }
6421     }
6422
6423   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6424    * backwards is much slower then forward, as there is no iter_prev function.
6425    * We go forwards first in case we run out of tree.  Then we go backwards to
6426    * fill out the top.
6427    */
6428   while (node && area_below > 0)
6429     {
6430       if (node->children)
6431         {
6432           GtkTreeIter parent = iter;
6433           gboolean has_child;
6434
6435           tree = node->children;
6436           node = tree->root;
6437
6438           g_assert (node != tree->nil);
6439
6440           while (node->left != tree->nil)
6441             node = node->left;
6442           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6443                                                     &iter,
6444                                                     &parent);
6445           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6446           gtk_tree_path_down (path);
6447         }
6448       else
6449         {
6450           gboolean done = FALSE;
6451           do
6452             {
6453               node = _gtk_rbtree_next (tree, node);
6454               if (node != NULL)
6455                 {
6456                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6457                   done = TRUE;
6458                   gtk_tree_path_next (path);
6459
6460                   /* Sanity Check! */
6461                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6462                 }
6463               else
6464                 {
6465                   GtkTreeIter parent_iter = iter;
6466                   gboolean has_parent;
6467
6468                   node = tree->parent_node;
6469                   tree = tree->parent_tree;
6470                   if (tree == NULL)
6471                     break;
6472                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6473                                                            &iter,
6474                                                            &parent_iter);
6475                   gtk_tree_path_up (path);
6476
6477                   /* Sanity check */
6478                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6479                 }
6480             }
6481           while (!done);
6482         }
6483
6484       if (!node)
6485         break;
6486
6487       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6488           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6489         {
6490           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6491           if (validate_row (tree_view, tree, node, &iter, path))
6492               size_changed = TRUE;
6493         }
6494
6495       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6496     }
6497   gtk_tree_path_free (path);
6498
6499   /* If we ran out of tree, and have extra area_below left, we need to add it
6500    * to area_above */
6501   if (area_below > 0)
6502     area_above += area_below;
6503
6504   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6505
6506   /* We walk backwards */
6507   while (area_above > 0)
6508     {
6509       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6510
6511       /* Always find the new path in the tree.  We cannot just assume
6512        * a gtk_tree_path_prev() is enough here, as there might be children
6513        * in between this node and the previous sibling node.  If this
6514        * appears to be a performance hotspot in profiles, we can look into
6515        * intrigate logic for keeping path, node and iter in sync like
6516        * we do for forward walks.  (Which will be hard because of the lacking
6517        * iter_prev).
6518        */
6519
6520       if (node == NULL)
6521         break;
6522
6523       gtk_tree_path_free (above_path);
6524       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6525
6526       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6527
6528       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6529           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6530         {
6531           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6532           if (validate_row (tree_view, tree, node, &iter, above_path))
6533             size_changed = TRUE;
6534         }
6535       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6536     }
6537
6538   /* if we scrolled to a path, we need to set the dy here,
6539    * and sync the top row accordingly
6540    */
6541   if (tree_view->priv->scroll_to_path)
6542     {
6543       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6544       gtk_tree_view_top_row_to_dy (tree_view);
6545
6546       need_redraw = TRUE;
6547     }
6548   else if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6549     {
6550       /* when we are not scrolling, we should never set dy to something
6551        * else than zero. we update top_row to be in sync with dy = 0.
6552        */
6553       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6554       gtk_tree_view_dy_to_top_row (tree_view);
6555     }
6556   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6557     {
6558       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6559       gtk_tree_view_dy_to_top_row (tree_view);
6560     }
6561   else
6562     gtk_tree_view_top_row_to_dy (tree_view);
6563
6564   /* update width/height and queue a resize */
6565   if (size_changed)
6566     {
6567       GtkRequisition requisition;
6568
6569       /* We temporarily guess a size, under the assumption that it will be the
6570        * same when we get our next size_allocate.  If we don't do this, we'll be
6571        * in an inconsistent state if we call top_row_to_dy. */
6572
6573       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6574                                      &requisition, NULL);
6575       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6576                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6577       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6578                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6579       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6580     }
6581
6582   if (tree_view->priv->scroll_to_path)
6583     {
6584       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6585       tree_view->priv->scroll_to_path = NULL;
6586     }
6587
6588   if (above_path)
6589     gtk_tree_path_free (above_path);
6590
6591   if (tree_view->priv->scroll_to_column)
6592     {
6593       tree_view->priv->scroll_to_column = NULL;
6594     }
6595   if (need_redraw)
6596     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6597 }
6598
6599 static void
6600 initialize_fixed_height_mode (GtkTreeView *tree_view)
6601 {
6602   if (!tree_view->priv->tree)
6603     return;
6604
6605   if (tree_view->priv->fixed_height < 0)
6606     {
6607       GtkTreeIter iter;
6608       GtkTreePath *path;
6609
6610       GtkRBTree *tree = NULL;
6611       GtkRBNode *node = NULL;
6612
6613       tree = tree_view->priv->tree;
6614       node = tree->root;
6615
6616       path = _gtk_tree_view_find_path (tree_view, tree, node);
6617       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6618
6619       validate_row (tree_view, tree, node, &iter, path);
6620
6621       gtk_tree_path_free (path);
6622
6623       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6624     }
6625
6626    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6627                                  tree_view->priv->fixed_height, TRUE);
6628 }
6629
6630 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6631  * the left-most uninvalidated node.  We then try walking right, validating
6632  * nodes.  Once we find a valid node, we repeat the previous process of finding
6633  * the first invalid node.
6634  */
6635
6636 static gboolean
6637 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6638 {
6639   GtkRBTree *tree = NULL;
6640   GtkRBNode *node = NULL;
6641   gboolean validated_area = FALSE;
6642   gint retval = TRUE;
6643   GtkTreePath *path = NULL;
6644   GtkTreeIter iter;
6645   GTimer *timer;
6646   gint i = 0;
6647
6648   gint prev_height = -1;
6649   gboolean fixed_height = TRUE;
6650
6651   g_assert (tree_view);
6652
6653   if (tree_view->priv->tree == NULL)
6654       return FALSE;
6655
6656   if (tree_view->priv->fixed_height_mode)
6657     {
6658       if (tree_view->priv->fixed_height < 0)
6659         initialize_fixed_height_mode (tree_view);
6660
6661       return FALSE;
6662     }
6663
6664   timer = g_timer_new ();
6665   g_timer_start (timer);
6666
6667   do
6668     {
6669       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6670         {
6671           retval = FALSE;
6672           goto done;
6673         }
6674
6675       if (path != NULL)
6676         {
6677           node = _gtk_rbtree_next (tree, node);
6678           if (node != NULL)
6679             {
6680               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6681               gtk_tree_path_next (path);
6682             }
6683           else
6684             {
6685               gtk_tree_path_free (path);
6686               path = NULL;
6687             }
6688         }
6689
6690       if (path == NULL)
6691         {
6692           tree = tree_view->priv->tree;
6693           node = tree_view->priv->tree->root;
6694
6695           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6696
6697           do
6698             {
6699               if (node->left != tree->nil &&
6700                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6701                 {
6702                   node = node->left;
6703                 }
6704               else if (node->right != tree->nil &&
6705                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6706                 {
6707                   node = node->right;
6708                 }
6709               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6710                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6711                 {
6712                   break;
6713                 }
6714               else if (node->children != NULL)
6715                 {
6716                   tree = node->children;
6717                   node = tree->root;
6718                 }
6719               else
6720                 /* RBTree corruption!  All bad */
6721                 g_assert_not_reached ();
6722             }
6723           while (TRUE);
6724           path = _gtk_tree_view_find_path (tree_view, tree, node);
6725           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6726         }
6727
6728       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6729                        validated_area;
6730
6731       if (!tree_view->priv->fixed_height_check)
6732         {
6733           gint height;
6734
6735           height = gtk_tree_view_get_row_height (tree_view, node);
6736           if (prev_height < 0)
6737             prev_height = height;
6738           else if (prev_height != height)
6739             fixed_height = FALSE;
6740         }
6741
6742       i++;
6743     }
6744   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6745
6746   if (!tree_view->priv->fixed_height_check)
6747    {
6748      if (fixed_height)
6749        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6750
6751      tree_view->priv->fixed_height_check = 1;
6752    }
6753   
6754  done:
6755   if (validated_area)
6756     {
6757       GtkRequisition requisition;
6758
6759       /* We temporarily guess a size, under the assumption that it will be the
6760        * same when we get our next size_allocate.  If we don't do this, we'll be
6761        * in an inconsistent state when we call top_row_to_dy. */
6762
6763       /* FIXME: This is called from size_request, for some reason it is not infinitely
6764        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6765        * not allowed (from inside ->get_preferred_width/height() implementations, one
6766        * should call the vfuncs directly). However what is desired here is the full
6767        * size including any margins and limited by any alignment (i.e. after 
6768        * GtkWidget:adjust_size_request() is called).
6769        *
6770        * Currently bypassing this but the real solution is to not update the scroll adjustments
6771        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6772        */
6773       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition, FALSE);
6774
6775       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6776                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6777       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6778                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6779
6780       if (queue_resize)
6781         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6782     }
6783
6784   if (path) gtk_tree_path_free (path);
6785   g_timer_destroy (timer);
6786
6787   return retval;
6788 }
6789
6790 static gboolean
6791 validate_rows (GtkTreeView *tree_view)
6792 {
6793   gboolean retval;
6794   
6795   retval = do_validate_rows (tree_view, TRUE);
6796   
6797   if (! retval && tree_view->priv->validate_rows_timer)
6798     {
6799       g_source_remove (tree_view->priv->validate_rows_timer);
6800       tree_view->priv->validate_rows_timer = 0;
6801     }
6802
6803   return retval;
6804 }
6805
6806 static gboolean
6807 validate_rows_handler (GtkTreeView *tree_view)
6808 {
6809   gboolean retval;
6810
6811   retval = do_validate_rows (tree_view, TRUE);
6812   if (! retval && tree_view->priv->validate_rows_timer)
6813     {
6814       g_source_remove (tree_view->priv->validate_rows_timer);
6815       tree_view->priv->validate_rows_timer = 0;
6816     }
6817
6818   return retval;
6819 }
6820
6821 static gboolean
6822 do_presize_handler (GtkTreeView *tree_view)
6823 {
6824   if (tree_view->priv->mark_rows_col_dirty)
6825     {
6826       if (tree_view->priv->tree)
6827         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6828       tree_view->priv->mark_rows_col_dirty = FALSE;
6829     }
6830   validate_visible_area (tree_view);
6831   tree_view->priv->presize_handler_timer = 0;
6832
6833   if (tree_view->priv->fixed_height_mode)
6834     {
6835       GtkRequisition requisition;
6836
6837       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6838                                      &requisition, NULL);
6839
6840       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6841                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6842       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6843                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6844       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6845     }
6846                    
6847   return FALSE;
6848 }
6849
6850 static gboolean
6851 presize_handler_callback (gpointer data)
6852 {
6853   do_presize_handler (GTK_TREE_VIEW (data));
6854                    
6855   return FALSE;
6856 }
6857
6858 static void
6859 install_presize_handler (GtkTreeView *tree_view)
6860 {
6861   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6862     return;
6863
6864   if (! tree_view->priv->presize_handler_timer)
6865     {
6866       tree_view->priv->presize_handler_timer =
6867         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6868     }
6869   if (! tree_view->priv->validate_rows_timer)
6870     {
6871       tree_view->priv->validate_rows_timer =
6872         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6873     }
6874 }
6875
6876 static void
6877 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6878 {
6879   /* Prior to drawing, we make sure the visible area is validated. */
6880   if (tree_view->priv->presize_handler_timer)
6881     {
6882       g_source_remove (tree_view->priv->presize_handler_timer);
6883       tree_view->priv->presize_handler_timer = 0;
6884
6885       do_presize_handler (tree_view);
6886     }
6887
6888   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6889 }
6890
6891 static gboolean
6892 scroll_sync_handler (GtkTreeView *tree_view)
6893 {
6894   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6895     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6896   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6897     gtk_tree_view_top_row_to_dy (tree_view);
6898   else
6899     gtk_tree_view_dy_to_top_row (tree_view);
6900
6901   tree_view->priv->scroll_sync_timer = 0;
6902
6903   return FALSE;
6904 }
6905
6906 static void
6907 install_scroll_sync_handler (GtkTreeView *tree_view)
6908 {
6909   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6910     return;
6911
6912   if (!tree_view->priv->scroll_sync_timer)
6913     {
6914       tree_view->priv->scroll_sync_timer =
6915         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6916     }
6917 }
6918
6919 static void
6920 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6921                            GtkTreePath *path,
6922                            gint         offset)
6923 {
6924   gtk_tree_row_reference_free (tree_view->priv->top_row);
6925
6926   if (!path)
6927     {
6928       tree_view->priv->top_row = NULL;
6929       tree_view->priv->top_row_dy = 0;
6930     }
6931   else
6932     {
6933       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6934       tree_view->priv->top_row_dy = offset;
6935     }
6936 }
6937
6938 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6939  * it's set to be NULL, and top_row_dy is 0;
6940  */
6941 static void
6942 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6943 {
6944   gint offset;
6945   GtkTreePath *path;
6946   GtkRBTree *tree;
6947   GtkRBNode *node;
6948
6949   if (tree_view->priv->tree == NULL)
6950     {
6951       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6952     }
6953   else
6954     {
6955       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6956                                         tree_view->priv->dy,
6957                                         &tree, &node);
6958
6959       if (tree == NULL)
6960         {
6961           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6962         }
6963       else
6964         {
6965           path = _gtk_tree_view_find_path (tree_view, tree, node);
6966           gtk_tree_view_set_top_row (tree_view, path, offset);
6967           gtk_tree_path_free (path);
6968         }
6969     }
6970 }
6971
6972 static void
6973 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6974 {
6975   GtkTreePath *path;
6976   GtkRBTree *tree;
6977   GtkRBNode *node;
6978   int new_dy;
6979
6980   /* Avoid recursive calls */
6981   if (tree_view->priv->in_top_row_to_dy)
6982     return;
6983
6984   if (tree_view->priv->top_row)
6985     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6986   else
6987     path = NULL;
6988
6989   if (!path)
6990     tree = NULL;
6991   else
6992     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6993
6994   if (path)
6995     gtk_tree_path_free (path);
6996
6997   if (tree == NULL)
6998     {
6999       /* keep dy and set new toprow */
7000       gtk_tree_row_reference_free (tree_view->priv->top_row);
7001       tree_view->priv->top_row = NULL;
7002       tree_view->priv->top_row_dy = 0;
7003       /* DO NOT install the idle handler */
7004       gtk_tree_view_dy_to_top_row (tree_view);
7005       return;
7006     }
7007
7008   if (gtk_tree_view_get_row_height (tree_view, node)
7009       < tree_view->priv->top_row_dy)
7010     {
7011       /* new top row -- do NOT install the idle handler */
7012       gtk_tree_view_dy_to_top_row (tree_view);
7013       return;
7014     }
7015
7016   new_dy = _gtk_rbtree_node_find_offset (tree, node);
7017   new_dy += tree_view->priv->top_row_dy;
7018
7019   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
7020     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
7021
7022   new_dy = MAX (0, new_dy);
7023
7024   tree_view->priv->in_top_row_to_dy = TRUE;
7025   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
7026   tree_view->priv->in_top_row_to_dy = FALSE;
7027 }
7028
7029
7030 void
7031 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
7032                                             gboolean     install_handler)
7033 {
7034   tree_view->priv->mark_rows_col_dirty = TRUE;
7035
7036   if (install_handler)
7037     install_presize_handler (tree_view);
7038 }
7039
7040 /*
7041  * This function works synchronously (due to the while (validate_rows...)
7042  * loop).
7043  *
7044  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
7045  * here. You now need to check that yourself.
7046  */
7047 void
7048 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
7049                                 GtkTreeViewColumn *column)
7050 {
7051   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7052   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
7053
7054   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
7055
7056   do_presize_handler (tree_view);
7057   while (validate_rows (tree_view));
7058
7059   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7060 }
7061
7062 /* Drag-and-drop */
7063
7064 static void
7065 set_source_row (GdkDragContext *context,
7066                 GtkTreeModel   *model,
7067                 GtkTreePath    *source_row)
7068 {
7069   g_object_set_data_full (G_OBJECT (context),
7070                           I_("gtk-tree-view-source-row"),
7071                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7072                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7073 }
7074
7075 static GtkTreePath*
7076 get_source_row (GdkDragContext *context)
7077 {
7078   GtkTreeRowReference *ref =
7079     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7080
7081   if (ref)
7082     return gtk_tree_row_reference_get_path (ref);
7083   else
7084     return NULL;
7085 }
7086
7087 typedef struct
7088 {
7089   GtkTreeRowReference *dest_row;
7090   guint                path_down_mode   : 1;
7091   guint                empty_view_drop  : 1;
7092   guint                drop_append_mode : 1;
7093 }
7094 DestRow;
7095
7096 static void
7097 dest_row_free (gpointer data)
7098 {
7099   DestRow *dr = (DestRow *)data;
7100
7101   gtk_tree_row_reference_free (dr->dest_row);
7102   g_slice_free (DestRow, dr);
7103 }
7104
7105 static void
7106 set_dest_row (GdkDragContext *context,
7107               GtkTreeModel   *model,
7108               GtkTreePath    *dest_row,
7109               gboolean        path_down_mode,
7110               gboolean        empty_view_drop,
7111               gboolean        drop_append_mode)
7112 {
7113   DestRow *dr;
7114
7115   if (!dest_row)
7116     {
7117       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7118                               NULL, NULL);
7119       return;
7120     }
7121
7122   dr = g_slice_new (DestRow);
7123
7124   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7125   dr->path_down_mode = path_down_mode != FALSE;
7126   dr->empty_view_drop = empty_view_drop != FALSE;
7127   dr->drop_append_mode = drop_append_mode != FALSE;
7128
7129   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7130                           dr, (GDestroyNotify) dest_row_free);
7131 }
7132
7133 static GtkTreePath*
7134 get_dest_row (GdkDragContext *context,
7135               gboolean       *path_down_mode)
7136 {
7137   DestRow *dr =
7138     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7139
7140   if (dr)
7141     {
7142       GtkTreePath *path = NULL;
7143
7144       if (path_down_mode)
7145         *path_down_mode = dr->path_down_mode;
7146
7147       if (dr->dest_row)
7148         path = gtk_tree_row_reference_get_path (dr->dest_row);
7149       else if (dr->empty_view_drop)
7150         path = gtk_tree_path_new_from_indices (0, -1);
7151       else
7152         path = NULL;
7153
7154       if (path && dr->drop_append_mode)
7155         gtk_tree_path_next (path);
7156
7157       return path;
7158     }
7159   else
7160     return NULL;
7161 }
7162
7163 /* Get/set whether drag_motion requested the drag data and
7164  * drag_data_received should thus not actually insert the data,
7165  * since the data doesn't result from a drop.
7166  */
7167 static void
7168 set_status_pending (GdkDragContext *context,
7169                     GdkDragAction   suggested_action)
7170 {
7171   g_object_set_data (G_OBJECT (context),
7172                      I_("gtk-tree-view-status-pending"),
7173                      GINT_TO_POINTER (suggested_action));
7174 }
7175
7176 static GdkDragAction
7177 get_status_pending (GdkDragContext *context)
7178 {
7179   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7180                                              "gtk-tree-view-status-pending"));
7181 }
7182
7183 static TreeViewDragInfo*
7184 get_info (GtkTreeView *tree_view)
7185 {
7186   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7187 }
7188
7189 static void
7190 destroy_info (TreeViewDragInfo *di)
7191 {
7192   g_slice_free (TreeViewDragInfo, di);
7193 }
7194
7195 static TreeViewDragInfo*
7196 ensure_info (GtkTreeView *tree_view)
7197 {
7198   TreeViewDragInfo *di;
7199
7200   di = get_info (tree_view);
7201
7202   if (di == NULL)
7203     {
7204       di = g_slice_new0 (TreeViewDragInfo);
7205
7206       g_object_set_data_full (G_OBJECT (tree_view),
7207                               I_("gtk-tree-view-drag-info"),
7208                               di,
7209                               (GDestroyNotify) destroy_info);
7210     }
7211
7212   return di;
7213 }
7214
7215 static void
7216 remove_info (GtkTreeView *tree_view)
7217 {
7218   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7219 }
7220
7221 #if 0
7222 static gint
7223 drag_scan_timeout (gpointer data)
7224 {
7225   GtkTreeView *tree_view;
7226   gint x, y;
7227   GdkModifierType state;
7228   GtkTreePath *path = NULL;
7229   GtkTreeViewColumn *column = NULL;
7230   GdkRectangle visible_rect;
7231
7232   GDK_THREADS_ENTER ();
7233
7234   tree_view = GTK_TREE_VIEW (data);
7235
7236   gdk_window_get_pointer (tree_view->priv->bin_window,
7237                           &x, &y, &state);
7238
7239   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7240
7241   /* See if we are near the edge. */
7242   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7243       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7244       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7245       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7246     {
7247       gtk_tree_view_get_path_at_pos (tree_view,
7248                                      tree_view->priv->bin_window,
7249                                      x, y,
7250                                      &path,
7251                                      &column,
7252                                      NULL,
7253                                      NULL);
7254
7255       if (path != NULL)
7256         {
7257           gtk_tree_view_scroll_to_cell (tree_view,
7258                                         path,
7259                                         column,
7260                                         TRUE,
7261                                         0.5, 0.5);
7262
7263           gtk_tree_path_free (path);
7264         }
7265     }
7266
7267   GDK_THREADS_LEAVE ();
7268
7269   return TRUE;
7270 }
7271 #endif /* 0 */
7272
7273 static void
7274 add_scroll_timeout (GtkTreeView *tree_view)
7275 {
7276   if (tree_view->priv->scroll_timeout == 0)
7277     {
7278       tree_view->priv->scroll_timeout =
7279         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7280     }
7281 }
7282
7283 static void
7284 remove_scroll_timeout (GtkTreeView *tree_view)
7285 {
7286   if (tree_view->priv->scroll_timeout != 0)
7287     {
7288       g_source_remove (tree_view->priv->scroll_timeout);
7289       tree_view->priv->scroll_timeout = 0;
7290     }
7291 }
7292
7293 static gboolean
7294 check_model_dnd (GtkTreeModel *model,
7295                  GType         required_iface,
7296                  const gchar  *signal)
7297 {
7298   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7299     {
7300       g_warning ("You must override the default '%s' handler "
7301                  "on GtkTreeView when using models that don't support "
7302                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7303                  "is to connect to '%s' and call "
7304                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7305                  "the default handler from running. Look at the source code "
7306                  "for the default handler in gtktreeview.c to get an idea what "
7307                  "your handler should do. (gtktreeview.c is in the GTK source "
7308                  "code.) If you're using GTK from a language other than C, "
7309                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7310                  signal, g_type_name (required_iface), signal);
7311       return FALSE;
7312     }
7313   else
7314     return TRUE;
7315 }
7316
7317 static void
7318 remove_open_timeout (GtkTreeView *tree_view)
7319 {
7320   if (tree_view->priv->open_dest_timeout != 0)
7321     {
7322       g_source_remove (tree_view->priv->open_dest_timeout);
7323       tree_view->priv->open_dest_timeout = 0;
7324     }
7325 }
7326
7327
7328 static gint
7329 open_row_timeout (gpointer data)
7330 {
7331   GtkTreeView *tree_view = data;
7332   GtkTreePath *dest_path = NULL;
7333   GtkTreeViewDropPosition pos;
7334   gboolean result = FALSE;
7335
7336   gtk_tree_view_get_drag_dest_row (tree_view,
7337                                    &dest_path,
7338                                    &pos);
7339
7340   if (dest_path &&
7341       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7342        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7343     {
7344       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7345       tree_view->priv->open_dest_timeout = 0;
7346
7347       gtk_tree_path_free (dest_path);
7348     }
7349   else
7350     {
7351       if (dest_path)
7352         gtk_tree_path_free (dest_path);
7353
7354       result = TRUE;
7355     }
7356
7357   return result;
7358 }
7359
7360 static gboolean
7361 scroll_row_timeout (gpointer data)
7362 {
7363   GtkTreeView *tree_view = data;
7364
7365   gtk_tree_view_vertical_autoscroll (tree_view);
7366
7367   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7368     gtk_tree_view_update_rubber_band (tree_view);
7369
7370   return TRUE;
7371 }
7372
7373 /* Returns TRUE if event should not be propagated to parent widgets */
7374 static gboolean
7375 set_destination_row (GtkTreeView    *tree_view,
7376                      GdkDragContext *context,
7377                      /* coordinates relative to the widget */
7378                      gint            x,
7379                      gint            y,
7380                      GdkDragAction  *suggested_action,
7381                      GdkAtom        *target)
7382 {
7383   GtkTreePath *path = NULL;
7384   GtkTreeViewDropPosition pos;
7385   GtkTreeViewDropPosition old_pos;
7386   TreeViewDragInfo *di;
7387   GtkWidget *widget;
7388   GtkTreePath *old_dest_path = NULL;
7389   gboolean can_drop = FALSE;
7390
7391   *suggested_action = 0;
7392   *target = GDK_NONE;
7393
7394   widget = GTK_WIDGET (tree_view);
7395
7396   di = get_info (tree_view);
7397
7398   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7399     {
7400       /* someone unset us as a drag dest, note that if
7401        * we return FALSE drag_leave isn't called
7402        */
7403
7404       gtk_tree_view_set_drag_dest_row (tree_view,
7405                                        NULL,
7406                                        GTK_TREE_VIEW_DROP_BEFORE);
7407
7408       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7409       remove_open_timeout (GTK_TREE_VIEW (widget));
7410
7411       return FALSE; /* no longer a drop site */
7412     }
7413
7414   *target = gtk_drag_dest_find_target (widget, context,
7415                                        gtk_drag_dest_get_target_list (widget));
7416   if (*target == GDK_NONE)
7417     {
7418       return FALSE;
7419     }
7420
7421   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7422                                           x, y,
7423                                           &path,
7424                                           &pos))
7425     {
7426       gint n_children;
7427       GtkTreeModel *model;
7428
7429       remove_open_timeout (tree_view);
7430
7431       /* the row got dropped on empty space, let's setup a special case
7432        */
7433
7434       if (path)
7435         gtk_tree_path_free (path);
7436
7437       model = gtk_tree_view_get_model (tree_view);
7438
7439       n_children = gtk_tree_model_iter_n_children (model, NULL);
7440       if (n_children)
7441         {
7442           pos = GTK_TREE_VIEW_DROP_AFTER;
7443           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7444         }
7445       else
7446         {
7447           pos = GTK_TREE_VIEW_DROP_BEFORE;
7448           path = gtk_tree_path_new_from_indices (0, -1);
7449         }
7450
7451       can_drop = TRUE;
7452
7453       goto out;
7454     }
7455
7456   g_assert (path);
7457
7458   /* If we left the current row's "open" zone, unset the timeout for
7459    * opening the row
7460    */
7461   gtk_tree_view_get_drag_dest_row (tree_view,
7462                                    &old_dest_path,
7463                                    &old_pos);
7464
7465   if (old_dest_path &&
7466       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7467        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7468          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7469     remove_open_timeout (tree_view);
7470
7471   if (old_dest_path)
7472     gtk_tree_path_free (old_dest_path);
7473
7474   if (TRUE /* FIXME if the location droppable predicate */)
7475     {
7476       can_drop = TRUE;
7477     }
7478
7479 out:
7480   if (can_drop)
7481     {
7482       GtkWidget *source_widget;
7483
7484       *suggested_action = gdk_drag_context_get_suggested_action (context);
7485       source_widget = gtk_drag_get_source_widget (context);
7486
7487       if (source_widget == widget)
7488         {
7489           /* Default to MOVE, unless the user has
7490            * pressed ctrl or shift to affect available actions
7491            */
7492           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7493             *suggested_action = GDK_ACTION_MOVE;
7494         }
7495
7496       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7497                                        path, pos);
7498     }
7499   else
7500     {
7501       /* can't drop here */
7502       remove_open_timeout (tree_view);
7503
7504       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7505                                        NULL,
7506                                        GTK_TREE_VIEW_DROP_BEFORE);
7507     }
7508
7509   if (path)
7510     gtk_tree_path_free (path);
7511
7512   return TRUE;
7513 }
7514
7515 static GtkTreePath*
7516 get_logical_dest_row (GtkTreeView *tree_view,
7517                       gboolean    *path_down_mode,
7518                       gboolean    *drop_append_mode)
7519 {
7520   /* adjust path to point to the row the drop goes in front of */
7521   GtkTreePath *path = NULL;
7522   GtkTreeViewDropPosition pos;
7523
7524   g_return_val_if_fail (path_down_mode != NULL, NULL);
7525   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7526
7527   *path_down_mode = FALSE;
7528   *drop_append_mode = 0;
7529
7530   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7531
7532   if (path == NULL)
7533     return NULL;
7534
7535   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7536     ; /* do nothing */
7537   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7538            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7539     *path_down_mode = TRUE;
7540   else
7541     {
7542       GtkTreeIter iter;
7543       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7544
7545       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7546
7547       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7548           !gtk_tree_model_iter_next (model, &iter))
7549         *drop_append_mode = 1;
7550       else
7551         {
7552           *drop_append_mode = 0;
7553           gtk_tree_path_next (path);
7554         }
7555     }
7556
7557   return path;
7558 }
7559
7560 static gboolean
7561 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7562                                         GdkEventMotion   *event)
7563 {
7564   GtkWidget *widget = GTK_WIDGET (tree_view);
7565   GdkDragContext *context;
7566   TreeViewDragInfo *di;
7567   GtkTreePath *path = NULL;
7568   gint button;
7569   gint cell_x, cell_y;
7570   GtkTreeModel *model;
7571   gboolean retval = FALSE;
7572
7573   di = get_info (tree_view);
7574
7575   if (di == NULL || !di->source_set)
7576     goto out;
7577
7578   if (tree_view->priv->pressed_button < 0)
7579     goto out;
7580
7581   if (!gtk_drag_check_threshold (widget,
7582                                  tree_view->priv->press_start_x,
7583                                  tree_view->priv->press_start_y,
7584                                  event->x, event->y))
7585     goto out;
7586
7587   model = gtk_tree_view_get_model (tree_view);
7588
7589   if (model == NULL)
7590     goto out;
7591
7592   button = tree_view->priv->pressed_button;
7593   tree_view->priv->pressed_button = -1;
7594
7595   gtk_tree_view_get_path_at_pos (tree_view,
7596                                  tree_view->priv->press_start_x,
7597                                  tree_view->priv->press_start_y,
7598                                  &path,
7599                                  NULL,
7600                                  &cell_x,
7601                                  &cell_y);
7602
7603   if (path == NULL)
7604     goto out;
7605
7606   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7607       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7608                                            path))
7609     goto out;
7610
7611   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7612     goto out;
7613
7614   /* Now we can begin the drag */
7615
7616   retval = TRUE;
7617
7618   context = gtk_drag_begin (widget,
7619                             gtk_drag_source_get_target_list (widget),
7620                             di->source_actions,
7621                             button,
7622                             (GdkEvent*)event);
7623
7624   set_source_row (context, model, path);
7625
7626  out:
7627   if (path)
7628     gtk_tree_path_free (path);
7629
7630   return retval;
7631 }
7632
7633
7634 static void
7635 gtk_tree_view_drag_begin (GtkWidget      *widget,
7636                           GdkDragContext *context)
7637 {
7638   GtkTreeView *tree_view;
7639   GtkTreePath *path = NULL;
7640   gint cell_x, cell_y;
7641   cairo_surface_t *row_pix;
7642   TreeViewDragInfo *di;
7643
7644   tree_view = GTK_TREE_VIEW (widget);
7645
7646   /* if the user uses a custom DND source impl, we don't set the icon here */
7647   di = get_info (tree_view);
7648
7649   if (di == NULL || !di->source_set)
7650     return;
7651
7652   gtk_tree_view_get_path_at_pos (tree_view,
7653                                  tree_view->priv->press_start_x,
7654                                  tree_view->priv->press_start_y,
7655                                  &path,
7656                                  NULL,
7657                                  &cell_x,
7658                                  &cell_y);
7659
7660   g_return_if_fail (path != NULL);
7661
7662   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7663                                                 path);
7664   cairo_surface_set_device_offset (row_pix,
7665                                    /* the + 1 is for the black border in the icon */
7666                                    - (tree_view->priv->press_start_x + 1),
7667                                    - (cell_y + 1));
7668
7669   gtk_drag_set_icon_surface (context, row_pix);
7670
7671   cairo_surface_destroy (row_pix);
7672   gtk_tree_path_free (path);
7673 }
7674
7675 static void
7676 gtk_tree_view_drag_end (GtkWidget      *widget,
7677                         GdkDragContext *context)
7678 {
7679   /* do nothing */
7680 }
7681
7682 /* Default signal implementations for the drag signals */
7683 static void
7684 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7685                              GdkDragContext   *context,
7686                              GtkSelectionData *selection_data,
7687                              guint             info,
7688                              guint             time)
7689 {
7690   GtkTreeView *tree_view;
7691   GtkTreeModel *model;
7692   TreeViewDragInfo *di;
7693   GtkTreePath *source_row;
7694
7695   tree_view = GTK_TREE_VIEW (widget);
7696
7697   model = gtk_tree_view_get_model (tree_view);
7698
7699   if (model == NULL)
7700     return;
7701
7702   di = get_info (GTK_TREE_VIEW (widget));
7703
7704   if (di == NULL)
7705     return;
7706
7707   source_row = get_source_row (context);
7708
7709   if (source_row == NULL)
7710     return;
7711
7712   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7713    * any model; for DragSource models there are some other targets
7714    * we also support.
7715    */
7716
7717   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7718       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7719                                           source_row,
7720                                           selection_data))
7721     goto done;
7722
7723   /* If drag_data_get does nothing, try providing row data. */
7724   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7725     {
7726       gtk_tree_set_row_drag_data (selection_data,
7727                                   model,
7728                                   source_row);
7729     }
7730
7731  done:
7732   gtk_tree_path_free (source_row);
7733 }
7734
7735
7736 static void
7737 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7738                                 GdkDragContext *context)
7739 {
7740   TreeViewDragInfo *di;
7741   GtkTreeModel *model;
7742   GtkTreeView *tree_view;
7743   GtkTreePath *source_row;
7744
7745   tree_view = GTK_TREE_VIEW (widget);
7746   model = gtk_tree_view_get_model (tree_view);
7747
7748   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7749     return;
7750
7751   di = get_info (tree_view);
7752
7753   if (di == NULL)
7754     return;
7755
7756   source_row = get_source_row (context);
7757
7758   if (source_row == NULL)
7759     return;
7760
7761   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7762                                          source_row);
7763
7764   gtk_tree_path_free (source_row);
7765
7766   set_source_row (context, NULL, NULL);
7767 }
7768
7769 static void
7770 gtk_tree_view_drag_leave (GtkWidget      *widget,
7771                           GdkDragContext *context,
7772                           guint             time)
7773 {
7774   /* unset any highlight row */
7775   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7776                                    NULL,
7777                                    GTK_TREE_VIEW_DROP_BEFORE);
7778
7779   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7780   remove_open_timeout (GTK_TREE_VIEW (widget));
7781 }
7782
7783
7784 static gboolean
7785 gtk_tree_view_drag_motion (GtkWidget        *widget,
7786                            GdkDragContext   *context,
7787                            /* coordinates relative to the widget */
7788                            gint              x,
7789                            gint              y,
7790                            guint             time)
7791 {
7792   gboolean empty;
7793   GtkTreePath *path = NULL;
7794   GtkTreeViewDropPosition pos;
7795   GtkTreeView *tree_view;
7796   GdkDragAction suggested_action = 0;
7797   GdkAtom target;
7798
7799   tree_view = GTK_TREE_VIEW (widget);
7800
7801   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7802     return FALSE;
7803
7804   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7805
7806   /* we only know this *after* set_desination_row */
7807   empty = tree_view->priv->empty_view_drop;
7808
7809   if (path == NULL && !empty)
7810     {
7811       /* Can't drop here. */
7812       gdk_drag_status (context, 0, time);
7813     }
7814   else
7815     {
7816       if (tree_view->priv->open_dest_timeout == 0 &&
7817           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7818            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7819         {
7820           tree_view->priv->open_dest_timeout =
7821             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7822         }
7823       else
7824         {
7825           add_scroll_timeout (tree_view);
7826         }
7827
7828       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7829         {
7830           /* Request data so we can use the source row when
7831            * determining whether to accept the drop
7832            */
7833           set_status_pending (context, suggested_action);
7834           gtk_drag_get_data (widget, context, target, time);
7835         }
7836       else
7837         {
7838           set_status_pending (context, 0);
7839           gdk_drag_status (context, suggested_action, time);
7840         }
7841     }
7842
7843   if (path)
7844     gtk_tree_path_free (path);
7845
7846   return TRUE;
7847 }
7848
7849
7850 static gboolean
7851 gtk_tree_view_drag_drop (GtkWidget        *widget,
7852                          GdkDragContext   *context,
7853                          /* coordinates relative to the widget */
7854                          gint              x,
7855                          gint              y,
7856                          guint             time)
7857 {
7858   GtkTreeView *tree_view;
7859   GtkTreePath *path;
7860   GdkDragAction suggested_action = 0;
7861   GdkAtom target = GDK_NONE;
7862   TreeViewDragInfo *di;
7863   GtkTreeModel *model;
7864   gboolean path_down_mode;
7865   gboolean drop_append_mode;
7866
7867   tree_view = GTK_TREE_VIEW (widget);
7868
7869   model = gtk_tree_view_get_model (tree_view);
7870
7871   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7872   remove_open_timeout (GTK_TREE_VIEW (widget));
7873
7874   di = get_info (tree_view);
7875
7876   if (di == NULL)
7877     return FALSE;
7878
7879   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7880     return FALSE;
7881
7882   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7883     return FALSE;
7884
7885   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7886
7887   if (target != GDK_NONE && path != NULL)
7888     {
7889       /* in case a motion had requested drag data, change things so we
7890        * treat drag data receives as a drop.
7891        */
7892       set_status_pending (context, 0);
7893       set_dest_row (context, model, path,
7894                     path_down_mode, tree_view->priv->empty_view_drop,
7895                     drop_append_mode);
7896     }
7897
7898   if (path)
7899     gtk_tree_path_free (path);
7900
7901   /* Unset this thing */
7902   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7903                                    NULL,
7904                                    GTK_TREE_VIEW_DROP_BEFORE);
7905
7906   if (target != GDK_NONE)
7907     {
7908       gtk_drag_get_data (widget, context, target, time);
7909       return TRUE;
7910     }
7911   else
7912     return FALSE;
7913 }
7914
7915 static void
7916 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7917                                   GdkDragContext   *context,
7918                                   /* coordinates relative to the widget */
7919                                   gint              x,
7920                                   gint              y,
7921                                   GtkSelectionData *selection_data,
7922                                   guint             info,
7923                                   guint             time)
7924 {
7925   GtkTreePath *path;
7926   TreeViewDragInfo *di;
7927   gboolean accepted = FALSE;
7928   GtkTreeModel *model;
7929   GtkTreeView *tree_view;
7930   GtkTreePath *dest_row;
7931   GdkDragAction suggested_action;
7932   gboolean path_down_mode;
7933   gboolean drop_append_mode;
7934
7935   tree_view = GTK_TREE_VIEW (widget);
7936
7937   model = gtk_tree_view_get_model (tree_view);
7938
7939   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7940     return;
7941
7942   di = get_info (tree_view);
7943
7944   if (di == NULL)
7945     return;
7946
7947   suggested_action = get_status_pending (context);
7948
7949   if (suggested_action)
7950     {
7951       /* We are getting this data due to a request in drag_motion,
7952        * rather than due to a request in drag_drop, so we are just
7953        * supposed to call drag_status, not actually paste in the
7954        * data.
7955        */
7956       path = get_logical_dest_row (tree_view, &path_down_mode,
7957                                    &drop_append_mode);
7958
7959       if (path == NULL)
7960         suggested_action = 0;
7961       else if (path_down_mode)
7962         gtk_tree_path_down (path);
7963
7964       if (suggested_action)
7965         {
7966           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7967                                                      path,
7968                                                      selection_data))
7969             {
7970               if (path_down_mode)
7971                 {
7972                   path_down_mode = FALSE;
7973                   gtk_tree_path_up (path);
7974
7975                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7976                                                              path,
7977                                                              selection_data))
7978                     suggested_action = 0;
7979                 }
7980               else
7981                 suggested_action = 0;
7982             }
7983         }
7984
7985       gdk_drag_status (context, suggested_action, time);
7986
7987       if (path)
7988         gtk_tree_path_free (path);
7989
7990       /* If you can't drop, remove user drop indicator until the next motion */
7991       if (suggested_action == 0)
7992         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7993                                          NULL,
7994                                          GTK_TREE_VIEW_DROP_BEFORE);
7995
7996       return;
7997     }
7998
7999   dest_row = get_dest_row (context, &path_down_mode);
8000
8001   if (dest_row == NULL)
8002     return;
8003
8004   if (gtk_selection_data_get_length (selection_data) >= 0)
8005     {
8006       if (path_down_mode)
8007         {
8008           gtk_tree_path_down (dest_row);
8009           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
8010                                                      dest_row, selection_data))
8011             gtk_tree_path_up (dest_row);
8012         }
8013     }
8014
8015   if (gtk_selection_data_get_length (selection_data) >= 0)
8016     {
8017       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
8018                                                  dest_row,
8019                                                  selection_data))
8020         accepted = TRUE;
8021     }
8022
8023   gtk_drag_finish (context,
8024                    accepted,
8025                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
8026                    time);
8027
8028   if (gtk_tree_path_get_depth (dest_row) == 1
8029       && gtk_tree_path_get_indices (dest_row)[0] == 0)
8030     {
8031       /* special special case drag to "0", scroll to first item */
8032       if (!tree_view->priv->scroll_to_path)
8033         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
8034     }
8035
8036   gtk_tree_path_free (dest_row);
8037
8038   /* drop dest_row */
8039   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
8040 }
8041
8042
8043
8044 /* GtkContainer Methods
8045  */
8046
8047
8048 static void
8049 gtk_tree_view_remove (GtkContainer *container,
8050                       GtkWidget    *widget)
8051 {
8052   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8053   GtkTreeViewChild *child = NULL;
8054   GList *tmp_list;
8055
8056   tmp_list = tree_view->priv->children;
8057   while (tmp_list)
8058     {
8059       child = tmp_list->data;
8060       if (child->widget == widget)
8061         {
8062           gtk_widget_unparent (widget);
8063
8064           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
8065           g_list_free_1 (tmp_list);
8066           g_slice_free (GtkTreeViewChild, child);
8067           return;
8068         }
8069
8070       tmp_list = tmp_list->next;
8071     }
8072
8073   tmp_list = tree_view->priv->columns;
8074
8075   while (tmp_list)
8076     {
8077       GtkTreeViewColumn *column;
8078       GtkWidget         *button;
8079
8080       column = tmp_list->data;
8081       button = gtk_tree_view_column_get_button (column);
8082
8083       if (button == widget)
8084         {
8085           gtk_widget_unparent (widget);
8086           return;
8087         }
8088       tmp_list = tmp_list->next;
8089     }
8090 }
8091
8092 static void
8093 gtk_tree_view_forall (GtkContainer *container,
8094                       gboolean      include_internals,
8095                       GtkCallback   callback,
8096                       gpointer      callback_data)
8097 {
8098   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8099   GtkTreeViewChild *child = NULL;
8100   GtkTreeViewColumn *column;
8101   GtkWidget *button;
8102   GList *tmp_list;
8103
8104   tmp_list = tree_view->priv->children;
8105   while (tmp_list)
8106     {
8107       child = tmp_list->data;
8108       tmp_list = tmp_list->next;
8109
8110       (* callback) (child->widget, callback_data);
8111     }
8112   if (include_internals == FALSE)
8113     return;
8114
8115   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8116     {
8117       column = tmp_list->data;
8118       button = gtk_tree_view_column_get_button (column);
8119
8120       if (button)
8121         (* callback) (button, callback_data);
8122     }
8123 }
8124
8125 /* Returns TRUE is any of the columns contains a cell that can-focus.
8126  * If this is not the case, a column-spanning focus rectangle will be
8127  * drawn.
8128  */
8129 static gboolean
8130 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8131 {
8132   GList *list;
8133
8134   for (list = tree_view->priv->columns; list; list = list->next)
8135     {
8136       GtkTreeViewColumn *column = list->data;
8137
8138       if (!gtk_tree_view_column_get_visible (column))
8139         continue;
8140       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8141         return TRUE;
8142     }
8143
8144   return FALSE;
8145 }
8146
8147 static void
8148 column_sizing_notify (GObject    *object,
8149                       GParamSpec *pspec,
8150                       gpointer    data)
8151 {
8152   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8153
8154   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8155     /* disable fixed height mode */
8156     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8157 }
8158
8159 /**
8160  * gtk_tree_view_set_fixed_height_mode:
8161  * @tree_view: a #GtkTreeView 
8162  * @enable: %TRUE to enable fixed height mode
8163  * 
8164  * Enables or disables the fixed height mode of @tree_view. 
8165  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8166  * rows have the same height. 
8167  * Only enable this option if all rows are the same height and all
8168  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8169  *
8170  * Since: 2.6 
8171  **/
8172 void
8173 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8174                                      gboolean     enable)
8175 {
8176   GList *l;
8177   
8178   enable = enable != FALSE;
8179
8180   if (enable == tree_view->priv->fixed_height_mode)
8181     return;
8182
8183   if (!enable)
8184     {
8185       tree_view->priv->fixed_height_mode = 0;
8186       tree_view->priv->fixed_height = -1;
8187
8188       /* force a revalidation */
8189       install_presize_handler (tree_view);
8190     }
8191   else 
8192     {
8193       /* make sure all columns are of type FIXED */
8194       for (l = tree_view->priv->columns; l; l = l->next)
8195         {
8196           GtkTreeViewColumn *c = l->data;
8197           
8198           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8199         }
8200       
8201       /* yes, we really have to do this is in a separate loop */
8202       for (l = tree_view->priv->columns; l; l = l->next)
8203         g_signal_connect (l->data, "notify::sizing",
8204                           G_CALLBACK (column_sizing_notify), tree_view);
8205       
8206       tree_view->priv->fixed_height_mode = 1;
8207       tree_view->priv->fixed_height = -1;
8208       
8209       if (tree_view->priv->tree)
8210         initialize_fixed_height_mode (tree_view);
8211     }
8212
8213   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8214 }
8215
8216 /**
8217  * gtk_tree_view_get_fixed_height_mode:
8218  * @tree_view: a #GtkTreeView
8219  * 
8220  * Returns whether fixed height mode is turned on for @tree_view.
8221  * 
8222  * Return value: %TRUE if @tree_view is in fixed height mode
8223  * 
8224  * Since: 2.6
8225  **/
8226 gboolean
8227 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8228 {
8229   return tree_view->priv->fixed_height_mode;
8230 }
8231
8232 /* Returns TRUE if the focus is within the headers, after the focus operation is
8233  * done
8234  */
8235 static gboolean
8236 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8237                             GtkDirectionType  dir,
8238                             gboolean          clamp_column_visible)
8239 {
8240   GtkTreeViewColumn *column;
8241   GtkWidget *focus_child;
8242   GtkWidget *button;
8243   GList *last_column, *first_column;
8244   GList *tmp_list;
8245   gboolean rtl;
8246
8247   if (! tree_view->priv->headers_visible)
8248     return FALSE;
8249
8250   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8251
8252   first_column = tree_view->priv->columns;
8253   while (first_column)
8254     {
8255       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8256       button = gtk_tree_view_column_get_button (column);
8257
8258       if (gtk_widget_get_can_focus (button) &&
8259           gtk_tree_view_column_get_visible (column) &&
8260           (gtk_tree_view_column_get_clickable (column) ||
8261            gtk_tree_view_column_get_reorderable (column)))
8262         break;
8263       first_column = first_column->next;
8264     }
8265
8266   /* No headers are visible, or are focusable.  We can't focus in or out.
8267    */
8268   if (first_column == NULL)
8269     return FALSE;
8270
8271   last_column = g_list_last (tree_view->priv->columns);
8272   while (last_column)
8273     {
8274       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8275       button = gtk_tree_view_column_get_button (column);
8276
8277       if (gtk_widget_get_can_focus (button) &&
8278           gtk_tree_view_column_get_visible (column) &&
8279           (gtk_tree_view_column_get_clickable (column) ||
8280            gtk_tree_view_column_get_reorderable (column)))
8281         break;
8282       last_column = last_column->prev;
8283     }
8284
8285
8286   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8287
8288   switch (dir)
8289     {
8290     case GTK_DIR_TAB_BACKWARD:
8291     case GTK_DIR_TAB_FORWARD:
8292     case GTK_DIR_UP:
8293     case GTK_DIR_DOWN:
8294       if (focus_child == NULL)
8295         {
8296           if (tree_view->priv->focus_column != NULL)
8297             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8298           else 
8299             button = NULL;
8300
8301           if (button && gtk_widget_get_can_focus (button))
8302             focus_child = button;
8303           else
8304             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8305
8306           gtk_widget_grab_focus (focus_child);
8307           break;
8308         }
8309       return FALSE;
8310
8311     case GTK_DIR_LEFT:
8312     case GTK_DIR_RIGHT:
8313       if (focus_child == NULL)
8314         {
8315           if (tree_view->priv->focus_column != NULL)
8316             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8317           else if (dir == GTK_DIR_LEFT)
8318             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8319           else
8320             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8321
8322           gtk_widget_grab_focus (focus_child);
8323           break;
8324         }
8325
8326       if (gtk_widget_child_focus (focus_child, dir))
8327         {
8328           /* The focus moves inside the button. */
8329           /* This is probably a great example of bad UI */
8330           break;
8331         }
8332
8333       /* We need to move the focus among the row of buttons. */
8334       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8335         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8336           break;
8337
8338       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8339           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8340         {
8341           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8342           break;
8343         }
8344
8345       while (tmp_list)
8346         {
8347           GtkTreeViewColumn *column;
8348           GtkWidget         *button;
8349
8350           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8351             tmp_list = tmp_list->next;
8352           else
8353             tmp_list = tmp_list->prev;
8354
8355           if (tmp_list == NULL)
8356             {
8357               g_warning ("Internal button not found");
8358               break;
8359             }
8360           column = tmp_list->data;
8361           button = gtk_tree_view_column_get_button (column);
8362           if (button &&
8363               gtk_tree_view_column_get_visible (column) &&
8364               gtk_widget_get_can_focus (button))
8365             {
8366               focus_child = button;
8367               gtk_widget_grab_focus (button);
8368               break;
8369             }
8370         }
8371       break;
8372     default:
8373       g_assert_not_reached ();
8374       break;
8375     }
8376
8377   /* if focus child is non-null, we assume it's been set to the current focus child
8378    */
8379   if (focus_child)
8380     {
8381       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8382         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8383           {
8384             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8385             break;
8386           }
8387
8388       if (clamp_column_visible)
8389         {
8390           gtk_tree_view_clamp_column_visible (tree_view,
8391                                               tree_view->priv->focus_column,
8392                                               FALSE);
8393         }
8394     }
8395
8396   return (focus_child != NULL);
8397 }
8398
8399 /* This function returns in 'path' the first focusable path, if the given path
8400  * is already focusable, it's the returned one.
8401  */
8402 static gboolean
8403 search_first_focusable_path (GtkTreeView  *tree_view,
8404                              GtkTreePath **path,
8405                              gboolean      search_forward,
8406                              GtkRBTree   **new_tree,
8407                              GtkRBNode   **new_node)
8408 {
8409   GtkRBTree *tree = NULL;
8410   GtkRBNode *node = NULL;
8411
8412   if (!path || !*path)
8413     return FALSE;
8414
8415   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8416
8417   if (!tree || !node)
8418     return FALSE;
8419
8420   while (node && row_is_separator (tree_view, NULL, *path))
8421     {
8422       if (search_forward)
8423         _gtk_rbtree_next_full (tree, node, &tree, &node);
8424       else
8425         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8426
8427       if (*path)
8428         gtk_tree_path_free (*path);
8429
8430       if (node)
8431         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8432       else
8433         *path = NULL;
8434     }
8435
8436   if (new_tree)
8437     *new_tree = tree;
8438
8439   if (new_node)
8440     *new_node = node;
8441
8442   return (*path != NULL);
8443 }
8444
8445 static gint
8446 gtk_tree_view_focus (GtkWidget        *widget,
8447                      GtkDirectionType  direction)
8448 {
8449   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8450   GtkContainer *container = GTK_CONTAINER (widget);
8451   GtkWidget *focus_child;
8452
8453   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8454     return FALSE;
8455
8456   focus_child = gtk_container_get_focus_child (container);
8457
8458   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8459   /* Case 1.  Headers currently have focus. */
8460   if (focus_child)
8461     {
8462       switch (direction)
8463         {
8464         case GTK_DIR_LEFT:
8465         case GTK_DIR_RIGHT:
8466           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8467           return TRUE;
8468         case GTK_DIR_TAB_BACKWARD:
8469         case GTK_DIR_UP:
8470           return FALSE;
8471         case GTK_DIR_TAB_FORWARD:
8472         case GTK_DIR_DOWN:
8473           gtk_widget_grab_focus (widget);
8474           return TRUE;
8475         default:
8476           g_assert_not_reached ();
8477           return FALSE;
8478         }
8479     }
8480
8481   /* Case 2. We don't have focus at all. */
8482   if (!gtk_widget_has_focus (widget))
8483     {
8484       gtk_widget_grab_focus (widget);
8485       return TRUE;
8486     }
8487
8488   /* Case 3. We have focus already. */
8489   if (direction == GTK_DIR_TAB_BACKWARD)
8490     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8491   else if (direction == GTK_DIR_TAB_FORWARD)
8492     return FALSE;
8493
8494   /* Other directions caught by the keybindings */
8495   gtk_widget_grab_focus (widget);
8496   return TRUE;
8497 }
8498
8499 static void
8500 gtk_tree_view_grab_focus (GtkWidget *widget)
8501 {
8502   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8503
8504   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8505 }
8506
8507 static void
8508 gtk_tree_view_style_set (GtkWidget *widget,
8509                          GtkStyle *previous_style)
8510 {
8511   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8512   GtkStyle *style;
8513   GList *list;
8514   GtkTreeViewColumn *column;
8515
8516   if (gtk_widget_get_realized (widget))
8517     {
8518       style = gtk_widget_get_style (widget);
8519       gdk_window_set_background (tree_view->priv->bin_window,
8520                                  &style->base[gtk_widget_get_state (widget)]);
8521       gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8522
8523       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8524       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8525     }
8526
8527   gtk_widget_style_get (widget,
8528                         "expander-size", &tree_view->priv->expander_size,
8529                         NULL);
8530   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8531
8532   for (list = tree_view->priv->columns; list; list = list->next)
8533     {
8534       column = list->data;
8535       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8536     }
8537
8538   tree_view->priv->fixed_height = -1;
8539   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8540
8541   gtk_widget_queue_resize (widget);
8542 }
8543
8544
8545 static void
8546 gtk_tree_view_set_focus_child (GtkContainer *container,
8547                                GtkWidget    *child)
8548 {
8549   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8550   GList *list;
8551
8552   for (list = tree_view->priv->columns; list; list = list->next)
8553     {
8554       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8555         {
8556           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8557           break;
8558         }
8559     }
8560
8561   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8562 }
8563
8564 static gboolean
8565 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8566                                 GtkMovementStep    step,
8567                                 gint               count)
8568 {
8569   GdkModifierType state;
8570
8571   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8572   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8573                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8574                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8575                         step == GTK_MOVEMENT_PAGES ||
8576                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8577
8578   if (tree_view->priv->tree == NULL)
8579     return FALSE;
8580   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8581     return FALSE;
8582
8583   gtk_tree_view_stop_editing (tree_view, FALSE);
8584   tree_view->priv->draw_keyfocus = TRUE;
8585   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8586
8587   if (gtk_get_current_event_state (&state))
8588     {
8589       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8590         tree_view->priv->ctrl_pressed = TRUE;
8591       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8592         tree_view->priv->shift_pressed = TRUE;
8593     }
8594   /* else we assume not pressed */
8595
8596   switch (step)
8597     {
8598       /* currently we make no distinction.  When we go bi-di, we need to */
8599     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8600     case GTK_MOVEMENT_VISUAL_POSITIONS:
8601       gtk_tree_view_move_cursor_left_right (tree_view, count);
8602       break;
8603     case GTK_MOVEMENT_DISPLAY_LINES:
8604       gtk_tree_view_move_cursor_up_down (tree_view, count);
8605       break;
8606     case GTK_MOVEMENT_PAGES:
8607       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8608       break;
8609     case GTK_MOVEMENT_BUFFER_ENDS:
8610       gtk_tree_view_move_cursor_start_end (tree_view, count);
8611       break;
8612     default:
8613       g_assert_not_reached ();
8614     }
8615
8616   tree_view->priv->ctrl_pressed = FALSE;
8617   tree_view->priv->shift_pressed = FALSE;
8618
8619   return TRUE;
8620 }
8621
8622 static void
8623 gtk_tree_view_put (GtkTreeView *tree_view,
8624                    GtkWidget   *child_widget,
8625                    /* in bin_window coordinates */
8626                    gint         x,
8627                    gint         y,
8628                    gint         width,
8629                    gint         height)
8630 {
8631   GtkTreeViewChild *child;
8632   
8633   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8634   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8635
8636   child = g_slice_new (GtkTreeViewChild);
8637
8638   child->widget = child_widget;
8639   child->x = x;
8640   child->y = y;
8641   child->width = width;
8642   child->height = height;
8643
8644   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8645
8646   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8647     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8648   
8649   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8650 }
8651
8652 void
8653 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8654                                   GtkWidget   *widget,
8655                                   /* in tree coordinates */
8656                                   gint         x,
8657                                   gint         y,
8658                                   gint         width,
8659                                   gint         height)
8660 {
8661   GtkTreeViewChild *child = NULL;
8662   GList *list;
8663   GdkRectangle allocation;
8664
8665   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8666   g_return_if_fail (GTK_IS_WIDGET (widget));
8667
8668   for (list = tree_view->priv->children; list; list = list->next)
8669     {
8670       if (((GtkTreeViewChild *)list->data)->widget == widget)
8671         {
8672           child = list->data;
8673           break;
8674         }
8675     }
8676   if (child == NULL)
8677     return;
8678
8679   allocation.x = child->x = x;
8680   allocation.y = child->y = y;
8681   allocation.width = child->width = width;
8682   allocation.height = child->height = height;
8683
8684   if (gtk_widget_get_realized (widget))
8685     gtk_widget_size_allocate (widget, &allocation);
8686 }
8687
8688
8689 /* TreeModel Callbacks
8690  */
8691
8692 static void
8693 gtk_tree_view_row_changed (GtkTreeModel *model,
8694                            GtkTreePath  *path,
8695                            GtkTreeIter  *iter,
8696                            gpointer      data)
8697 {
8698   GtkTreeView *tree_view = (GtkTreeView *)data;
8699   GtkRBTree *tree;
8700   GtkRBNode *node;
8701   gboolean free_path = FALSE;
8702   GList *list;
8703   GtkTreePath *cursor_path;
8704
8705   g_return_if_fail (path != NULL || iter != NULL);
8706
8707   if (tree_view->priv->cursor != NULL)
8708     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8709   else
8710     cursor_path = NULL;
8711
8712   if (tree_view->priv->edited_column &&
8713       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8714     gtk_tree_view_stop_editing (tree_view, TRUE);
8715
8716   if (cursor_path != NULL)
8717     gtk_tree_path_free (cursor_path);
8718
8719   if (path == NULL)
8720     {
8721       path = gtk_tree_model_get_path (model, iter);
8722       free_path = TRUE;
8723     }
8724   else if (iter == NULL)
8725     gtk_tree_model_get_iter (model, iter, path);
8726
8727   if (_gtk_tree_view_find_node (tree_view,
8728                                 path,
8729                                 &tree,
8730                                 &node))
8731     /* We aren't actually showing the node */
8732     goto done;
8733
8734   if (tree == NULL)
8735     goto done;
8736
8737   if (tree_view->priv->fixed_height_mode
8738       && tree_view->priv->fixed_height >= 0)
8739     {
8740       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8741       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8742         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8743     }
8744   else
8745     {
8746       _gtk_rbtree_node_mark_invalid (tree, node);
8747       for (list = tree_view->priv->columns; list; list = list->next)
8748         {
8749           GtkTreeViewColumn *column;
8750
8751           column = list->data;
8752           if (!gtk_tree_view_column_get_visible (column))
8753             continue;
8754
8755           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8756             {
8757               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8758             }
8759         }
8760     }
8761
8762  done:
8763   if (!tree_view->priv->fixed_height_mode &&
8764       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8765     install_presize_handler (tree_view);
8766   if (free_path)
8767     gtk_tree_path_free (path);
8768 }
8769
8770 static void
8771 gtk_tree_view_row_inserted (GtkTreeModel *model,
8772                             GtkTreePath  *path,
8773                             GtkTreeIter  *iter,
8774                             gpointer      data)
8775 {
8776   GtkTreeView *tree_view = (GtkTreeView *) data;
8777   gint *indices;
8778   GtkRBTree *tmptree, *tree;
8779   GtkRBNode *tmpnode = NULL;
8780   gint depth;
8781   gint i = 0;
8782   gint height;
8783   gboolean free_path = FALSE;
8784   gboolean node_visible = TRUE;
8785
8786   g_return_if_fail (path != NULL || iter != NULL);
8787
8788   if (tree_view->priv->fixed_height_mode
8789       && tree_view->priv->fixed_height >= 0)
8790     height = tree_view->priv->fixed_height;
8791   else
8792     height = 0;
8793
8794   if (path == NULL)
8795     {
8796       path = gtk_tree_model_get_path (model, iter);
8797       free_path = TRUE;
8798     }
8799   else if (iter == NULL)
8800     gtk_tree_model_get_iter (model, iter, path);
8801
8802   if (tree_view->priv->tree == NULL)
8803     tree_view->priv->tree = _gtk_rbtree_new ();
8804
8805   tmptree = tree = tree_view->priv->tree;
8806
8807   /* Update all row-references */
8808   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8809   depth = gtk_tree_path_get_depth (path);
8810   indices = gtk_tree_path_get_indices (path);
8811
8812   /* First, find the parent tree */
8813   while (i < depth - 1)
8814     {
8815       if (tmptree == NULL)
8816         {
8817           /* We aren't showing the node */
8818           node_visible = FALSE;
8819           goto done;
8820         }
8821
8822       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8823       if (tmpnode == NULL)
8824         {
8825           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8826                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8827                      "before the parent was inserted.");
8828           goto done;
8829         }
8830       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8831         {
8832           /* FIXME enforce correct behavior on model, probably */
8833           /* In theory, the model should have emitted has_child_toggled here.  We
8834            * try to catch it anyway, just to be safe, in case the model hasn't.
8835            */
8836           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8837                                                            tree,
8838                                                            tmpnode);
8839           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8840           gtk_tree_path_free (tmppath);
8841           goto done;
8842         }
8843
8844       tmptree = tmpnode->children;
8845       tree = tmptree;
8846       i++;
8847     }
8848
8849   if (tree == NULL)
8850     {
8851       node_visible = FALSE;
8852       goto done;
8853     }
8854
8855   /* ref the node */
8856   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8857   if (indices[depth - 1] == 0)
8858     {
8859       tmpnode = _gtk_rbtree_find_count (tree, 1);
8860       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8861     }
8862   else
8863     {
8864       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8865       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8866     }
8867
8868  done:
8869   if (height > 0)
8870     {
8871       if (tree)
8872         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8873
8874       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8875         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8876       else
8877         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8878     }
8879   else
8880     install_presize_handler (tree_view);
8881   if (free_path)
8882     gtk_tree_path_free (path);
8883 }
8884
8885 static void
8886 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8887                                      GtkTreePath  *path,
8888                                      GtkTreeIter  *iter,
8889                                      gpointer      data)
8890 {
8891   GtkTreeView *tree_view = (GtkTreeView *)data;
8892   GtkTreeIter real_iter;
8893   gboolean has_child;
8894   GtkRBTree *tree;
8895   GtkRBNode *node;
8896   gboolean free_path = FALSE;
8897
8898   g_return_if_fail (path != NULL || iter != NULL);
8899
8900   if (iter)
8901     real_iter = *iter;
8902
8903   if (path == NULL)
8904     {
8905       path = gtk_tree_model_get_path (model, iter);
8906       free_path = TRUE;
8907     }
8908   else if (iter == NULL)
8909     gtk_tree_model_get_iter (model, &real_iter, path);
8910
8911   if (_gtk_tree_view_find_node (tree_view,
8912                                 path,
8913                                 &tree,
8914                                 &node))
8915     /* We aren't actually showing the node */
8916     goto done;
8917
8918   if (tree == NULL)
8919     goto done;
8920
8921   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8922   /* Sanity check.
8923    */
8924   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8925     goto done;
8926
8927   if (has_child)
8928     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8929   else
8930     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8931
8932   if (has_child && tree_view->priv->is_list)
8933     {
8934       tree_view->priv->is_list = FALSE;
8935       if (tree_view->priv->show_expanders)
8936         {
8937           GList *list;
8938
8939           for (list = tree_view->priv->columns; list; list = list->next)
8940             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8941               {
8942                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8943                 break;
8944               }
8945         }
8946       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8947     }
8948   else
8949     {
8950       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8951     }
8952
8953  done:
8954   if (free_path)
8955     gtk_tree_path_free (path);
8956 }
8957
8958 static void
8959 count_children_helper (GtkRBTree *tree,
8960                        GtkRBNode *node,
8961                        gpointer   data)
8962 {
8963   if (node->children)
8964     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8965   (*((gint *)data))++;
8966 }
8967
8968 static void
8969 check_selection_helper (GtkRBTree *tree,
8970                         GtkRBNode *node,
8971                         gpointer   data)
8972 {
8973   gint *value = (gint *)data;
8974
8975   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8976
8977   if (node->children && !*value)
8978     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8979 }
8980
8981 static void
8982 gtk_tree_view_row_deleted (GtkTreeModel *model,
8983                            GtkTreePath  *path,
8984                            gpointer      data)
8985 {
8986   GtkTreeView *tree_view = (GtkTreeView *)data;
8987   GtkRBTree *tree;
8988   GtkRBNode *node;
8989   GList *list;
8990   gint selection_changed = FALSE;
8991
8992   g_return_if_fail (path != NULL);
8993
8994   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8995
8996   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8997     return;
8998
8999   if (tree == NULL)
9000     return;
9001
9002   /* check if the selection has been changed */
9003   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
9004                         check_selection_helper, &selection_changed);
9005
9006   for (list = tree_view->priv->columns; list; list = list->next)
9007     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
9008         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9009       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
9010
9011   /* Ensure we don't have a dangling pointer to a dead node */
9012   ensure_unprelighted (tree_view);
9013
9014   /* Cancel editting if we've started */
9015   gtk_tree_view_stop_editing (tree_view, TRUE);
9016
9017   /* If we have a node expanded/collapsed timeout, remove it */
9018   remove_expand_collapse_timeout (tree_view);
9019
9020   if (tree_view->priv->destroy_count_func)
9021     {
9022       gint child_count = 0;
9023       if (node->children)
9024         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9025       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9026     }
9027
9028   if (tree->root->count == 1)
9029     {
9030       if (tree_view->priv->tree == tree)
9031         tree_view->priv->tree = NULL;
9032
9033       _gtk_rbtree_remove (tree);
9034     }
9035   else
9036     {
9037       _gtk_rbtree_remove_node (tree, node);
9038     }
9039
9040   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9041     {
9042       gtk_tree_row_reference_free (tree_view->priv->top_row);
9043       tree_view->priv->top_row = NULL;
9044     }
9045
9046   install_scroll_sync_handler (tree_view);
9047
9048   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9049
9050   if (selection_changed)
9051     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9052 }
9053
9054 static void
9055 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9056                               GtkTreePath  *parent,
9057                               GtkTreeIter  *iter,
9058                               gint         *new_order,
9059                               gpointer      data)
9060 {
9061   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9062   GtkRBTree *tree;
9063   GtkRBNode *node;
9064   gint len;
9065
9066   len = gtk_tree_model_iter_n_children (model, iter);
9067
9068   if (len < 2)
9069     return;
9070
9071   gtk_tree_row_reference_reordered (G_OBJECT (data),
9072                                     parent,
9073                                     iter,
9074                                     new_order);
9075
9076   if (_gtk_tree_view_find_node (tree_view,
9077                                 parent,
9078                                 &tree,
9079                                 &node))
9080     return;
9081
9082   /* We need to special case the parent path */
9083   if (tree == NULL)
9084     tree = tree_view->priv->tree;
9085   else
9086     tree = node->children;
9087
9088   if (tree == NULL)
9089     return;
9090
9091   if (tree_view->priv->edited_column)
9092     gtk_tree_view_stop_editing (tree_view, TRUE);
9093
9094   /* we need to be unprelighted */
9095   ensure_unprelighted (tree_view);
9096
9097   /* clear the timeout */
9098   cancel_arrow_animation (tree_view);
9099   
9100   _gtk_rbtree_reorder (tree, new_order, len);
9101
9102   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9103
9104   gtk_tree_view_dy_to_top_row (tree_view);
9105 }
9106
9107
9108 /* Internal tree functions
9109  */
9110
9111
9112 static void
9113 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9114                                      GtkRBTree         *tree,
9115                                      GtkTreeViewColumn *column,
9116                                      gint              *x1,
9117                                      gint              *x2)
9118 {
9119   GtkTreeViewColumn *tmp_column = NULL;
9120   gint total_width;
9121   GList *list;
9122   gboolean rtl;
9123
9124   if (x1)
9125     *x1 = 0;
9126
9127   if (x2)
9128     *x2 = 0;
9129
9130   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9131
9132   total_width = 0;
9133   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9134        list;
9135        list = (rtl ? list->prev : list->next))
9136     {
9137       tmp_column = list->data;
9138
9139       if (tmp_column == column)
9140         break;
9141
9142       if (gtk_tree_view_column_get_visible (tmp_column))
9143         total_width += gtk_tree_view_column_get_width (tmp_column);
9144     }
9145
9146   if (tmp_column != column)
9147     {
9148       g_warning (G_STRLOC": passed-in column isn't in the tree");
9149       return;
9150     }
9151
9152   if (x1)
9153     *x1 = total_width;
9154
9155   if (x2)
9156     {
9157       if (gtk_tree_view_column_get_visible (column))
9158         *x2 = total_width + gtk_tree_view_column_get_width (column);
9159       else
9160         *x2 = total_width; /* width of 0 */
9161     }
9162 }
9163
9164 static void
9165 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9166                                 GtkRBTree   *tree,
9167                                 gint        *x1,
9168                                 gint        *x2)
9169 {
9170   gint x_offset = 0;
9171   GList *list;
9172   GtkTreeViewColumn *tmp_column = NULL;
9173   gint total_width;
9174   gboolean indent_expanders;
9175   gboolean rtl;
9176
9177   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9178
9179   total_width = 0;
9180   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9181        list;
9182        list = (rtl ? list->prev : list->next))
9183     {
9184       tmp_column = list->data;
9185
9186       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9187         {
9188           if (rtl)
9189             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - tree_view->priv->expander_size;
9190           else
9191             x_offset = total_width;
9192           break;
9193         }
9194
9195       if (gtk_tree_view_column_get_visible (tmp_column))
9196         total_width += gtk_tree_view_column_get_width (tmp_column);
9197     }
9198
9199   gtk_widget_style_get (GTK_WIDGET (tree_view),
9200                         "indent-expanders", &indent_expanders,
9201                         NULL);
9202
9203   if (indent_expanders)
9204     {
9205       if (rtl)
9206         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9207       else
9208         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9209     }
9210
9211   *x1 = x_offset;
9212
9213   if (tmp_column &&
9214       gtk_tree_view_column_get_visible (tmp_column))
9215     /* +1 because x2 isn't included in the range. */
9216     *x2 = *x1 + tree_view->priv->expander_size + 1;
9217   else
9218     *x2 = *x1;
9219 }
9220
9221 static void
9222 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9223                           GtkRBTree   *tree,
9224                           GtkTreeIter *iter,
9225                           gint         depth,
9226                           gboolean     recurse)
9227 {
9228   GtkRBNode *temp = NULL;
9229   GtkTreePath *path = NULL;
9230
9231   do
9232     {
9233       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9234       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9235
9236       if (tree_view->priv->fixed_height > 0)
9237         {
9238           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9239             {
9240               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9241               _gtk_rbtree_node_mark_valid (tree, temp);
9242             }
9243         }
9244
9245       if (tree_view->priv->is_list)
9246         continue;
9247
9248       if (recurse)
9249         {
9250           GtkTreeIter child;
9251
9252           if (!path)
9253             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9254           else
9255             gtk_tree_path_next (path);
9256
9257           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9258             {
9259               gboolean expand;
9260
9261               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9262
9263               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9264                   && !expand)
9265                 {
9266                   temp->children = _gtk_rbtree_new ();
9267                   temp->children->parent_tree = tree;
9268                   temp->children->parent_node = temp;
9269                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9270                 }
9271             }
9272         }
9273
9274       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9275         {
9276           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9277             temp->flags ^= GTK_RBNODE_IS_PARENT;
9278         }
9279     }
9280   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9281
9282   if (path)
9283     gtk_tree_path_free (path);
9284 }
9285
9286 /* Make sure the node is visible vertically */
9287 static void
9288 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9289                                   GtkRBTree   *tree,
9290                                   GtkRBNode   *node)
9291 {
9292   gint node_dy, height;
9293   GtkTreePath *path = NULL;
9294
9295   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9296     return;
9297
9298   /* just return if the node is visible, avoiding a costly expose */
9299   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9300   height = gtk_tree_view_get_row_height (tree_view, node);
9301   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9302       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9303       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9304                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9305     return;
9306
9307   path = _gtk_tree_view_find_path (tree_view, tree, node);
9308   if (path)
9309     {
9310       /* We process updates because we want to clear old selected items when we scroll.
9311        * if this is removed, we get a "selection streak" at the bottom. */
9312       gtk_tree_view_bin_process_updates (tree_view);
9313
9314       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9315       gtk_tree_path_free (path);
9316     }
9317 }
9318
9319 static void
9320 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9321                                     GtkTreeViewColumn *column,
9322                                     gboolean           focus_to_cell)
9323 {
9324   GtkAllocation allocation;
9325   gint x, width;
9326
9327   if (column == NULL)
9328     return;
9329
9330   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9331   x = allocation.x;
9332   width = allocation.width;
9333
9334   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9335     {
9336       /* The column is larger than the horizontal page size.  If the
9337        * column has cells which can be focussed individually, then we make
9338        * sure the cell which gets focus is fully visible (if even the
9339        * focus cell is bigger than the page size, we make sure the
9340        * left-hand side of the cell is visible).
9341        *
9342        * If the column does not have an activatable cell, we
9343        * make sure the left-hand side of the column is visible.
9344        */
9345
9346       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9347         {
9348           GtkCellArea *cell_area;
9349           GtkCellRenderer *focus_cell;
9350
9351           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9352           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9353
9354           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9355                                                       &x, &width))
9356             {
9357               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9358                 {
9359                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9360                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9361                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9362                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9363                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9364                 }
9365             }
9366         }
9367
9368       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9369     }
9370   else
9371     {
9372       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9373           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9374                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9375       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9376         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9377   }
9378 }
9379
9380 /* This function could be more efficient.  I'll optimize it if profiling seems
9381  * to imply that it is important */
9382 GtkTreePath *
9383 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9384                           GtkRBTree   *tree,
9385                           GtkRBNode   *node)
9386 {
9387   GtkTreePath *path;
9388   GtkRBTree *tmp_tree;
9389   GtkRBNode *tmp_node, *last;
9390   gint count;
9391
9392   path = gtk_tree_path_new ();
9393
9394   g_return_val_if_fail (node != NULL, path);
9395   g_return_val_if_fail (node != tree->nil, path);
9396
9397   count = 1 + node->left->count;
9398
9399   last = node;
9400   tmp_node = node->parent;
9401   tmp_tree = tree;
9402   while (tmp_tree)
9403     {
9404       while (tmp_node != tmp_tree->nil)
9405         {
9406           if (tmp_node->right == last)
9407             count += 1 + tmp_node->left->count;
9408           last = tmp_node;
9409           tmp_node = tmp_node->parent;
9410         }
9411       gtk_tree_path_prepend_index (path, count - 1);
9412       last = tmp_tree->parent_node;
9413       tmp_tree = tmp_tree->parent_tree;
9414       if (last)
9415         {
9416           count = 1 + last->left->count;
9417           tmp_node = last->parent;
9418         }
9419     }
9420   return path;
9421 }
9422
9423 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9424  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9425  * both set to NULL.
9426  */
9427 gboolean
9428 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9429                           GtkTreePath  *path,
9430                           GtkRBTree   **tree,
9431                           GtkRBNode   **node)
9432 {
9433   GtkRBNode *tmpnode = NULL;
9434   GtkRBTree *tmptree = tree_view->priv->tree;
9435   gint *indices = gtk_tree_path_get_indices (path);
9436   gint depth = gtk_tree_path_get_depth (path);
9437   gint i = 0;
9438
9439   *node = NULL;
9440   *tree = NULL;
9441
9442   if (depth == 0 || tmptree == NULL)
9443     return FALSE;
9444   do
9445     {
9446       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9447       ++i;
9448       if (tmpnode == NULL)
9449         {
9450           *tree = NULL;
9451           *node = NULL;
9452           return FALSE;
9453         }
9454       if (i >= depth)
9455         {
9456           *tree = tmptree;
9457           *node = tmpnode;
9458           return FALSE;
9459         }
9460       *tree = tmptree;
9461       *node = tmpnode;
9462       tmptree = tmpnode->children;
9463       if (tmptree == NULL)
9464         return TRUE;
9465     }
9466   while (1);
9467 }
9468
9469 static gboolean
9470 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9471                                   GtkTreeViewColumn *column)
9472 {
9473   GList *list;
9474
9475   if (tree_view->priv->is_list)
9476     return FALSE;
9477
9478   if (tree_view->priv->expander_column != NULL)
9479     {
9480       if (tree_view->priv->expander_column == column)
9481         return TRUE;
9482       return FALSE;
9483     }
9484   else
9485     {
9486       for (list = tree_view->priv->columns;
9487            list;
9488            list = list->next)
9489         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9490           break;
9491       if (list && list->data == column)
9492         return TRUE;
9493     }
9494   return FALSE;
9495 }
9496
9497 static inline gboolean
9498 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9499 {
9500   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9501     return TRUE;
9502   /* else */
9503   return FALSE;
9504 }
9505
9506 static void
9507 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9508                                 guint           keyval,
9509                                 guint           modmask,
9510                                 gboolean        add_shifted_binding,
9511                                 GtkMovementStep step,
9512                                 gint            count)
9513 {
9514   
9515   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9516                                 "move-cursor", 2,
9517                                 G_TYPE_ENUM, step,
9518                                 G_TYPE_INT, count);
9519
9520   if (add_shifted_binding)
9521     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9522                                   "move-cursor", 2,
9523                                   G_TYPE_ENUM, step,
9524                                   G_TYPE_INT, count);
9525
9526   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9527    return;
9528
9529   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9530                                 "move-cursor", 2,
9531                                 G_TYPE_ENUM, step,
9532                                 G_TYPE_INT, count);
9533
9534   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9535                                 "move-cursor", 2,
9536                                 G_TYPE_ENUM, step,
9537                                 G_TYPE_INT, count);
9538 }
9539
9540 static gint
9541 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9542                                  GtkTreeIter  *iter,
9543                                  GtkRBTree    *tree,
9544                                  GtkRBNode    *node)
9545 {
9546   gint retval = FALSE;
9547   do
9548     {
9549       g_return_val_if_fail (node != NULL, FALSE);
9550
9551       if (node->children)
9552         {
9553           GtkTreeIter child;
9554           GtkRBTree *new_tree;
9555           GtkRBNode *new_node;
9556
9557           new_tree = node->children;
9558           new_node = new_tree->root;
9559
9560           while (new_node && new_node->left != new_tree->nil)
9561             new_node = new_node->left;
9562
9563           if (!gtk_tree_model_iter_children (model, &child, iter))
9564             return FALSE;
9565
9566           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9567         }
9568
9569       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9570         retval = TRUE;
9571       gtk_tree_model_unref_node (model, iter);
9572       node = _gtk_rbtree_next (tree, node);
9573     }
9574   while (gtk_tree_model_iter_next (model, iter));
9575
9576   return retval;
9577 }
9578
9579 static gint
9580 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9581                                               GtkRBTree   *tree)
9582 {
9583   GtkTreeIter iter;
9584   GtkTreePath *path;
9585   GtkRBNode *node;
9586   gint retval;
9587
9588   if (!tree)
9589     return FALSE;
9590
9591   node = tree->root;
9592   while (node && node->left != tree->nil)
9593     node = node->left;
9594
9595   g_return_val_if_fail (node != NULL, FALSE);
9596   path = _gtk_tree_view_find_path (tree_view, tree, node);
9597   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9598                            &iter, path);
9599   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9600   gtk_tree_path_free (path);
9601
9602   return retval;
9603 }
9604
9605 static void
9606 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9607                                     GtkTreeViewColumn *column)
9608 {
9609   GtkTreeViewColumn *left_column;
9610   GtkTreeViewColumn *cur_column = NULL;
9611   GtkTreeViewColumnReorder *reorder;
9612   gboolean rtl;
9613   GList *tmp_list;
9614   gint left;
9615
9616   /* We want to precalculate the motion list such that we know what column slots
9617    * are available.
9618    */
9619   left_column = NULL;
9620   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9621
9622   /* First, identify all possible drop spots */
9623   if (rtl)
9624     tmp_list = g_list_last (tree_view->priv->columns);
9625   else
9626     tmp_list = g_list_first (tree_view->priv->columns);
9627
9628   while (tmp_list)
9629     {
9630       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9631       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9632
9633       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9634         continue;
9635
9636       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9637       if (left_column != column && cur_column != column &&
9638           tree_view->priv->column_drop_func &&
9639           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9640         {
9641           left_column = cur_column;
9642           continue;
9643         }
9644       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9645       reorder->left_column = left_column;
9646       left_column = reorder->right_column = cur_column;
9647
9648       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9649     }
9650
9651   /* Add the last one */
9652   if (tree_view->priv->column_drop_func == NULL ||
9653       ((left_column != column) &&
9654        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9655     {
9656       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9657       reorder->left_column = left_column;
9658       reorder->right_column = NULL;
9659       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9660     }
9661
9662   /* We quickly check to see if it even makes sense to reorder columns. */
9663   /* If there is nothing that can be moved, then we return */
9664
9665   if (tree_view->priv->column_drag_info == NULL)
9666     return;
9667
9668   /* We know there are always 2 slots possbile, as you can always return column. */
9669   /* If that's all there is, return */
9670   if (tree_view->priv->column_drag_info->next == NULL || 
9671       (tree_view->priv->column_drag_info->next->next == NULL &&
9672        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9673        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9674     {
9675       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9676         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9677       g_list_free (tree_view->priv->column_drag_info);
9678       tree_view->priv->column_drag_info = NULL;
9679       return;
9680     }
9681   /* We fill in the ranges for the columns, now that we've isolated them */
9682   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9683
9684   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9685     {
9686       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9687
9688       reorder->left_align = left;
9689       if (tmp_list->next != NULL)
9690         {
9691           GtkAllocation right_allocation, left_allocation;
9692           GtkWidget    *left_button, *right_button;
9693
9694           g_assert (tmp_list->next->data);
9695
9696           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9697           left_button  = gtk_tree_view_column_get_button
9698             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9699
9700           gtk_widget_get_allocation (right_button, &right_allocation);
9701           gtk_widget_get_allocation (left_button, &left_allocation);
9702           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9703         }
9704       else
9705         {
9706           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9707                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9708         }
9709     }
9710 }
9711
9712 void
9713 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9714                                   GtkTreeViewColumn *column,
9715                                   GdkDevice         *device)
9716 {
9717   GdkEvent *send_event;
9718   GtkAllocation allocation;
9719   GtkAllocation button_allocation;
9720   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9721   GtkWidget *button;
9722   GdkDevice *pointer, *keyboard;
9723
9724   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9725   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9726
9727   gtk_tree_view_set_column_drag_info (tree_view, column);
9728
9729   if (tree_view->priv->column_drag_info == NULL)
9730     return;
9731
9732   button = gtk_tree_view_column_get_button (column);
9733
9734   if (tree_view->priv->drag_window == NULL)
9735     {
9736       GdkWindowAttr attributes;
9737       guint attributes_mask;
9738
9739       gtk_widget_get_allocation (button, &button_allocation);
9740
9741       attributes.window_type = GDK_WINDOW_CHILD;
9742       attributes.wclass = GDK_INPUT_OUTPUT;
9743       attributes.x = button_allocation.x;
9744       attributes.y = 0;
9745       attributes.width = button_allocation.width;
9746       attributes.height = button_allocation.height;
9747       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9748       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9749       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9750
9751       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9752                                                      &attributes,
9753                                                      attributes_mask);
9754       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9755     }
9756
9757   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9758     {
9759       keyboard = device;
9760       pointer = gdk_device_get_associated_device (device);
9761     }
9762   else
9763     {
9764       pointer = device;
9765       keyboard = gdk_device_get_associated_device (device);
9766     }
9767
9768   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9769   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9770
9771   gtk_grab_remove (button);
9772
9773   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9774   send_event->crossing.send_event = TRUE;
9775   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9776   send_event->crossing.subwindow = NULL;
9777   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9778   send_event->crossing.time = GDK_CURRENT_TIME;
9779   gdk_event_set_device (send_event, device);
9780
9781   gtk_propagate_event (button, send_event);
9782   gdk_event_free (send_event);
9783
9784   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9785   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9786   send_event->button.send_event = TRUE;
9787   send_event->button.time = GDK_CURRENT_TIME;
9788   send_event->button.x = -1;
9789   send_event->button.y = -1;
9790   send_event->button.axes = NULL;
9791   send_event->button.state = 0;
9792   send_event->button.button = 1;
9793   send_event->button.x_root = 0;
9794   send_event->button.y_root = 0;
9795   gdk_event_set_device (send_event, device);
9796
9797   gtk_propagate_event (button, send_event);
9798   gdk_event_free (send_event);
9799
9800   /* Kids, don't try this at home */
9801   g_object_ref (button);
9802   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9803   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9804   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9805   g_object_unref (button);
9806
9807   gtk_widget_get_allocation (button, &button_allocation);
9808   tree_view->priv->drag_column_x = button_allocation.x;
9809   allocation = button_allocation;
9810   allocation.x = 0;
9811   gtk_widget_size_allocate (button, &allocation);
9812   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9813
9814   tree_view->priv->drag_column = column;
9815   gdk_window_show (tree_view->priv->drag_window);
9816
9817   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9818   while (gtk_events_pending ())
9819     gtk_main_iteration ();
9820
9821   tree_view->priv->in_column_drag = TRUE;
9822
9823   gdk_device_grab (pointer,
9824                    tree_view->priv->drag_window,
9825                    GDK_OWNERSHIP_NONE,
9826                    FALSE,
9827                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9828                    NULL,
9829                    GDK_CURRENT_TIME);
9830   gdk_device_grab (keyboard,
9831                    tree_view->priv->drag_window,
9832                    GDK_OWNERSHIP_NONE,
9833                    FALSE,
9834                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9835                    NULL,
9836                    GDK_CURRENT_TIME);
9837 }
9838
9839 static void
9840 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9841                                 GtkRBTree          *tree,
9842                                 GtkRBNode          *node)
9843 {
9844   GtkAllocation allocation;
9845   GdkRectangle rect;
9846
9847   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9848     return;
9849
9850   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9851   rect.x = 0;
9852   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9853
9854   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9855   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9856
9857   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9858 }
9859
9860 void
9861 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9862                                 GtkRBTree          *tree,
9863                                 GtkRBNode          *node,
9864                                 const GdkRectangle *clip_rect)
9865 {
9866   GtkAllocation allocation;
9867   GdkRectangle rect;
9868
9869   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9870     return;
9871
9872   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9873   rect.x = 0;
9874   rect.width = MAX (tree_view->priv->width, allocation.width);
9875
9876   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9877   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9878
9879   if (clip_rect)
9880     {
9881       GdkRectangle new_rect;
9882
9883       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9884
9885       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9886     }
9887   else
9888     {
9889       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9890     }
9891 }
9892
9893 static inline gint
9894 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9895 {
9896   if (tree_view->priv->headers_visible)
9897     return tree_view->priv->header_height;
9898   /* else */
9899   return 0;
9900 }
9901
9902 gint
9903 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9904 {
9905   return tree_view->priv->header_height;
9906 }
9907
9908 void
9909 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9910                                        GtkTreeViewRowSeparatorFunc *func,
9911                                        gpointer                    *data)
9912 {
9913   *func = tree_view->priv->row_separator_func;
9914   *data = tree_view->priv->row_separator_data;
9915 }
9916
9917 GtkTreePath *
9918 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9919 {
9920   if (tree_view->priv->anchor)
9921     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9922
9923   return NULL;
9924 }
9925
9926 void
9927 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9928                                 GtkTreePath *anchor_path)
9929 {
9930   if (tree_view->priv->anchor)
9931     {
9932       gtk_tree_row_reference_free (tree_view->priv->anchor);
9933       tree_view->priv->anchor = NULL;
9934     }
9935
9936   if (anchor_path && tree_view->priv->model)
9937     tree_view->priv->anchor =
9938       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
9939                                         tree_view->priv->model, anchor_path);
9940 }
9941
9942 GtkRBTree *
9943 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
9944 {
9945   return tree_view->priv->tree;
9946 }
9947
9948 GdkWindow *
9949 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
9950 {
9951   return tree_view->priv->header_window;
9952 }
9953
9954 void
9955 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
9956                                  GtkTreeViewColumn *column)
9957 {
9958   tree_view->priv->focus_column = column;
9959 }
9960
9961
9962 static void
9963 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9964                                GtkTreePath        *path,
9965                                const GdkRectangle *clip_rect)
9966 {
9967   GtkRBTree *tree = NULL;
9968   GtkRBNode *node = NULL;
9969
9970   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9971
9972   if (tree)
9973     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9974 }
9975
9976 /* x and y are the mouse position
9977  */
9978 static void
9979 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9980                           cairo_t     *cr,
9981                           GtkRBTree   *tree,
9982                           GtkRBNode   *node,
9983                           /* in bin_window coordinates */
9984                           gint         x,
9985                           gint         y)
9986 {
9987   GdkRectangle area;
9988   GtkStateType state;
9989   GtkWidget *widget;
9990   gint x_offset = 0;
9991   gint x2;
9992   gint vertical_separator;
9993   gint expander_size;
9994   GtkExpanderStyle expander_style;
9995
9996   widget = GTK_WIDGET (tree_view);
9997
9998   gtk_widget_style_get (widget,
9999                         "vertical-separator", &vertical_separator,
10000                         NULL);
10001   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
10002
10003   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
10004     return;
10005
10006   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
10007
10008   area.x = x_offset;
10009   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
10010                                                  vertical_separator);
10011   area.width = expander_size + 2;
10012   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10013                                                     vertical_separator);
10014
10015   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
10016     {
10017       state = GTK_STATE_INSENSITIVE;
10018     }
10019   else if (node == tree_view->priv->button_pressed_node)
10020     {
10021       if (x >= area.x && x <= (area.x + area.width) &&
10022           y >= area.y && y <= (area.y + area.height))
10023         state = GTK_STATE_ACTIVE;
10024       else
10025         state = GTK_STATE_NORMAL;
10026     }
10027   else
10028     {
10029       if (node == tree_view->priv->prelight_node &&
10030           tree_view->priv->arrow_prelit)
10031         state = GTK_STATE_PRELIGHT;
10032       else
10033         state = GTK_STATE_NORMAL;
10034     }
10035
10036   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
10037     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
10038   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
10039     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
10040   else if (node->children != NULL)
10041     expander_style = GTK_EXPANDER_EXPANDED;
10042   else
10043     expander_style = GTK_EXPANDER_COLLAPSED;
10044
10045   gtk_paint_expander (gtk_widget_get_style (widget),
10046                       cr,
10047                       state,
10048                       widget,
10049                       "treeview",
10050                       area.x + area.width / 2,
10051                       area.y + area.height / 2,
10052                       expander_style);
10053 }
10054
10055 static void
10056 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10057
10058 {
10059   GtkTreePath *cursor_path;
10060
10061   if ((tree_view->priv->tree == NULL) ||
10062       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10063     return;
10064
10065   cursor_path = NULL;
10066   if (tree_view->priv->cursor)
10067     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10068
10069   if (cursor_path == NULL)
10070     {
10071       /* Consult the selection before defaulting to the
10072        * first focusable element
10073        */
10074       GList *selected_rows;
10075       GtkTreeModel *model;
10076       GtkTreeSelection *selection;
10077
10078       selection = gtk_tree_view_get_selection (tree_view);
10079       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10080
10081       if (selected_rows)
10082         {
10083           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10084           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
10085           g_list_free (selected_rows);
10086         }
10087       else
10088         {
10089           cursor_path = gtk_tree_path_new_first ();
10090           search_first_focusable_path (tree_view, &cursor_path,
10091                                        TRUE, NULL, NULL);
10092         }
10093
10094       gtk_tree_row_reference_free (tree_view->priv->cursor);
10095       tree_view->priv->cursor = NULL;
10096
10097       if (cursor_path)
10098         {
10099           if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10100             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
10101           else
10102             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10103         }
10104     }
10105
10106   if (cursor_path)
10107     {
10108       tree_view->priv->draw_keyfocus = TRUE;
10109
10110       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10111       gtk_tree_path_free (cursor_path);
10112
10113       if (tree_view->priv->focus_column == NULL)
10114         {
10115           GList *list;
10116           for (list = tree_view->priv->columns; list; list = list->next)
10117             {
10118               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10119                 {
10120                   GtkCellArea *cell_area;
10121
10122                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
10123
10124                   /* This happens when the treeview initially grabs focus and there
10125                    * is no column in focus, here we explicitly focus into the first cell */
10126                   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10127                   if (!gtk_cell_area_get_focus_cell (cell_area))
10128                     {
10129                       gboolean rtl;
10130
10131                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10132                       gtk_cell_area_focus (cell_area,
10133                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10134                     }
10135
10136                   break;
10137                 }
10138             }
10139         }
10140     }
10141 }
10142
10143 static void
10144 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10145                                    gint         count)
10146 {
10147   gint selection_count;
10148   GtkRBTree *cursor_tree = NULL;
10149   GtkRBNode *cursor_node = NULL;
10150   GtkRBTree *new_cursor_tree = NULL;
10151   GtkRBNode *new_cursor_node = NULL;
10152   GtkTreePath *cursor_path = NULL;
10153   gboolean grab_focus = TRUE;
10154   gboolean selectable;
10155   GtkDirectionType direction;
10156   GtkCellArea *cell_area = NULL;
10157   GtkCellRenderer *last_focus_cell = NULL;
10158   GtkTreeIter iter;
10159
10160   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10161     return;
10162
10163   cursor_path = NULL;
10164   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
10165     /* FIXME: we lost the cursor; should we get the first? */
10166     return;
10167
10168   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10169   _gtk_tree_view_find_node (tree_view, cursor_path,
10170                             &cursor_tree, &cursor_node);
10171
10172   if (cursor_tree == NULL)
10173     /* FIXME: we lost the cursor; should we get the first? */
10174     return;
10175
10176   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10177
10178   if (tree_view->priv->focus_column)
10179     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10180
10181   /* If focus stays in the area for this row, then just return for this round */
10182   if (cell_area && (count == -1 || count == 1) &&
10183       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10184     {
10185       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10186                                                tree_view->priv->model,
10187                                                &iter,
10188                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10189                                                cursor_node->children?TRUE:FALSE);
10190
10191       /* Save the last cell that had focus, if we hit the end of the view we'll give
10192        * focus back to it. */
10193       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10194
10195       /* If focus stays in the area, no need to change the cursor row */
10196       if (gtk_cell_area_focus (cell_area, direction))
10197         return;
10198     }
10199
10200   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10201   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10202                                                       cursor_node,
10203                                                       cursor_path);
10204
10205   if (selection_count == 0
10206       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10207       && !tree_view->priv->ctrl_pressed
10208       && selectable)
10209     {
10210       /* Don't move the cursor, but just select the current node */
10211       new_cursor_tree = cursor_tree;
10212       new_cursor_node = cursor_node;
10213     }
10214   else
10215     {
10216       if (count == -1)
10217         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10218                                &new_cursor_tree, &new_cursor_node);
10219       else
10220         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10221                                &new_cursor_tree, &new_cursor_node);
10222     }
10223
10224   gtk_tree_path_free (cursor_path);
10225
10226   if (new_cursor_node)
10227     {
10228       cursor_path = _gtk_tree_view_find_path (tree_view,
10229                                               new_cursor_tree, new_cursor_node);
10230
10231       search_first_focusable_path (tree_view, &cursor_path,
10232                                    (count != -1),
10233                                    &new_cursor_tree,
10234                                    &new_cursor_node);
10235
10236       if (cursor_path)
10237         gtk_tree_path_free (cursor_path);
10238     }
10239
10240   /*
10241    * If the list has only one item and multi-selection is set then select
10242    * the row (if not yet selected).
10243    */
10244   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10245       new_cursor_node == NULL)
10246     {
10247       if (count == -1)
10248         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10249                                &new_cursor_tree, &new_cursor_node);
10250       else
10251         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10252                                &new_cursor_tree, &new_cursor_node);
10253
10254       if (new_cursor_node == NULL
10255           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
10256         {
10257           new_cursor_node = cursor_node;
10258           new_cursor_tree = cursor_tree;
10259         }
10260       else
10261         {
10262           new_cursor_node = NULL;
10263         }
10264     }
10265
10266   if (new_cursor_node)
10267     {
10268       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
10269       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
10270       gtk_tree_path_free (cursor_path);
10271
10272       /* Give focus to the area in the new row */
10273       if (cell_area)
10274         gtk_cell_area_focus (cell_area, direction);
10275     }
10276   else
10277     {
10278       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10279
10280       if (!tree_view->priv->shift_pressed)
10281         {
10282           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10283                                           count < 0 ?
10284                                           GTK_DIR_UP : GTK_DIR_DOWN))
10285             {
10286               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10287
10288               if (toplevel)
10289                 gtk_widget_child_focus (toplevel,
10290                                         count < 0 ?
10291                                         GTK_DIR_TAB_BACKWARD :
10292                                         GTK_DIR_TAB_FORWARD);
10293
10294               grab_focus = FALSE;
10295             }
10296         }
10297       else
10298         {
10299           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10300         }
10301
10302       if (cell_area)
10303         gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10304     }
10305
10306   if (grab_focus)
10307     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10308 }
10309
10310 static void
10311 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10312                                         gint         count)
10313 {
10314   GtkRBTree *cursor_tree = NULL;
10315   GtkRBNode *cursor_node = NULL;
10316   GtkTreePath *old_cursor_path = NULL;
10317   GtkTreePath *cursor_path = NULL;
10318   GtkRBTree *start_cursor_tree = NULL;
10319   GtkRBNode *start_cursor_node = NULL;
10320   gint y;
10321   gint window_y;
10322   gint vertical_separator;
10323
10324   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10325     return;
10326
10327   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10328     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10329   else
10330     /* This is sorta weird.  Focus in should give us a cursor */
10331     return;
10332
10333   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10334   _gtk_tree_view_find_node (tree_view, old_cursor_path,
10335                             &cursor_tree, &cursor_node);
10336
10337   if (cursor_tree == NULL)
10338     {
10339       /* FIXME: we lost the cursor.  Should we try to get one? */
10340       gtk_tree_path_free (old_cursor_path);
10341       return;
10342     }
10343   g_return_if_fail (cursor_node != NULL);
10344
10345   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10346   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10347   y += tree_view->priv->cursor_offset;
10348   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10349   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10350
10351   if (y >= tree_view->priv->height)
10352     y = tree_view->priv->height - 1;
10353
10354   tree_view->priv->cursor_offset =
10355     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10356                              &cursor_tree, &cursor_node);
10357
10358   if (cursor_tree == NULL)
10359     {
10360       /* FIXME: we lost the cursor.  Should we try to get one? */
10361       gtk_tree_path_free (old_cursor_path);
10362       return;
10363     }
10364
10365   if (tree_view->priv->cursor_offset
10366       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10367     {
10368       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10369                              &cursor_tree, &cursor_node);
10370       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10371     }
10372
10373   y -= tree_view->priv->cursor_offset;
10374   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10375
10376   start_cursor_tree = cursor_tree;
10377   start_cursor_node = cursor_node;
10378
10379   if (! search_first_focusable_path (tree_view, &cursor_path,
10380                                      (count != -1),
10381                                      &cursor_tree, &cursor_node))
10382     {
10383       /* It looks like we reached the end of the view without finding
10384        * a focusable row.  We will step backwards to find the last
10385        * focusable row.
10386        */
10387       cursor_tree = start_cursor_tree;
10388       cursor_node = start_cursor_node;
10389       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10390
10391       search_first_focusable_path (tree_view, &cursor_path,
10392                                    (count == -1),
10393                                    &cursor_tree, &cursor_node);
10394     }
10395
10396   if (!cursor_path)
10397     goto cleanup;
10398
10399   /* update y */
10400   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10401
10402   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10403
10404   y -= window_y;
10405   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10406   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10407   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10408
10409   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10410     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10411
10412   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10413
10414 cleanup:
10415   gtk_tree_path_free (old_cursor_path);
10416   gtk_tree_path_free (cursor_path);
10417 }
10418
10419 static void
10420 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10421                                       gint         count)
10422 {
10423   GtkRBTree *cursor_tree = NULL;
10424   GtkRBNode *cursor_node = NULL;
10425   GtkTreePath *cursor_path = NULL;
10426   GtkTreeViewColumn *column;
10427   GtkTreeIter iter;
10428   GList *list;
10429   gboolean found_column = FALSE;
10430   gboolean rtl;
10431   GtkDirectionType direction;
10432   GtkCellArea     *cell_area;
10433   GtkCellRenderer *last_focus_cell = NULL;
10434   GtkCellArea     *last_focus_area = NULL;
10435
10436   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10437
10438   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10439     return;
10440
10441   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10442     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10443   else
10444     return;
10445
10446   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
10447   if (cursor_tree == NULL)
10448     return;
10449   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10450     {
10451       gtk_tree_path_free (cursor_path);
10452       return;
10453     }
10454   gtk_tree_path_free (cursor_path);
10455
10456   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10457   if (tree_view->priv->focus_column)
10458     {
10459       /* Save the cell/area we are moving focus from, if moving the cursor
10460        * by one step hits the end we'll set focus back here */
10461       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10462       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10463
10464       for (; list; list = (rtl ? list->prev : list->next))
10465         {
10466           if (list->data == tree_view->priv->focus_column)
10467             break;
10468         }
10469     }
10470
10471   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10472
10473   while (list)
10474     {
10475       column = list->data;
10476       if (gtk_tree_view_column_get_visible (column) == FALSE)
10477         goto loop_end;
10478
10479       gtk_tree_view_column_cell_set_cell_data (column,
10480                                                tree_view->priv->model,
10481                                                &iter,
10482                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10483                                                cursor_node->children?TRUE:FALSE);
10484
10485       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10486       if (gtk_cell_area_focus (cell_area, direction))
10487         {
10488           tree_view->priv->focus_column = column;
10489           found_column = TRUE;
10490           break;
10491         }
10492
10493     loop_end:
10494       if (count == 1)
10495         list = rtl ? list->prev : list->next;
10496       else
10497         list = rtl ? list->next : list->prev;
10498     }
10499
10500   if (found_column)
10501     {
10502       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10503         _gtk_tree_view_queue_draw_node (tree_view,
10504                                         cursor_tree,
10505                                         cursor_node,
10506                                         NULL);
10507       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10508       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10509     }
10510   else
10511     {
10512       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10513
10514       if (last_focus_area)
10515         gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10516     }
10517
10518   gtk_tree_view_clamp_column_visible (tree_view,
10519                                       tree_view->priv->focus_column, TRUE);
10520 }
10521
10522 static void
10523 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10524                                      gint         count)
10525 {
10526   GtkRBTree *cursor_tree;
10527   GtkRBNode *cursor_node;
10528   GtkTreePath *path;
10529   GtkTreePath *old_path;
10530
10531   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10532     return;
10533
10534   g_return_if_fail (tree_view->priv->tree != NULL);
10535
10536   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10537
10538   cursor_tree = tree_view->priv->tree;
10539   cursor_node = cursor_tree->root;
10540
10541   if (count == -1)
10542     {
10543       while (cursor_node && cursor_node->left != cursor_tree->nil)
10544         cursor_node = cursor_node->left;
10545
10546       /* Now go forward to find the first focusable row. */
10547       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10548       search_first_focusable_path (tree_view, &path,
10549                                    TRUE, &cursor_tree, &cursor_node);
10550     }
10551   else
10552     {
10553       do
10554         {
10555           while (cursor_node && cursor_node->right != cursor_tree->nil)
10556             cursor_node = cursor_node->right;
10557           if (cursor_node->children == NULL)
10558             break;
10559
10560           cursor_tree = cursor_node->children;
10561           cursor_node = cursor_tree->root;
10562         }
10563       while (1);
10564
10565       /* Now go backwards to find last focusable row. */
10566       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10567       search_first_focusable_path (tree_view, &path,
10568                                    FALSE, &cursor_tree, &cursor_node);
10569     }
10570
10571   if (!path)
10572     goto cleanup;
10573
10574   if (gtk_tree_path_compare (old_path, path))
10575     {
10576       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10577       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10578     }
10579   else
10580     {
10581       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10582     }
10583
10584 cleanup:
10585   gtk_tree_path_free (old_path);
10586   gtk_tree_path_free (path);
10587 }
10588
10589 static gboolean
10590 gtk_tree_view_real_select_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_select_all (tree_view->priv->selection);
10599
10600   return TRUE;
10601 }
10602
10603 static gboolean
10604 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10605 {
10606   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10607     return FALSE;
10608
10609   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10610     return FALSE;
10611
10612   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10613
10614   return TRUE;
10615 }
10616
10617 static gboolean
10618 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10619                                       gboolean     start_editing)
10620 {
10621   GtkRBTree *new_tree = NULL;
10622   GtkRBNode *new_node = NULL;
10623   GtkRBTree *cursor_tree = NULL;
10624   GtkRBNode *cursor_node = NULL;
10625   GtkTreePath *cursor_path = NULL;
10626   GtkTreeSelectMode mode = 0;
10627
10628   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10629     return FALSE;
10630
10631   if (tree_view->priv->cursor)
10632     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10633
10634   if (cursor_path == NULL)
10635     return FALSE;
10636
10637   _gtk_tree_view_find_node (tree_view, cursor_path,
10638                             &cursor_tree, &cursor_node);
10639
10640   if (cursor_tree == NULL)
10641     {
10642       gtk_tree_path_free (cursor_path);
10643       return FALSE;
10644     }
10645
10646   if (!tree_view->priv->shift_pressed && start_editing &&
10647       tree_view->priv->focus_column)
10648     {
10649       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10650         {
10651           gtk_tree_path_free (cursor_path);
10652           return TRUE;
10653         }
10654     }
10655
10656   if (tree_view->priv->ctrl_pressed)
10657     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10658   if (tree_view->priv->shift_pressed)
10659     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10660
10661   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10662                                             cursor_node,
10663                                             cursor_tree,
10664                                             cursor_path,
10665                                             mode,
10666                                             FALSE);
10667
10668   /* We bail out if the original (tree, node) don't exist anymore after
10669    * handling the selection-changed callback.  We do return TRUE because
10670    * the key press has been handled at this point.
10671    */
10672   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10673
10674   if (cursor_tree != new_tree || cursor_node != new_node)
10675     return FALSE;
10676
10677   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10678
10679   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10680   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10681
10682   if (!tree_view->priv->shift_pressed)
10683     gtk_tree_view_row_activated (tree_view, cursor_path,
10684                                  tree_view->priv->focus_column);
10685     
10686   gtk_tree_path_free (cursor_path);
10687
10688   return TRUE;
10689 }
10690
10691 static gboolean
10692 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10693 {
10694   GtkRBTree *new_tree = NULL;
10695   GtkRBNode *new_node = NULL;
10696   GtkRBTree *cursor_tree = NULL;
10697   GtkRBNode *cursor_node = NULL;
10698   GtkTreePath *cursor_path = NULL;
10699
10700   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10701     return FALSE;
10702
10703   cursor_path = NULL;
10704   if (tree_view->priv->cursor)
10705     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10706
10707   if (cursor_path == NULL)
10708     return FALSE;
10709
10710   _gtk_tree_view_find_node (tree_view, cursor_path,
10711                             &cursor_tree, &cursor_node);
10712   if (cursor_tree == NULL)
10713     {
10714       gtk_tree_path_free (cursor_path);
10715       return FALSE;
10716     }
10717
10718   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10719                                             cursor_node,
10720                                             cursor_tree,
10721                                             cursor_path,
10722                                             GTK_TREE_SELECT_MODE_TOGGLE,
10723                                             FALSE);
10724
10725   /* We bail out if the original (tree, node) don't exist anymore after
10726    * handling the selection-changed callback.  We do return TRUE because
10727    * the key press has been handled at this point.
10728    */
10729   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10730
10731   if (cursor_tree != new_tree || cursor_node != new_node)
10732     return FALSE;
10733
10734   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10735
10736   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10737   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10738   gtk_tree_path_free (cursor_path);
10739
10740   return TRUE;
10741 }
10742
10743 static gboolean
10744 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10745                                                gboolean     logical,
10746                                                gboolean     expand,
10747                                                gboolean     open_all)
10748 {
10749   GtkTreePath *cursor_path = NULL;
10750   GtkRBTree *tree;
10751   GtkRBNode *node;
10752
10753   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10754     return FALSE;
10755
10756   cursor_path = NULL;
10757   if (tree_view->priv->cursor)
10758     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10759
10760   if (cursor_path == NULL)
10761     return FALSE;
10762
10763   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10764     return FALSE;
10765
10766   /* Don't handle the event if we aren't an expander */
10767   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10768     return FALSE;
10769
10770   if (!logical
10771       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10772     expand = !expand;
10773
10774   if (expand)
10775     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10776   else
10777     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10778
10779   gtk_tree_path_free (cursor_path);
10780
10781   return TRUE;
10782 }
10783
10784 static gboolean
10785 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10786 {
10787   GtkRBTree *cursor_tree = NULL;
10788   GtkRBNode *cursor_node = NULL;
10789   GtkTreePath *cursor_path = NULL;
10790   GdkModifierType state;
10791
10792   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10793     goto out;
10794
10795   cursor_path = NULL;
10796   if (tree_view->priv->cursor)
10797     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10798
10799   if (cursor_path == NULL)
10800     goto out;
10801
10802   _gtk_tree_view_find_node (tree_view, cursor_path,
10803                             &cursor_tree, &cursor_node);
10804   if (cursor_tree == NULL)
10805     {
10806       gtk_tree_path_free (cursor_path);
10807       goto out;
10808     }
10809
10810   if (cursor_tree->parent_node)
10811     {
10812       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10813       cursor_node = cursor_tree->parent_node;
10814       cursor_tree = cursor_tree->parent_tree;
10815
10816       gtk_tree_path_up (cursor_path);
10817
10818       if (gtk_get_current_event_state (&state))
10819         {
10820           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10821             tree_view->priv->ctrl_pressed = TRUE;
10822         }
10823
10824       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10825       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10826
10827       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10828       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10829       gtk_tree_path_free (cursor_path);
10830
10831       tree_view->priv->ctrl_pressed = FALSE;
10832
10833       return TRUE;
10834     }
10835
10836  out:
10837
10838   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10839   return FALSE;
10840 }
10841
10842 static gboolean
10843 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10844 {
10845   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10846   tree_view->priv->typeselect_flush_timeout = 0;
10847
10848   return FALSE;
10849 }
10850
10851 /* Cut and paste from gtkwindow.c */
10852 static void
10853 send_focus_change (GtkWidget *widget,
10854                    GdkDevice *device,
10855                    gboolean   in)
10856 {
10857   GdkDeviceManager *device_manager;
10858   GList *devices, *d;
10859
10860   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10861   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10862   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10863   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10864
10865   for (d = devices; d; d = d->next)
10866     {
10867       GdkDevice *dev = d->data;
10868       GdkEvent *fevent;
10869       GdkWindow *window;
10870
10871       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10872         continue;
10873
10874       window = gtk_widget_get_window (widget);
10875
10876       /* Skip non-master keyboards that haven't
10877        * selected for events from this window
10878        */
10879       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10880           !gdk_window_get_device_events (window, dev))
10881         continue;
10882
10883       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10884
10885       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10886       fevent->focus_change.window = g_object_ref (window);
10887       fevent->focus_change.in = in;
10888       gdk_event_set_device (fevent, device);
10889
10890       gtk_widget_send_focus_change (widget, fevent);
10891
10892       gdk_event_free (fevent);
10893     }
10894 }
10895
10896 static void
10897 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10898 {
10899   GtkWidget *frame, *vbox, *toplevel;
10900   GdkScreen *screen;
10901
10902   if (tree_view->priv->search_custom_entry_set)
10903     return;
10904
10905   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10906   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10907
10908    if (tree_view->priv->search_window != NULL)
10909      {
10910        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10911          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10912                                       GTK_WINDOW (tree_view->priv->search_window));
10913        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10914          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10915                                          GTK_WINDOW (tree_view->priv->search_window));
10916
10917        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10918
10919        return;
10920      }
10921    
10922   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10923   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10924
10925   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10926     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10927                                  GTK_WINDOW (tree_view->priv->search_window));
10928
10929   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10930                             GDK_WINDOW_TYPE_HINT_UTILITY);
10931   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10932   g_signal_connect (tree_view->priv->search_window, "delete-event",
10933                     G_CALLBACK (gtk_tree_view_search_delete_event),
10934                     tree_view);
10935   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10936                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10937                     tree_view);
10938   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10939                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10940                     tree_view);
10941   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10942                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10943                     tree_view);
10944
10945   frame = gtk_frame_new (NULL);
10946   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10947   gtk_widget_show (frame);
10948   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10949
10950   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10951   gtk_widget_show (vbox);
10952   gtk_container_add (GTK_CONTAINER (frame), vbox);
10953   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10954
10955   /* add entry */
10956   tree_view->priv->search_entry = gtk_entry_new ();
10957   gtk_widget_show (tree_view->priv->search_entry);
10958   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10959                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10960                     tree_view);
10961   g_signal_connect (tree_view->priv->search_entry,
10962                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10963                     tree_view);
10964
10965   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
10966                     "preedit-changed",
10967                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10968                     tree_view);
10969
10970   gtk_container_add (GTK_CONTAINER (vbox),
10971                      tree_view->priv->search_entry);
10972
10973   gtk_widget_realize (tree_view->priv->search_entry);
10974 }
10975
10976 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10977  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10978  */
10979 static gboolean
10980 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10981                                              GdkDevice   *device,
10982                                              gboolean     keybinding)
10983 {
10984   /* We only start interactive search if we have focus or the columns
10985    * have focus.  If one of our children have focus, we don't want to
10986    * start the search.
10987    */
10988   GList *list;
10989   gboolean found_focus = FALSE;
10990   GtkWidgetClass *entry_parent_class;
10991   
10992   if (!tree_view->priv->enable_search && !keybinding)
10993     return FALSE;
10994
10995   if (tree_view->priv->search_custom_entry_set)
10996     return FALSE;
10997
10998   if (tree_view->priv->search_window != NULL &&
10999       gtk_widget_get_visible (tree_view->priv->search_window))
11000     return TRUE;
11001
11002   for (list = tree_view->priv->columns; list; list = list->next)
11003     {
11004       GtkTreeViewColumn *column;
11005       GtkWidget         *button;
11006
11007       column = list->data;
11008       if (!gtk_tree_view_column_get_visible (column))
11009         continue;
11010
11011       button = gtk_tree_view_column_get_button (column);
11012       if (gtk_widget_has_focus (button))
11013         {
11014           found_focus = TRUE;
11015           break;
11016         }
11017     }
11018   
11019   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11020     found_focus = TRUE;
11021
11022   if (!found_focus)
11023     return FALSE;
11024
11025   if (tree_view->priv->search_column < 0)
11026     return FALSE;
11027
11028   gtk_tree_view_ensure_interactive_directory (tree_view);
11029
11030   if (keybinding)
11031     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11032
11033   /* done, show it */
11034   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11035   gtk_widget_show (tree_view->priv->search_window);
11036   if (tree_view->priv->search_entry_changed_id == 0)
11037     {
11038       tree_view->priv->search_entry_changed_id =
11039         g_signal_connect (tree_view->priv->search_entry, "changed",
11040                           G_CALLBACK (gtk_tree_view_search_init),
11041                           tree_view);
11042     }
11043
11044   tree_view->priv->typeselect_flush_timeout =
11045     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11046                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11047                    tree_view);
11048
11049   /* Grab focus will select all the text.  We don't want that to happen, so we
11050    * call the parent instance and bypass the selection change.  This is probably
11051    * really non-kosher. */
11052   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11053   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11054
11055   /* send focus-in event */
11056   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11057
11058   /* search first matching iter */
11059   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11060
11061   return TRUE;
11062 }
11063
11064 static gboolean
11065 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11066 {
11067   return gtk_tree_view_real_start_interactive_search (tree_view,
11068                                                       gtk_get_current_event_device (),
11069                                                       TRUE);
11070 }
11071
11072 /* this function returns the new width of the column being resized given
11073  * the column and x position of the cursor; the x cursor position is passed
11074  * in as a pointer and automagicly corrected if it's beyond min/max limits
11075  */
11076 static gint
11077 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11078                                 gint       i,
11079                                 gint      *x)
11080 {
11081   GtkAllocation allocation;
11082   GtkTreeViewColumn *column;
11083   GtkRequisition button_req;
11084   gint max_width, min_width;
11085   gint width;
11086   gboolean rtl;
11087
11088   /* first translate the x position from widget->window
11089    * to clist->clist_window
11090    */
11091   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11092   column = g_list_nth (tree_view->priv->columns, i)->data;
11093   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11094   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11095
11096   /* Clamp down the value */
11097   min_width = gtk_tree_view_column_get_min_width (column);
11098   if (min_width == -1)
11099     {
11100       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11101       width = MAX (button_req.width, width);
11102     }
11103   else
11104     width = MAX (min_width, width);
11105
11106   max_width = gtk_tree_view_column_get_max_width (column);
11107   if (max_width != -1)
11108     width = MIN (width, max_width);
11109
11110   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11111
11112   return width;
11113 }
11114
11115
11116 /* FIXME this adjust_allocation is a big cut-and-paste from
11117  * GtkCList, needs to be some "official" way to do this
11118  * factored out.
11119  */
11120 typedef struct
11121 {
11122   GdkWindow *window;
11123   int dx;
11124   int dy;
11125 } ScrollData;
11126
11127 /* The window to which widget->window is relative */
11128 #define ALLOCATION_WINDOW(widget)               \
11129    (!gtk_widget_get_has_window (widget) ?                   \
11130     gtk_widget_get_window (widget) :                        \
11131     gdk_window_get_parent (gtk_widget_get_window (widget)))
11132
11133 static void
11134 adjust_allocation_recurse (GtkWidget *widget,
11135                            gpointer   data)
11136 {
11137   GtkAllocation allocation;
11138   ScrollData *scroll_data = data;
11139
11140   /* Need to really size allocate instead of just poking
11141    * into widget->allocation if the widget is not realized.
11142    * FIXME someone figure out why this was.
11143    */
11144   gtk_widget_get_allocation (widget, &allocation);
11145   if (!gtk_widget_get_realized (widget))
11146     {
11147       if (gtk_widget_get_visible (widget))
11148         {
11149           GdkRectangle tmp_rectangle = allocation;
11150           tmp_rectangle.x += scroll_data->dx;
11151           tmp_rectangle.y += scroll_data->dy;
11152           
11153           gtk_widget_size_allocate (widget, &tmp_rectangle);
11154         }
11155     }
11156   else
11157     {
11158       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11159         {
11160           allocation.x += scroll_data->dx;
11161           allocation.y += scroll_data->dy;
11162           gtk_widget_set_allocation (widget, &allocation);
11163
11164           if (GTK_IS_CONTAINER (widget))
11165             gtk_container_forall (GTK_CONTAINER (widget),
11166                                   adjust_allocation_recurse,
11167                                   data);
11168         }
11169     }
11170 }
11171
11172 static void
11173 adjust_allocation (GtkWidget *widget,
11174                    int        dx,
11175                    int        dy)
11176 {
11177   ScrollData scroll_data;
11178
11179   if (gtk_widget_get_realized (widget))
11180     scroll_data.window = ALLOCATION_WINDOW (widget);
11181   else
11182     scroll_data.window = NULL;
11183     
11184   scroll_data.dx = dx;
11185   scroll_data.dy = dy;
11186   
11187   adjust_allocation_recurse (widget, &scroll_data);
11188 }
11189
11190 /* Callbacks */
11191 static void
11192 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11193                                   GtkTreeView   *tree_view)
11194 {
11195   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11196     {
11197       gint dy;
11198         
11199       gdk_window_move (tree_view->priv->bin_window,
11200                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11201                        gtk_tree_view_get_effective_header_height (tree_view));
11202       gdk_window_move (tree_view->priv->header_window,
11203                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11204                        0);
11205       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11206       if (dy)
11207         {
11208           update_prelight (tree_view,
11209                            tree_view->priv->event_last_x,
11210                            tree_view->priv->event_last_y - dy);
11211
11212           if (tree_view->priv->edited_column)
11213             {
11214               GList *list;
11215               GtkTreeViewChild *child = NULL;
11216               GtkCellEditable *edit_widget;
11217               GtkCellArea *area;
11218
11219               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11220               edit_widget = gtk_cell_area_get_edit_widget (area);
11221               if (GTK_IS_WIDGET (edit_widget))
11222                 {
11223                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11224
11225                   for (list = tree_view->priv->children; list; list = list->next)
11226                     {
11227                       child = (GtkTreeViewChild *)list->data;
11228                       if (child->widget == GTK_WIDGET (edit_widget))
11229                         {
11230                           child->y += dy;
11231                           break;
11232                         }
11233                     }
11234                 }
11235             }
11236         }
11237       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11238
11239       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11240         {
11241           /* update our dy and top_row */
11242           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11243
11244           if (!tree_view->priv->in_top_row_to_dy)
11245             gtk_tree_view_dy_to_top_row (tree_view);
11246         }
11247
11248       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
11249       gtk_tree_view_bin_process_updates (tree_view);
11250     }
11251 }
11252
11253 \f
11254
11255 /* Public methods
11256  */
11257
11258 /**
11259  * gtk_tree_view_new:
11260  *
11261  * Creates a new #GtkTreeView widget.
11262  *
11263  * Return value: A newly created #GtkTreeView widget.
11264  **/
11265 GtkWidget *
11266 gtk_tree_view_new (void)
11267 {
11268   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11269 }
11270
11271 /**
11272  * gtk_tree_view_new_with_model:
11273  * @model: the model.
11274  *
11275  * Creates a new #GtkTreeView widget with the model initialized to @model.
11276  *
11277  * Return value: A newly created #GtkTreeView widget.
11278  **/
11279 GtkWidget *
11280 gtk_tree_view_new_with_model (GtkTreeModel *model)
11281 {
11282   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11283 }
11284
11285 /* Public Accessors
11286  */
11287
11288 /**
11289  * gtk_tree_view_get_model:
11290  * @tree_view: a #GtkTreeView
11291  *
11292  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11293  * model is unset.
11294  *
11295  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11296  **/
11297 GtkTreeModel *
11298 gtk_tree_view_get_model (GtkTreeView *tree_view)
11299 {
11300   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11301
11302   return tree_view->priv->model;
11303 }
11304
11305 /**
11306  * gtk_tree_view_set_model:
11307  * @tree_view: A #GtkTreeNode.
11308  * @model: (allow-none): The model.
11309  *
11310  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11311  * set, it will remove it before setting the new model.  If @model is %NULL,
11312  * then it will unset the old model.
11313  **/
11314 void
11315 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11316                          GtkTreeModel *model)
11317 {
11318   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11319   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11320
11321   if (model == tree_view->priv->model)
11322     return;
11323
11324   if (tree_view->priv->scroll_to_path)
11325     {
11326       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11327       tree_view->priv->scroll_to_path = NULL;
11328     }
11329
11330   if (tree_view->priv->model)
11331     {
11332       GList *tmplist = tree_view->priv->columns;
11333
11334       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11335       gtk_tree_view_stop_editing (tree_view, TRUE);
11336
11337       remove_expand_collapse_timeout (tree_view);
11338
11339       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11340                                             gtk_tree_view_row_changed,
11341                                             tree_view);
11342       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11343                                             gtk_tree_view_row_inserted,
11344                                             tree_view);
11345       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11346                                             gtk_tree_view_row_has_child_toggled,
11347                                             tree_view);
11348       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11349                                             gtk_tree_view_row_deleted,
11350                                             tree_view);
11351       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11352                                             gtk_tree_view_rows_reordered,
11353                                             tree_view);
11354
11355       for (; tmplist; tmplist = tmplist->next)
11356         _gtk_tree_view_column_unset_model (tmplist->data,
11357                                            tree_view->priv->model);
11358
11359       if (tree_view->priv->tree)
11360         gtk_tree_view_free_rbtree (tree_view);
11361
11362       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11363       tree_view->priv->drag_dest_row = NULL;
11364       gtk_tree_row_reference_free (tree_view->priv->cursor);
11365       tree_view->priv->cursor = NULL;
11366       gtk_tree_row_reference_free (tree_view->priv->anchor);
11367       tree_view->priv->anchor = NULL;
11368       gtk_tree_row_reference_free (tree_view->priv->top_row);
11369       tree_view->priv->top_row = NULL;
11370       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11371       tree_view->priv->scroll_to_path = NULL;
11372
11373       tree_view->priv->scroll_to_column = NULL;
11374
11375       g_object_unref (tree_view->priv->model);
11376
11377       tree_view->priv->search_column = -1;
11378       tree_view->priv->fixed_height_check = 0;
11379       tree_view->priv->fixed_height = -1;
11380       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11381       tree_view->priv->last_button_x = -1;
11382       tree_view->priv->last_button_y = -1;
11383     }
11384
11385   tree_view->priv->model = model;
11386
11387   if (tree_view->priv->model)
11388     {
11389       gint i;
11390       GtkTreePath *path;
11391       GtkTreeIter iter;
11392       GtkTreeModelFlags flags;
11393
11394       if (tree_view->priv->search_column == -1)
11395         {
11396           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11397             {
11398               GType type = gtk_tree_model_get_column_type (model, i);
11399
11400               if (g_value_type_transformable (type, G_TYPE_STRING))
11401                 {
11402                   tree_view->priv->search_column = i;
11403                   break;
11404                 }
11405             }
11406         }
11407
11408       g_object_ref (tree_view->priv->model);
11409       g_signal_connect (tree_view->priv->model,
11410                         "row-changed",
11411                         G_CALLBACK (gtk_tree_view_row_changed),
11412                         tree_view);
11413       g_signal_connect (tree_view->priv->model,
11414                         "row-inserted",
11415                         G_CALLBACK (gtk_tree_view_row_inserted),
11416                         tree_view);
11417       g_signal_connect (tree_view->priv->model,
11418                         "row-has-child-toggled",
11419                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11420                         tree_view);
11421       g_signal_connect (tree_view->priv->model,
11422                         "row-deleted",
11423                         G_CALLBACK (gtk_tree_view_row_deleted),
11424                         tree_view);
11425       g_signal_connect (tree_view->priv->model,
11426                         "rows-reordered",
11427                         G_CALLBACK (gtk_tree_view_rows_reordered),
11428                         tree_view);
11429
11430       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11431       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11432         tree_view->priv->is_list = TRUE;
11433       else
11434         tree_view->priv->is_list = FALSE;
11435
11436       path = gtk_tree_path_new_first ();
11437       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11438         {
11439           tree_view->priv->tree = _gtk_rbtree_new ();
11440           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11441         }
11442       gtk_tree_path_free (path);
11443
11444       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11445       install_presize_handler (tree_view);
11446     }
11447
11448   g_object_notify (G_OBJECT (tree_view), "model");
11449
11450   if (tree_view->priv->selection)
11451   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11452
11453   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11454     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11455 }
11456
11457 /**
11458  * gtk_tree_view_get_selection:
11459  * @tree_view: A #GtkTreeView.
11460  *
11461  * Gets the #GtkTreeSelection associated with @tree_view.
11462  *
11463  * Return value: (transfer none): A #GtkTreeSelection object.
11464  **/
11465 GtkTreeSelection *
11466 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11467 {
11468   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11469
11470   return tree_view->priv->selection;
11471 }
11472
11473 /**
11474  * gtk_tree_view_get_hadjustment:
11475  * @tree_view: A #GtkTreeView
11476  *
11477  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11478  *
11479  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11480  *     if none is currently being used.
11481  *
11482  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11483  **/
11484 GtkAdjustment *
11485 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11486 {
11487   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11488
11489   return tree_view->priv->hadjustment;
11490 }
11491
11492 /**
11493  * gtk_tree_view_set_hadjustment:
11494  * @tree_view: A #GtkTreeView
11495  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11496  *
11497  * Sets the #GtkAdjustment for the current horizontal aspect.
11498  *
11499  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11500  **/
11501 void
11502 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11503                                GtkAdjustment *adjustment)
11504 {
11505   GtkTreeViewPrivate *priv = tree_view->priv;
11506
11507   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11508   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11509
11510   if (adjustment && priv->hadjustment == adjustment)
11511     return;
11512
11513   if (priv->hadjustment != NULL)
11514     {
11515       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11516                                             gtk_tree_view_adjustment_changed,
11517                                             tree_view);
11518       g_object_unref (priv->hadjustment);
11519     }
11520
11521   if (adjustment == NULL)
11522     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11523                                      0.0, 0.0, 0.0);
11524
11525   g_signal_connect (adjustment, "value-changed",
11526                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11527   priv->hadjustment = g_object_ref_sink (adjustment);
11528   /* FIXME: Adjustment should probably be populated here with fresh values, but
11529    * internal details are too complicated for me to decipher right now.
11530    */
11531   gtk_tree_view_adjustment_changed (NULL, tree_view);
11532
11533   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11534 }
11535
11536 /**
11537  * gtk_tree_view_get_vadjustment:
11538  * @tree_view: A #GtkTreeView
11539  *
11540  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11541  *
11542  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11543  *     if none is currently being used.
11544  *
11545  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11546  **/
11547 GtkAdjustment *
11548 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11549 {
11550   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11551
11552   return tree_view->priv->vadjustment;
11553 }
11554
11555 /**
11556  * gtk_tree_view_set_vadjustment:
11557  * @tree_view: A #GtkTreeView
11558  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11559  *
11560  * Sets the #GtkAdjustment for the current vertical aspect.
11561  *
11562  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11563  **/
11564 void
11565 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11566                                GtkAdjustment *adjustment)
11567 {
11568   GtkTreeViewPrivate *priv = tree_view->priv;
11569
11570   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11571   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11572
11573   if (adjustment && priv->vadjustment == adjustment)
11574     return;
11575
11576   if (priv->vadjustment != NULL)
11577     {
11578       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11579                                             gtk_tree_view_adjustment_changed,
11580                                             tree_view);
11581       g_object_unref (priv->vadjustment);
11582     }
11583
11584   if (adjustment == NULL)
11585     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11586                                      0.0, 0.0, 0.0);
11587
11588   g_signal_connect (adjustment, "value-changed",
11589                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11590   priv->vadjustment = g_object_ref_sink (adjustment);
11591   /* FIXME: Adjustment should probably be populated here with fresh values, but
11592    * internal details are too complicated for me to decipher right now.
11593    */
11594   gtk_tree_view_adjustment_changed (NULL, tree_view);
11595   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11596 }
11597
11598 /* Column and header operations */
11599
11600 /**
11601  * gtk_tree_view_get_headers_visible:
11602  * @tree_view: A #GtkTreeView.
11603  *
11604  * Returns %TRUE if the headers on the @tree_view are visible.
11605  *
11606  * Return value: Whether the headers are visible or not.
11607  **/
11608 gboolean
11609 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11610 {
11611   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11612
11613   return tree_view->priv->headers_visible;
11614 }
11615
11616 /**
11617  * gtk_tree_view_set_headers_visible:
11618  * @tree_view: A #GtkTreeView.
11619  * @headers_visible: %TRUE if the headers are visible
11620  *
11621  * Sets the visibility state of the headers.
11622  **/
11623 void
11624 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11625                                    gboolean     headers_visible)
11626 {
11627   gint x, y;
11628   GList *list;
11629   GtkTreeViewColumn *column;
11630   GtkAllocation allocation;
11631   GtkWidget *button;
11632
11633   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11634
11635   headers_visible = !! headers_visible;
11636
11637   if (tree_view->priv->headers_visible == headers_visible)
11638     return;
11639
11640   tree_view->priv->headers_visible = headers_visible == TRUE;
11641
11642   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11643     {
11644       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11645       if (headers_visible)
11646         {
11647           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11648           gdk_window_move_resize (tree_view->priv->bin_window,
11649                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11650                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11651
11652           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11653             gtk_tree_view_map_buttons (tree_view);
11654         }
11655       else
11656         {
11657           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11658
11659           for (list = tree_view->priv->columns; list; list = list->next)
11660             {
11661               column = list->data;
11662               button = gtk_tree_view_column_get_button (column);
11663
11664               gtk_widget_hide (button);
11665               gtk_widget_unmap (button);
11666             }
11667           gdk_window_hide (tree_view->priv->header_window);
11668         }
11669     }
11670
11671   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11672   gtk_adjustment_configure (tree_view->priv->vadjustment,
11673                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11674                             0,
11675                             tree_view->priv->height,
11676                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11677                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11678                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11679
11680   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11681
11682   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11683 }
11684
11685 /**
11686  * gtk_tree_view_columns_autosize:
11687  * @tree_view: A #GtkTreeView.
11688  *
11689  * Resizes all columns to their optimal width. Only works after the
11690  * treeview has been realized.
11691  **/
11692 void
11693 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11694 {
11695   gboolean dirty = FALSE;
11696   GList *list;
11697   GtkTreeViewColumn *column;
11698
11699   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11700
11701   for (list = tree_view->priv->columns; list; list = list->next)
11702     {
11703       column = list->data;
11704       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11705         continue;
11706       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11707       dirty = TRUE;
11708     }
11709
11710   if (dirty)
11711     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11712 }
11713
11714 /**
11715  * gtk_tree_view_set_headers_clickable:
11716  * @tree_view: A #GtkTreeView.
11717  * @setting: %TRUE if the columns are clickable.
11718  *
11719  * Allow the column title buttons to be clicked.
11720  **/
11721 void
11722 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11723                                      gboolean   setting)
11724 {
11725   GList *list;
11726
11727   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11728
11729   for (list = tree_view->priv->columns; list; list = list->next)
11730     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11731
11732   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11733 }
11734
11735
11736 /**
11737  * gtk_tree_view_get_headers_clickable:
11738  * @tree_view: A #GtkTreeView.
11739  *
11740  * Returns whether all header columns are clickable.
11741  *
11742  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11743  *
11744  * Since: 2.10
11745  **/
11746 gboolean 
11747 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11748 {
11749   GList *list;
11750   
11751   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11752
11753   for (list = tree_view->priv->columns; list; list = list->next)
11754     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11755       return FALSE;
11756
11757   return TRUE;
11758 }
11759
11760 /**
11761  * gtk_tree_view_set_rules_hint
11762  * @tree_view: a #GtkTreeView
11763  * @setting: %TRUE if the tree requires reading across rows
11764  *
11765  * This function tells GTK+ that the user interface for your
11766  * application requires users to read across tree rows and associate
11767  * cells with one another. By default, GTK+ will then render the tree
11768  * with alternating row colors. Do <emphasis>not</emphasis> use it
11769  * just because you prefer the appearance of the ruled tree; that's a
11770  * question for the theme. Some themes will draw tree rows in
11771  * alternating colors even when rules are turned off, and users who
11772  * prefer that appearance all the time can choose those themes. You
11773  * should call this function only as a <emphasis>semantic</emphasis>
11774  * hint to the theme engine that your tree makes alternating colors
11775  * useful from a functional standpoint (since it has lots of columns,
11776  * generally).
11777  *
11778  **/
11779 void
11780 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11781                               gboolean      setting)
11782 {
11783   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11784
11785   setting = setting != FALSE;
11786
11787   if (tree_view->priv->has_rules != setting)
11788     {
11789       tree_view->priv->has_rules = setting;
11790       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11791     }
11792
11793   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11794 }
11795
11796 /**
11797  * gtk_tree_view_get_rules_hint
11798  * @tree_view: a #GtkTreeView
11799  *
11800  * Gets the setting set by gtk_tree_view_set_rules_hint().
11801  *
11802  * Return value: %TRUE if rules are useful for the user of this tree
11803  **/
11804 gboolean
11805 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11806 {
11807   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11808
11809   return tree_view->priv->has_rules;
11810 }
11811
11812 /* Public Column functions
11813  */
11814
11815 /**
11816  * gtk_tree_view_append_column:
11817  * @tree_view: A #GtkTreeView.
11818  * @column: The #GtkTreeViewColumn to add.
11819  *
11820  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11821  * mode enabled, then @column must have its "sizing" property set to be
11822  * GTK_TREE_VIEW_COLUMN_FIXED.
11823  *
11824  * Return value: The number of columns in @tree_view after appending.
11825  **/
11826 gint
11827 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11828                              GtkTreeViewColumn *column)
11829 {
11830   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11831   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11832   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11833
11834   return gtk_tree_view_insert_column (tree_view, column, -1);
11835 }
11836
11837
11838 /**
11839  * gtk_tree_view_remove_column:
11840  * @tree_view: A #GtkTreeView.
11841  * @column: The #GtkTreeViewColumn to remove.
11842  *
11843  * Removes @column from @tree_view.
11844  *
11845  * Return value: The number of columns in @tree_view after removing.
11846  **/
11847 gint
11848 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11849                              GtkTreeViewColumn *column)
11850 {
11851   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11852   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11853   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11854
11855   if (tree_view->priv->focus_column == column)
11856     tree_view->priv->focus_column = NULL;
11857
11858   if (tree_view->priv->edited_column == column)
11859     {
11860       gtk_tree_view_stop_editing (tree_view, TRUE);
11861
11862       /* no need to, but just to be sure ... */
11863       tree_view->priv->edited_column = NULL;
11864     }
11865
11866   if (tree_view->priv->expander_column == column)
11867     tree_view->priv->expander_column = NULL;
11868
11869   g_signal_handlers_disconnect_by_func (column,
11870                                         G_CALLBACK (column_sizing_notify),
11871                                         tree_view);
11872
11873   _gtk_tree_view_column_unset_tree_view (column);
11874
11875   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11876   tree_view->priv->n_columns--;
11877
11878   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11879     {
11880       GList *list;
11881
11882       _gtk_tree_view_column_unrealize_button (column);
11883       for (list = tree_view->priv->columns; list; list = list->next)
11884         {
11885           GtkTreeViewColumn *tmp_column;
11886
11887           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11888           if (gtk_tree_view_column_get_visible (tmp_column))
11889             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11890         }
11891
11892       if (tree_view->priv->n_columns == 0 &&
11893           gtk_tree_view_get_headers_visible (tree_view))
11894         gdk_window_hide (tree_view->priv->header_window);
11895
11896       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11897     }
11898
11899   g_object_unref (column);
11900   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11901
11902   return tree_view->priv->n_columns;
11903 }
11904
11905 /**
11906  * gtk_tree_view_insert_column:
11907  * @tree_view: A #GtkTreeView.
11908  * @column: The #GtkTreeViewColumn to be inserted.
11909  * @position: The position to insert @column in.
11910  *
11911  * This inserts the @column into the @tree_view at @position.  If @position is
11912  * -1, then the column is inserted at the end. If @tree_view has
11913  * "fixed_height" mode enabled, then @column must have its "sizing" property
11914  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11915  *
11916  * Return value: The number of columns in @tree_view after insertion.
11917  **/
11918 gint
11919 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11920                              GtkTreeViewColumn *column,
11921                              gint               position)
11922 {
11923   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11924   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11925   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11926
11927   if (tree_view->priv->fixed_height_mode)
11928     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11929                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11930
11931   g_object_ref_sink (column);
11932
11933   if (tree_view->priv->n_columns == 0 &&
11934       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11935       gtk_tree_view_get_headers_visible (tree_view))
11936     {
11937       gdk_window_show (tree_view->priv->header_window);
11938     }
11939
11940   g_signal_connect (column, "notify::sizing",
11941                     G_CALLBACK (column_sizing_notify), tree_view);
11942
11943   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11944                                             column, position);
11945   tree_view->priv->n_columns++;
11946
11947   _gtk_tree_view_column_set_tree_view (column, tree_view);
11948
11949   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11950     {
11951       GList *list;
11952
11953       _gtk_tree_view_column_realize_button (column);
11954
11955       for (list = tree_view->priv->columns; list; list = list->next)
11956         {
11957           column = GTK_TREE_VIEW_COLUMN (list->data);
11958           if (gtk_tree_view_column_get_visible (column))
11959             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11960         }
11961       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11962     }
11963
11964   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11965
11966   return tree_view->priv->n_columns;
11967 }
11968
11969 /**
11970  * gtk_tree_view_insert_column_with_attributes:
11971  * @tree_view: A #GtkTreeView
11972  * @position: The position to insert the new column in.
11973  * @title: The title to set the header to.
11974  * @cell: The #GtkCellRenderer.
11975  * @Varargs: A %NULL-terminated list of attributes.
11976  *
11977  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11978  * @position.  If @position is -1, then the newly created column is inserted at
11979  * the end.  The column is initialized with the attributes given. If @tree_view
11980  * has "fixed_height" mode enabled, then the new column will have its sizing
11981  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11982  *
11983  * Return value: The number of columns in @tree_view after insertion.
11984  **/
11985 gint
11986 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11987                                              gint             position,
11988                                              const gchar     *title,
11989                                              GtkCellRenderer *cell,
11990                                              ...)
11991 {
11992   GtkTreeViewColumn *column;
11993   gchar *attribute;
11994   va_list args;
11995   gint column_id;
11996
11997   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11998
11999   column = gtk_tree_view_column_new ();
12000   if (tree_view->priv->fixed_height_mode)
12001     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12002
12003   gtk_tree_view_column_set_title (column, title);
12004   gtk_tree_view_column_pack_start (column, cell, TRUE);
12005
12006   va_start (args, cell);
12007
12008   attribute = va_arg (args, gchar *);
12009
12010   while (attribute != NULL)
12011     {
12012       column_id = va_arg (args, gint);
12013       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12014       attribute = va_arg (args, gchar *);
12015     }
12016
12017   va_end (args);
12018
12019   gtk_tree_view_insert_column (tree_view, column, position);
12020
12021   return tree_view->priv->n_columns;
12022 }
12023
12024 /**
12025  * gtk_tree_view_insert_column_with_data_func:
12026  * @tree_view: a #GtkTreeView
12027  * @position: Position to insert, -1 for append
12028  * @title: column title
12029  * @cell: cell renderer for column
12030  * @func: function to set attributes of cell renderer
12031  * @data: data for @func
12032  * @dnotify: destroy notifier for @data
12033  *
12034  * Convenience function that inserts a new column into the #GtkTreeView
12035  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
12036  * attributes (normally using data from the model). See also
12037  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12038  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12039  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12040  *
12041  * Return value: number of columns in the tree view post-insert
12042  **/
12043 gint
12044 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12045                                              gint                       position,
12046                                              const gchar               *title,
12047                                              GtkCellRenderer           *cell,
12048                                              GtkTreeCellDataFunc        func,
12049                                              gpointer                   data,
12050                                              GDestroyNotify             dnotify)
12051 {
12052   GtkTreeViewColumn *column;
12053
12054   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12055
12056   column = gtk_tree_view_column_new ();
12057   if (tree_view->priv->fixed_height_mode)
12058     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12059
12060   gtk_tree_view_column_set_title (column, title);
12061   gtk_tree_view_column_pack_start (column, cell, TRUE);
12062   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12063
12064   gtk_tree_view_insert_column (tree_view, column, position);
12065
12066   return tree_view->priv->n_columns;
12067 }
12068
12069 /**
12070  * gtk_tree_view_get_column:
12071  * @tree_view: A #GtkTreeView.
12072  * @n: The position of the column, counting from 0.
12073  *
12074  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12075  *
12076  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12077  *     position is outside the range of columns.
12078  **/
12079 GtkTreeViewColumn *
12080 gtk_tree_view_get_column (GtkTreeView *tree_view,
12081                           gint         n)
12082 {
12083   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12084
12085   if (n < 0 || n >= tree_view->priv->n_columns)
12086     return NULL;
12087
12088   if (tree_view->priv->columns == NULL)
12089     return NULL;
12090
12091   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12092 }
12093
12094 /**
12095  * gtk_tree_view_get_columns:
12096  * @tree_view: A #GtkTreeView
12097  *
12098  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12099  * The returned list must be freed with g_list_free ().
12100  *
12101  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12102  **/
12103 GList *
12104 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12105 {
12106   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12107
12108   return g_list_copy (tree_view->priv->columns);
12109 }
12110
12111 /**
12112  * gtk_tree_view_move_column_after:
12113  * @tree_view: A #GtkTreeView
12114  * @column: The #GtkTreeViewColumn to be moved.
12115  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12116  *
12117  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12118  * @column is placed in the first position.
12119  **/
12120 void
12121 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12122                                  GtkTreeViewColumn *column,
12123                                  GtkTreeViewColumn *base_column)
12124 {
12125   GList *column_list_el, *base_el = NULL;
12126
12127   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12128
12129   column_list_el = g_list_find (tree_view->priv->columns, column);
12130   g_return_if_fail (column_list_el != NULL);
12131
12132   if (base_column)
12133     {
12134       base_el = g_list_find (tree_view->priv->columns, base_column);
12135       g_return_if_fail (base_el != NULL);
12136     }
12137
12138   if (column_list_el->prev == base_el)
12139     return;
12140
12141   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12142   if (base_el == NULL)
12143     {
12144       column_list_el->prev = NULL;
12145       column_list_el->next = tree_view->priv->columns;
12146       if (column_list_el->next)
12147         column_list_el->next->prev = column_list_el;
12148       tree_view->priv->columns = column_list_el;
12149     }
12150   else
12151     {
12152       column_list_el->prev = base_el;
12153       column_list_el->next = base_el->next;
12154       if (column_list_el->next)
12155         column_list_el->next->prev = column_list_el;
12156       base_el->next = column_list_el;
12157     }
12158
12159   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12160     {
12161       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12162       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12163     }
12164
12165   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12166 }
12167
12168 /**
12169  * gtk_tree_view_set_expander_column:
12170  * @tree_view: A #GtkTreeView
12171  * @column: %NULL, or the column to draw the expander arrow at.
12172  *
12173  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12174  * If @column is %NULL, then the expander arrow is always at the first 
12175  * visible column.
12176  *
12177  * If you do not want expander arrow to appear in your tree, set the 
12178  * expander column to a hidden column.
12179  **/
12180 void
12181 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12182                                    GtkTreeViewColumn *column)
12183 {
12184   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12185   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12186
12187   if (tree_view->priv->expander_column != column)
12188     {
12189       GList *list;
12190
12191       if (column)
12192         {
12193           /* Confirm that column is in tree_view */
12194           for (list = tree_view->priv->columns; list; list = list->next)
12195             if (list->data == column)
12196               break;
12197           g_return_if_fail (list != NULL);
12198         }
12199
12200       tree_view->priv->expander_column = column;
12201       g_object_notify (G_OBJECT (tree_view), "expander-column");
12202     }
12203 }
12204
12205 /**
12206  * gtk_tree_view_get_expander_column:
12207  * @tree_view: A #GtkTreeView
12208  *
12209  * Returns the column that is the current expander column.
12210  * This column has the expander arrow drawn next to it.
12211  *
12212  * Return value: (transfer none): The expander column.
12213  **/
12214 GtkTreeViewColumn *
12215 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12216 {
12217   GList *list;
12218
12219   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12220
12221   for (list = tree_view->priv->columns; list; list = list->next)
12222     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12223       return (GtkTreeViewColumn *) list->data;
12224   return NULL;
12225 }
12226
12227
12228 /**
12229  * gtk_tree_view_set_column_drag_function:
12230  * @tree_view: A #GtkTreeView.
12231  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12232  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12233  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12234  *
12235  * Sets a user function for determining where a column may be dropped when
12236  * dragged.  This function is called on every column pair in turn at the
12237  * beginning of a column drag to determine where a drop can take place.  The
12238  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12239  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12240  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12241  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12242  * @tree_view reverts to the default behavior of allowing all columns to be
12243  * dropped everywhere.
12244  **/
12245 void
12246 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12247                                         GtkTreeViewColumnDropFunc  func,
12248                                         gpointer                   user_data,
12249                                         GDestroyNotify             destroy)
12250 {
12251   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12252
12253   if (tree_view->priv->column_drop_func_data_destroy)
12254     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12255
12256   tree_view->priv->column_drop_func = func;
12257   tree_view->priv->column_drop_func_data = user_data;
12258   tree_view->priv->column_drop_func_data_destroy = destroy;
12259 }
12260
12261 /**
12262  * gtk_tree_view_scroll_to_point:
12263  * @tree_view: a #GtkTreeView
12264  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12265  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12266  *
12267  * Scrolls the tree view such that the top-left corner of the visible
12268  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12269  * in tree coordinates.  The @tree_view must be realized before
12270  * this function is called.  If it isn't, you probably want to be
12271  * using gtk_tree_view_scroll_to_cell().
12272  *
12273  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12274  **/
12275 void
12276 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12277                                gint         tree_x,
12278                                gint         tree_y)
12279 {
12280   GtkAdjustment *hadj;
12281   GtkAdjustment *vadj;
12282
12283   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12284   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12285
12286   hadj = tree_view->priv->hadjustment;
12287   vadj = tree_view->priv->vadjustment;
12288
12289   if (tree_x != -1)
12290     gtk_adjustment_set_value (hadj, tree_x);
12291   if (tree_y != -1)
12292     gtk_adjustment_set_value (vadj, tree_y);
12293 }
12294
12295 /**
12296  * gtk_tree_view_scroll_to_cell:
12297  * @tree_view: A #GtkTreeView.
12298  * @path: (allow-none): The path of the row to move to, or %NULL.
12299  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12300  * @use_align: whether to use alignment arguments, or %FALSE.
12301  * @row_align: The vertical alignment of the row specified by @path.
12302  * @col_align: The horizontal alignment of the column specified by @column.
12303  *
12304  * Moves the alignments of @tree_view to the position specified by @column and
12305  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12306  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12307  * or @path need to be non-%NULL.  @row_align determines where the row is
12308  * placed, and @col_align determines where @column is placed.  Both are expected
12309  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12310  * right/bottom alignment, 0.5 means center.
12311  *
12312  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12313  * tree does the minimum amount of work to scroll the cell onto the screen.
12314  * This means that the cell will be scrolled to the edge closest to its current
12315  * position.  If the cell is currently visible on the screen, nothing is done.
12316  *
12317  * This function only works if the model is set, and @path is a valid row on the
12318  * model.  If the model changes before the @tree_view is realized, the centered
12319  * path will be modified to reflect this change.
12320  **/
12321 void
12322 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12323                               GtkTreePath       *path,
12324                               GtkTreeViewColumn *column,
12325                               gboolean           use_align,
12326                               gfloat             row_align,
12327                               gfloat             col_align)
12328 {
12329   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12330   g_return_if_fail (tree_view->priv->model != NULL);
12331   g_return_if_fail (tree_view->priv->tree != NULL);
12332   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12333   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12334   g_return_if_fail (path != NULL || column != NULL);
12335
12336 #if 0
12337   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12338            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12339 #endif
12340   row_align = CLAMP (row_align, 0.0, 1.0);
12341   col_align = CLAMP (col_align, 0.0, 1.0);
12342
12343
12344   /* Note: Despite the benefits that come from having one code path for the
12345    * scrolling code, we short-circuit validate_visible_area's immplementation as
12346    * it is much slower than just going to the point.
12347    */
12348   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12349       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12350       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12351       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12352     {
12353       if (tree_view->priv->scroll_to_path)
12354         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12355
12356       tree_view->priv->scroll_to_path = NULL;
12357       tree_view->priv->scroll_to_column = NULL;
12358
12359       if (path)
12360         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12361       if (column)
12362         tree_view->priv->scroll_to_column = column;
12363       tree_view->priv->scroll_to_use_align = use_align;
12364       tree_view->priv->scroll_to_row_align = row_align;
12365       tree_view->priv->scroll_to_col_align = col_align;
12366
12367       install_presize_handler (tree_view);
12368     }
12369   else
12370     {
12371       GdkRectangle cell_rect;
12372       GdkRectangle vis_rect;
12373       gint dest_x, dest_y;
12374
12375       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12376       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12377
12378       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12379
12380       dest_x = vis_rect.x;
12381       dest_y = vis_rect.y;
12382
12383       if (column)
12384         {
12385           if (use_align)
12386             {
12387               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12388             }
12389           else
12390             {
12391               if (cell_rect.x < vis_rect.x)
12392                 dest_x = cell_rect.x;
12393               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12394                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12395             }
12396         }
12397
12398       if (path)
12399         {
12400           if (use_align)
12401             {
12402               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12403               dest_y = MAX (dest_y, 0);
12404             }
12405           else
12406             {
12407               if (cell_rect.y < vis_rect.y)
12408                 dest_y = cell_rect.y;
12409               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12410                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12411             }
12412         }
12413
12414       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12415     }
12416 }
12417
12418 /**
12419  * gtk_tree_view_row_activated:
12420  * @tree_view: A #GtkTreeView
12421  * @path: The #GtkTreePath to be activated.
12422  * @column: The #GtkTreeViewColumn to be activated.
12423  *
12424  * Activates the cell determined by @path and @column.
12425  **/
12426 void
12427 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12428                              GtkTreePath       *path,
12429                              GtkTreeViewColumn *column)
12430 {
12431   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12432
12433   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12434 }
12435
12436
12437 static void
12438 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12439                                           GtkRBNode *node,
12440                                           gpointer   data)
12441 {
12442   GtkTreeView *tree_view = data;
12443
12444   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12445       node->children)
12446     {
12447       GtkTreePath *path;
12448       GtkTreeIter iter;
12449
12450       path = _gtk_tree_view_find_path (tree_view, tree, node);
12451       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12452
12453       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12454
12455       gtk_tree_path_free (path);
12456     }
12457
12458   if (node->children)
12459     _gtk_rbtree_traverse (node->children,
12460                           node->children->root,
12461                           G_PRE_ORDER,
12462                           gtk_tree_view_expand_all_emission_helper,
12463                           tree_view);
12464 }
12465
12466 /**
12467  * gtk_tree_view_expand_all:
12468  * @tree_view: A #GtkTreeView.
12469  *
12470  * Recursively expands all nodes in the @tree_view.
12471  **/
12472 void
12473 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12474 {
12475   GtkTreePath *path;
12476   GtkRBTree *tree;
12477   GtkRBNode *node;
12478
12479   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12480
12481   if (tree_view->priv->tree == NULL)
12482     return;
12483
12484   path = gtk_tree_path_new_first ();
12485   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12486
12487   while (node)
12488     {
12489       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12490       node = _gtk_rbtree_next (tree, node);
12491       gtk_tree_path_next (path);
12492   }
12493
12494   gtk_tree_path_free (path);
12495 }
12496
12497 /* Timeout to animate the expander during expands and collapses */
12498 static gboolean
12499 expand_collapse_timeout (gpointer data)
12500 {
12501   return do_expand_collapse (data);
12502 }
12503
12504 static void
12505 add_expand_collapse_timeout (GtkTreeView *tree_view,
12506                              GtkRBTree   *tree,
12507                              GtkRBNode   *node,
12508                              gboolean     expand)
12509 {
12510   if (tree_view->priv->expand_collapse_timeout != 0)
12511     return;
12512
12513   tree_view->priv->expand_collapse_timeout =
12514       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
12515   tree_view->priv->expanded_collapsed_tree = tree;
12516   tree_view->priv->expanded_collapsed_node = node;
12517
12518   if (expand)
12519     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12520   else
12521     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12522 }
12523
12524 static void
12525 remove_expand_collapse_timeout (GtkTreeView *tree_view)
12526 {
12527   if (tree_view->priv->expand_collapse_timeout)
12528     {
12529       g_source_remove (tree_view->priv->expand_collapse_timeout);
12530       tree_view->priv->expand_collapse_timeout = 0;
12531     }
12532
12533   if (tree_view->priv->expanded_collapsed_node != NULL)
12534     {
12535       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
12536       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12537
12538       tree_view->priv->expanded_collapsed_node = NULL;
12539     }
12540 }
12541
12542 static void
12543 cancel_arrow_animation (GtkTreeView *tree_view)
12544 {
12545   if (tree_view->priv->expand_collapse_timeout)
12546     {
12547       while (do_expand_collapse (tree_view));
12548
12549       remove_expand_collapse_timeout (tree_view);
12550     }
12551 }
12552
12553 static gboolean
12554 do_expand_collapse (GtkTreeView *tree_view)
12555 {
12556   GtkRBNode *node;
12557   GtkRBTree *tree;
12558   gboolean expanding;
12559   gboolean redraw;
12560
12561   redraw = FALSE;
12562   expanding = TRUE;
12563
12564   node = tree_view->priv->expanded_collapsed_node;
12565   tree = tree_view->priv->expanded_collapsed_tree;
12566
12567   if (node->children == NULL)
12568     expanding = FALSE;
12569
12570   if (expanding)
12571     {
12572       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12573         {
12574           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12575           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12576
12577           redraw = TRUE;
12578
12579         }
12580       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12581         {
12582           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12583
12584           redraw = TRUE;
12585         }
12586     }
12587   else
12588     {
12589       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12590         {
12591           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12592           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12593
12594           redraw = TRUE;
12595         }
12596       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12597         {
12598           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12599
12600           redraw = TRUE;
12601
12602         }
12603     }
12604
12605   if (redraw)
12606     {
12607       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
12608
12609       return TRUE;
12610     }
12611
12612   return FALSE;
12613 }
12614
12615 /**
12616  * gtk_tree_view_collapse_all:
12617  * @tree_view: A #GtkTreeView.
12618  *
12619  * Recursively collapses all visible, expanded nodes in @tree_view.
12620  **/
12621 void
12622 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12623 {
12624   GtkRBTree *tree;
12625   GtkRBNode *node;
12626   GtkTreePath *path;
12627   gint *indices;
12628
12629   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12630
12631   if (tree_view->priv->tree == NULL)
12632     return;
12633
12634   path = gtk_tree_path_new ();
12635   gtk_tree_path_down (path);
12636   indices = gtk_tree_path_get_indices (path);
12637
12638   tree = tree_view->priv->tree;
12639   node = tree->root;
12640   while (node && node->left != tree->nil)
12641     node = node->left;
12642
12643   while (node)
12644     {
12645       if (node->children)
12646         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12647       indices[0]++;
12648       node = _gtk_rbtree_next (tree, node);
12649     }
12650
12651   gtk_tree_path_free (path);
12652 }
12653
12654 /**
12655  * gtk_tree_view_expand_to_path:
12656  * @tree_view: A #GtkTreeView.
12657  * @path: path to a row.
12658  *
12659  * Expands the row at @path. This will also expand all parent rows of
12660  * @path as necessary.
12661  *
12662  * Since: 2.2
12663  **/
12664 void
12665 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12666                               GtkTreePath *path)
12667 {
12668   gint i, depth;
12669   gint *indices;
12670   GtkTreePath *tmp;
12671
12672   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12673   g_return_if_fail (path != NULL);
12674
12675   depth = gtk_tree_path_get_depth (path);
12676   indices = gtk_tree_path_get_indices (path);
12677
12678   tmp = gtk_tree_path_new ();
12679   g_return_if_fail (tmp != NULL);
12680
12681   for (i = 0; i < depth; i++)
12682     {
12683       gtk_tree_path_append_index (tmp, indices[i]);
12684       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12685     }
12686
12687   gtk_tree_path_free (tmp);
12688 }
12689
12690 /* FIXME the bool return values for expand_row and collapse_row are
12691  * not analagous; they should be TRUE if the row had children and
12692  * was not already in the requested state.
12693  */
12694
12695
12696 static gboolean
12697 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12698                                GtkTreePath *path,
12699                                GtkRBTree   *tree,
12700                                GtkRBNode   *node,
12701                                gboolean     open_all,
12702                                gboolean     animate)
12703 {
12704   GtkTreeIter iter;
12705   GtkTreeIter temp;
12706   gboolean expand;
12707
12708   if (animate)
12709     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12710                   "gtk-enable-animations", &animate,
12711                   NULL);
12712
12713   remove_auto_expand_timeout (tree_view);
12714
12715   if (node->children && !open_all)
12716     return FALSE;
12717
12718   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12719     return FALSE;
12720
12721   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12722   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12723     return FALSE;
12724
12725
12726    if (node->children && open_all)
12727     {
12728       gboolean retval = FALSE;
12729       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12730
12731       gtk_tree_path_append_index (tmp_path, 0);
12732       tree = node->children;
12733       node = tree->root;
12734       while (node->left != tree->nil)
12735         node = node->left;
12736       /* try to expand the children */
12737       do
12738         {
12739          gboolean t;
12740          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12741                                             TRUE, animate);
12742          if (t)
12743            retval = TRUE;
12744
12745          gtk_tree_path_next (tmp_path);
12746          node = _gtk_rbtree_next (tree, node);
12747        }
12748       while (node != NULL);
12749
12750       gtk_tree_path_free (tmp_path);
12751
12752       return retval;
12753     }
12754
12755   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12756
12757   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12758     return FALSE;
12759
12760   if (expand)
12761     return FALSE;
12762
12763   node->children = _gtk_rbtree_new ();
12764   node->children->parent_tree = tree;
12765   node->children->parent_node = node;
12766
12767   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12768
12769   gtk_tree_view_build_tree (tree_view,
12770                             node->children,
12771                             &temp,
12772                             gtk_tree_path_get_depth (path) + 1,
12773                             open_all);
12774
12775   remove_expand_collapse_timeout (tree_view);
12776
12777   if (animate)
12778     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12779
12780   install_presize_handler (tree_view);
12781
12782   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12783   if (open_all && node->children)
12784     {
12785       _gtk_rbtree_traverse (node->children,
12786                             node->children->root,
12787                             G_PRE_ORDER,
12788                             gtk_tree_view_expand_all_emission_helper,
12789                             tree_view);
12790     }
12791   return TRUE;
12792 }
12793
12794
12795 /**
12796  * gtk_tree_view_expand_row:
12797  * @tree_view: a #GtkTreeView
12798  * @path: path to a row
12799  * @open_all: whether to recursively expand, or just expand immediate children
12800  *
12801  * Opens the row so its children are visible.
12802  *
12803  * Return value: %TRUE if the row existed and had children
12804  **/
12805 gboolean
12806 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12807                           GtkTreePath *path,
12808                           gboolean     open_all)
12809 {
12810   GtkRBTree *tree;
12811   GtkRBNode *node;
12812
12813   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12814   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12815   g_return_val_if_fail (path != NULL, FALSE);
12816
12817   if (_gtk_tree_view_find_node (tree_view,
12818                                 path,
12819                                 &tree,
12820                                 &node))
12821     return FALSE;
12822
12823   if (tree != NULL)
12824     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12825   else
12826     return FALSE;
12827 }
12828
12829 static gboolean
12830 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12831                                  GtkTreePath *path,
12832                                  GtkRBTree   *tree,
12833                                  GtkRBNode   *node,
12834                                  gboolean     animate)
12835 {
12836   GtkTreeIter iter;
12837   GtkTreeIter children;
12838   gboolean collapse;
12839   gint x, y;
12840   GList *list;
12841   GdkWindow *child, *parent;
12842
12843   if (animate)
12844     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12845                   "gtk-enable-animations", &animate,
12846                   NULL);
12847
12848   remove_auto_expand_timeout (tree_view);
12849
12850   if (node->children == NULL)
12851     return FALSE;
12852
12853   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12854
12855   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12856
12857   if (collapse)
12858     return FALSE;
12859
12860   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12861    * a chance to prelight the correct node below */
12862
12863   if (tree_view->priv->prelight_tree)
12864     {
12865       GtkRBTree *parent_tree;
12866       GtkRBNode *parent_node;
12867
12868       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12869       parent_node = tree_view->priv->prelight_tree->parent_node;
12870       while (parent_tree)
12871         {
12872           if (parent_tree == tree && parent_node == node)
12873             {
12874               ensure_unprelighted (tree_view);
12875               break;
12876             }
12877           parent_node = parent_tree->parent_node;
12878           parent_tree = parent_tree->parent_tree;
12879         }
12880     }
12881
12882   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12883
12884   for (list = tree_view->priv->columns; list; list = list->next)
12885     {
12886       GtkTreeViewColumn *column = list->data;
12887
12888       if (gtk_tree_view_column_get_visible (column) == FALSE)
12889         continue;
12890       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12891         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12892     }
12893
12894   if (tree_view->priv->destroy_count_func)
12895     {
12896       GtkTreePath *child_path;
12897       gint child_count = 0;
12898       child_path = gtk_tree_path_copy (path);
12899       gtk_tree_path_down (child_path);
12900       if (node->children)
12901         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12902       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12903       gtk_tree_path_free (child_path);
12904     }
12905
12906   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12907     {
12908       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12909
12910       if (gtk_tree_path_is_ancestor (path, cursor_path))
12911         {
12912           gtk_tree_row_reference_free (tree_view->priv->cursor);
12913           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12914                                                                       tree_view->priv->model,
12915                                                                       path);
12916         }
12917       gtk_tree_path_free (cursor_path);
12918     }
12919
12920   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12921     {
12922       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12923       if (gtk_tree_path_is_ancestor (path, anchor_path))
12924         {
12925           gtk_tree_row_reference_free (tree_view->priv->anchor);
12926           tree_view->priv->anchor = NULL;
12927         }
12928       gtk_tree_path_free (anchor_path);
12929     }
12930
12931   /* Stop a pending double click */
12932   tree_view->priv->last_button_x = -1;
12933   tree_view->priv->last_button_y = -1;
12934
12935   remove_expand_collapse_timeout (tree_view);
12936
12937   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12938     {
12939       _gtk_rbtree_remove (node->children);
12940       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12941     }
12942   else
12943     _gtk_rbtree_remove (node->children);
12944   
12945   if (animate)
12946     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12947   
12948   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12949     {
12950       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12951     }
12952
12953   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12954   
12955   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12956     {
12957       /* now that we've collapsed all rows, we want to try to set the prelight
12958        * again. To do this, we fake a motion event and send it to ourselves. */
12959
12960       child = tree_view->priv->bin_window;
12961       parent = gdk_window_get_parent (child);
12962
12963       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12964         {
12965           GdkEventMotion event;
12966           gint child_x, child_y;
12967
12968           gdk_window_get_position (child, &child_x, &child_y);
12969
12970           event.window = tree_view->priv->bin_window;
12971           event.x = x - child_x;
12972           event.y = y - child_y;
12973
12974           /* despite the fact this isn't a real event, I'm almost positive it will
12975            * never trigger a drag event.  maybe_drag is the only function that uses
12976            * more than just event.x and event.y. */
12977           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12978         }
12979     }
12980
12981   return TRUE;
12982 }
12983
12984 /**
12985  * gtk_tree_view_collapse_row:
12986  * @tree_view: a #GtkTreeView
12987  * @path: path to a row in the @tree_view
12988  *
12989  * Collapses a row (hides its child rows, if they exist).
12990  *
12991  * Return value: %TRUE if the row was collapsed.
12992  **/
12993 gboolean
12994 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12995                             GtkTreePath *path)
12996 {
12997   GtkRBTree *tree;
12998   GtkRBNode *node;
12999
13000   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13001   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
13002   g_return_val_if_fail (path != NULL, FALSE);
13003
13004   if (_gtk_tree_view_find_node (tree_view,
13005                                 path,
13006                                 &tree,
13007                                 &node))
13008     return FALSE;
13009
13010   if (tree == NULL || node->children == NULL)
13011     return FALSE;
13012
13013   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
13014 }
13015
13016 static void
13017 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
13018                                         GtkRBTree              *tree,
13019                                         GtkTreePath            *path,
13020                                         GtkTreeViewMappingFunc  func,
13021                                         gpointer                user_data)
13022 {
13023   GtkRBNode *node;
13024
13025   if (tree == NULL || tree->root == NULL)
13026     return;
13027
13028   node = tree->root;
13029
13030   while (node && node->left != tree->nil)
13031     node = node->left;
13032
13033   while (node)
13034     {
13035       if (node->children)
13036         {
13037           (* func) (tree_view, path, user_data);
13038           gtk_tree_path_down (path);
13039           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
13040           gtk_tree_path_up (path);
13041         }
13042       gtk_tree_path_next (path);
13043       node = _gtk_rbtree_next (tree, node);
13044     }
13045 }
13046
13047 /**
13048  * gtk_tree_view_map_expanded_rows:
13049  * @tree_view: A #GtkTreeView
13050  * @func: (scope call): A function to be called
13051  * @data: User data to be passed to the function.
13052  *
13053  * Calls @func on all expanded rows.
13054  **/
13055 void
13056 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
13057                                  GtkTreeViewMappingFunc  func,
13058                                  gpointer                user_data)
13059 {
13060   GtkTreePath *path;
13061
13062   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13063   g_return_if_fail (func != NULL);
13064
13065   path = gtk_tree_path_new_first ();
13066
13067   gtk_tree_view_map_expanded_rows_helper (tree_view,
13068                                           tree_view->priv->tree,
13069                                           path, func, user_data);
13070
13071   gtk_tree_path_free (path);
13072 }
13073
13074 /**
13075  * gtk_tree_view_row_expanded:
13076  * @tree_view: A #GtkTreeView.
13077  * @path: A #GtkTreePath to test expansion state.
13078  *
13079  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13080  *
13081  * Return value: %TRUE if #path is expanded.
13082  **/
13083 gboolean
13084 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13085                             GtkTreePath *path)
13086 {
13087   GtkRBTree *tree;
13088   GtkRBNode *node;
13089
13090   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13091   g_return_val_if_fail (path != NULL, FALSE);
13092
13093   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13094
13095   if (node == NULL)
13096     return FALSE;
13097
13098   return (node->children != NULL);
13099 }
13100
13101 /**
13102  * gtk_tree_view_get_reorderable:
13103  * @tree_view: a #GtkTreeView
13104  *
13105  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13106  * gtk_tree_view_set_reorderable().
13107  *
13108  * Return value: %TRUE if the tree can be reordered.
13109  **/
13110 gboolean
13111 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13112 {
13113   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13114
13115   return tree_view->priv->reorderable;
13116 }
13117
13118 /**
13119  * gtk_tree_view_set_reorderable:
13120  * @tree_view: A #GtkTreeView.
13121  * @reorderable: %TRUE, if the tree can be reordered.
13122  *
13123  * This function is a convenience function to allow you to reorder
13124  * models that support the #GtkDragSourceIface and the
13125  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13126  * these.  If @reorderable is %TRUE, then the user can reorder the
13127  * model by dragging and dropping rows. The developer can listen to
13128  * these changes by connecting to the model's row_inserted and
13129  * row_deleted signals. The reordering is implemented by setting up
13130  * the tree view as a drag source and destination. Therefore, drag and
13131  * drop can not be used in a reorderable view for any other purpose.
13132  *
13133  * This function does not give you any degree of control over the order -- any
13134  * reordering is allowed.  If more control is needed, you should probably
13135  * handle drag and drop manually.
13136  **/
13137 void
13138 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13139                                gboolean     reorderable)
13140 {
13141   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13142
13143   reorderable = reorderable != FALSE;
13144
13145   if (tree_view->priv->reorderable == reorderable)
13146     return;
13147
13148   if (reorderable)
13149     {
13150       const GtkTargetEntry row_targets[] = {
13151         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13152       };
13153
13154       gtk_tree_view_enable_model_drag_source (tree_view,
13155                                               GDK_BUTTON1_MASK,
13156                                               row_targets,
13157                                               G_N_ELEMENTS (row_targets),
13158                                               GDK_ACTION_MOVE);
13159       gtk_tree_view_enable_model_drag_dest (tree_view,
13160                                             row_targets,
13161                                             G_N_ELEMENTS (row_targets),
13162                                             GDK_ACTION_MOVE);
13163     }
13164   else
13165     {
13166       gtk_tree_view_unset_rows_drag_source (tree_view);
13167       gtk_tree_view_unset_rows_drag_dest (tree_view);
13168     }
13169
13170   tree_view->priv->reorderable = reorderable;
13171
13172   g_object_notify (G_OBJECT (tree_view), "reorderable");
13173 }
13174
13175 static void
13176 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13177                                GtkTreePath     *path,
13178                                gboolean         clear_and_select,
13179                                gboolean         clamp_node)
13180 {
13181   GtkRBTree *tree = NULL;
13182   GtkRBNode *node = NULL;
13183
13184   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13185     {
13186       GtkTreePath *cursor_path;
13187       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13188       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
13189       gtk_tree_path_free (cursor_path);
13190     }
13191
13192   gtk_tree_row_reference_free (tree_view->priv->cursor);
13193   tree_view->priv->cursor = NULL;
13194
13195   /* One cannot set the cursor on a separator.   Also, if
13196    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13197    * before finding the tree and node belonging to path.  The
13198    * path maps to a non-existing path and we will silently bail out.
13199    * We unset tree and node to avoid further processing.
13200    */
13201   if (!row_is_separator (tree_view, NULL, path)
13202       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
13203     {
13204       tree_view->priv->cursor =
13205           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
13206                                             tree_view->priv->model,
13207                                             path);
13208     }
13209   else
13210     {
13211       tree = NULL;
13212       node = NULL;
13213     }
13214
13215   if (tree != NULL)
13216     {
13217       GtkRBTree *new_tree = NULL;
13218       GtkRBNode *new_node = NULL;
13219
13220       if (clear_and_select && !tree_view->priv->ctrl_pressed)
13221         {
13222           GtkTreeSelectMode mode = 0;
13223
13224           if (tree_view->priv->ctrl_pressed)
13225             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
13226           if (tree_view->priv->shift_pressed)
13227             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13228
13229           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13230                                                     node, tree, path, mode,
13231                                                     FALSE);
13232         }
13233
13234       /* We have to re-find tree and node here again, somebody might have
13235        * cleared the node or the whole tree in the GtkTreeSelection::changed
13236        * callback. If the nodes differ we bail out here.
13237        */
13238       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13239
13240       if (tree != new_tree || node != new_node)
13241         return;
13242
13243       if (clamp_node)
13244         {
13245           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
13246           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13247         }
13248     }
13249
13250   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13251 }
13252
13253 /**
13254  * gtk_tree_view_get_cursor:
13255  * @tree_view: A #GtkTreeView
13256  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13257  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
13258  *
13259  * Fills in @path and @focus_column with the current path and focus column.  If
13260  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13261  * currently has focus, then *@focus_column will be %NULL.
13262  *
13263  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13264  * you are done with it.
13265  **/
13266 void
13267 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13268                           GtkTreePath       **path,
13269                           GtkTreeViewColumn **focus_column)
13270 {
13271   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13272
13273   if (path)
13274     {
13275       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13276         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13277       else
13278         *path = NULL;
13279     }
13280
13281   if (focus_column)
13282     {
13283       *focus_column = tree_view->priv->focus_column;
13284     }
13285 }
13286
13287 /**
13288  * gtk_tree_view_set_cursor:
13289  * @tree_view: A #GtkTreeView
13290  * @path: A #GtkTreePath
13291  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13292  * @start_editing: %TRUE if the specified cell should start being edited.
13293  *
13294  * Sets the current keyboard focus to be at @path, and selects it.  This is
13295  * useful when you want to focus the user's attention on a particular row.  If
13296  * @focus_column is not %NULL, then focus is given to the column specified by 
13297  * it. Additionally, if @focus_column is specified, and @start_editing is 
13298  * %TRUE, then editing should be started in the specified cell.  
13299  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13300  * in order to give keyboard focus to the widget.  Please note that editing 
13301  * can only happen when the widget is realized.
13302  *
13303  * If @path is invalid for @model, the current cursor (if any) will be unset
13304  * and the function will return without failing.
13305  **/
13306 void
13307 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13308                           GtkTreePath       *path,
13309                           GtkTreeViewColumn *focus_column,
13310                           gboolean           start_editing)
13311 {
13312   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13313                                     NULL, start_editing);
13314 }
13315
13316 /**
13317  * gtk_tree_view_set_cursor_on_cell:
13318  * @tree_view: A #GtkTreeView
13319  * @path: A #GtkTreePath
13320  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13321  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13322  * @start_editing: %TRUE if the specified cell should start being edited.
13323  *
13324  * Sets the current keyboard focus to be at @path, and selects it.  This is
13325  * useful when you want to focus the user's attention on a particular row.  If
13326  * @focus_column is not %NULL, then focus is given to the column specified by
13327  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13328  * contains 2 or more editable or activatable cells, then focus is given to
13329  * the cell specified by @focus_cell. Additionally, if @focus_column is
13330  * specified, and @start_editing is %TRUE, then editing should be started in
13331  * the specified cell.  This function is often followed by
13332  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13333  * widget.  Please note that editing can only happen when the widget is
13334  * realized.
13335  *
13336  * If @path is invalid for @model, the current cursor (if any) will be unset
13337  * and the function will return without failing.
13338  *
13339  * Since: 2.2
13340  **/
13341 void
13342 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13343                                   GtkTreePath       *path,
13344                                   GtkTreeViewColumn *focus_column,
13345                                   GtkCellRenderer   *focus_cell,
13346                                   gboolean           start_editing)
13347 {
13348   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13349   g_return_if_fail (path != NULL);
13350   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13351
13352   if (!tree_view->priv->model)
13353     return;
13354
13355   if (focus_cell)
13356     {
13357       g_return_if_fail (focus_column);
13358       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13359     }
13360
13361   /* cancel the current editing, if it exists */
13362   if (tree_view->priv->edited_column &&
13363       gtk_cell_area_get_edit_widget
13364       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13365     gtk_tree_view_stop_editing (tree_view, TRUE);
13366
13367   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
13368
13369   if (focus_column &&
13370       gtk_tree_view_column_get_visible (focus_column))
13371     {
13372       GList *list;
13373       gboolean column_in_tree = FALSE;
13374
13375       for (list = tree_view->priv->columns; list; list = list->next)
13376         if (list->data == focus_column)
13377           {
13378             column_in_tree = TRUE;
13379             break;
13380           }
13381       g_return_if_fail (column_in_tree);
13382       tree_view->priv->focus_column = focus_column;
13383       if (focus_cell)
13384         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13385       if (start_editing)
13386         gtk_tree_view_start_editing (tree_view, path, TRUE);
13387     }
13388 }
13389
13390 /**
13391  * gtk_tree_view_get_bin_window:
13392  * @tree_view: A #GtkTreeView
13393  *
13394  * Returns the window that @tree_view renders to.
13395  * This is used primarily to compare to <literal>event->window</literal>
13396  * to confirm that the event on @tree_view is on the right window.
13397  *
13398  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13399  *     hasn't been realized yet
13400  **/
13401 GdkWindow *
13402 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13403 {
13404   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13405
13406   return tree_view->priv->bin_window;
13407 }
13408
13409 /**
13410  * gtk_tree_view_get_path_at_pos:
13411  * @tree_view: A #GtkTreeView.
13412  * @x: The x position to be identified (relative to bin_window).
13413  * @y: The y position to be identified (relative to bin_window).
13414  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13415  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13416  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13417  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13418  *
13419  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13420  * (please see gtk_tree_view_get_bin_window()).
13421  * That is, @x and @y are relative to an events coordinates. @x and @y must
13422  * come from an event on the @tree_view only where <literal>event->window ==
13423  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13424  * things like popup menus. If @path is non-%NULL, then it will be filled
13425  * with the #GtkTreePath at that point.  This path should be freed with
13426  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13427  * with the column at that point.  @cell_x and @cell_y return the coordinates
13428  * relative to the cell background (i.e. the @background_area passed to
13429  * gtk_cell_renderer_render()).  This function is only meaningful if
13430  * @tree_view is realized.  Therefore this function will always return %FALSE
13431  * if @tree_view is not realized or does not have a model.
13432  *
13433  * For converting widget coordinates (eg. the ones you get from
13434  * GtkWidget::query-tooltip), please see
13435  * gtk_tree_view_convert_widget_to_bin_window_coords().
13436  *
13437  * Return value: %TRUE if a row exists at that coordinate.
13438  **/
13439 gboolean
13440 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13441                                gint                x,
13442                                gint                y,
13443                                GtkTreePath       **path,
13444                                GtkTreeViewColumn **column,
13445                                gint               *cell_x,
13446                                gint               *cell_y)
13447 {
13448   GtkRBTree *tree;
13449   GtkRBNode *node;
13450   gint y_offset;
13451
13452   g_return_val_if_fail (tree_view != NULL, FALSE);
13453
13454   if (path)
13455     *path = NULL;
13456   if (column)
13457     *column = NULL;
13458
13459   if (tree_view->priv->bin_window == NULL)
13460     return FALSE;
13461
13462   if (tree_view->priv->tree == NULL)
13463     return FALSE;
13464
13465   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13466     return FALSE;
13467
13468   if (x < 0 || y < 0)
13469     return FALSE;
13470
13471   if (column || cell_x)
13472     {
13473       GtkTreeViewColumn *tmp_column;
13474       GtkTreeViewColumn *last_column = NULL;
13475       GList *list;
13476       gint remaining_x = x;
13477       gboolean found = FALSE;
13478       gboolean rtl;
13479       gint width;
13480
13481       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13482       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13483            list;
13484            list = (rtl ? list->prev : list->next))
13485         {
13486           tmp_column = list->data;
13487
13488           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13489             continue;
13490
13491           last_column = tmp_column;
13492           width = gtk_tree_view_column_get_width (tmp_column);
13493           if (remaining_x <= width)
13494             {
13495               found = TRUE;
13496
13497               if (column)
13498                 *column = tmp_column;
13499
13500               if (cell_x)
13501                 *cell_x = remaining_x;
13502
13503               break;
13504             }
13505           remaining_x -= width;
13506         }
13507
13508       /* If found is FALSE and there is a last_column, then it the remainder
13509        * space is in that area
13510        */
13511       if (!found)
13512         {
13513           if (last_column)
13514             {
13515               if (column)
13516                 *column = last_column;
13517               
13518               if (cell_x)
13519                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13520             }
13521           else
13522             {
13523               return FALSE;
13524             }
13525         }
13526     }
13527
13528   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13529                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13530                                       &tree, &node);
13531
13532   if (tree == NULL)
13533     return FALSE;
13534
13535   if (cell_y)
13536     *cell_y = y_offset;
13537
13538   if (path)
13539     *path = _gtk_tree_view_find_path (tree_view, tree, node);
13540
13541   return TRUE;
13542 }
13543
13544
13545 static inline gint
13546 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13547                                     GtkRBNode   *node,
13548                                     gint         vertical_separator)
13549 {
13550   int height;
13551
13552   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13553    * i.e. just the cells, no spacing.
13554    *
13555    * The cell area height is at least expander_size - vertical_separator.
13556    * For regular nodes, the height is then at least expander_size. We should
13557    * be able to enforce the expander_size minimum here, because this
13558    * function will not be called for irregular (e.g. separator) rows.
13559    */
13560   height = gtk_tree_view_get_row_height (tree_view, node);
13561   if (height < tree_view->priv->expander_size)
13562     height = tree_view->priv->expander_size;
13563
13564   return height - vertical_separator;
13565 }
13566
13567 static inline gint
13568 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13569                                       GtkRBTree   *tree,
13570                                       GtkRBNode   *node,
13571                                       gint         vertical_separator)
13572 {
13573   int offset;
13574
13575   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13576   offset += vertical_separator / 2;
13577
13578   return offset;
13579 }
13580
13581 /**
13582  * gtk_tree_view_get_cell_area:
13583  * @tree_view: a #GtkTreeView
13584  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13585  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13586  * @rect: rectangle to fill with cell rect
13587  *
13588  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13589  * row specified by @path and the column specified by @column.  If @path is
13590  * %NULL, or points to a path not currently displayed, the @y and @height fields
13591  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13592  * fields will be filled with 0.  The sum of all cell rects does not cover the
13593  * entire tree; there are extra pixels in between rows, for example. The
13594  * returned rectangle is equivalent to the @cell_area passed to
13595  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13596  * realized.
13597  **/
13598 void
13599 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13600                              GtkTreePath        *path,
13601                              GtkTreeViewColumn  *column,
13602                              GdkRectangle       *rect)
13603 {
13604   GtkAllocation allocation;
13605   GtkRBTree *tree = NULL;
13606   GtkRBNode *node = NULL;
13607   gint vertical_separator;
13608   gint horizontal_separator;
13609
13610   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13611   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13612   g_return_if_fail (rect != NULL);
13613   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13614   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13615
13616   gtk_widget_style_get (GTK_WIDGET (tree_view),
13617                         "vertical-separator", &vertical_separator,
13618                         "horizontal-separator", &horizontal_separator,
13619                         NULL);
13620
13621   rect->x = 0;
13622   rect->y = 0;
13623   rect->width = 0;
13624   rect->height = 0;
13625
13626   if (column)
13627     {
13628       gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
13629       rect->x = allocation.x + horizontal_separator/2;
13630       rect->width = allocation.width - horizontal_separator;
13631     }
13632
13633   if (path)
13634     {
13635       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13636
13637       /* Get vertical coords */
13638       if ((!ret && tree == NULL) || ret)
13639         return;
13640
13641       if (row_is_separator (tree_view, NULL, path))
13642         {
13643           /* There isn't really a "cell area" for separator, so we
13644            * return the y, height values for background area instead.
13645            */
13646           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13647           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13648         }
13649       else
13650         {
13651           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13652                                                           vertical_separator);
13653           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13654                                                              vertical_separator);
13655         }
13656
13657       if (column &&
13658           gtk_tree_view_is_expander_column (tree_view, column))
13659         {
13660           gint depth = gtk_tree_path_get_depth (path);
13661           gboolean rtl;
13662
13663           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13664
13665           if (!rtl)
13666             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13667           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13668
13669           if (gtk_tree_view_draw_expanders (tree_view))
13670             {
13671               if (!rtl)
13672                 rect->x += depth * tree_view->priv->expander_size;
13673               rect->width -= depth * tree_view->priv->expander_size;
13674             }
13675
13676           rect->width = MAX (rect->width, 0);
13677         }
13678     }
13679 }
13680
13681 static inline gint
13682 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13683                               GtkRBNode   *node)
13684 {
13685   int height;
13686
13687   /* The "background" areas of all rows/cells add up to cover the entire tree.
13688    * The background includes all inter-row and inter-cell spacing.
13689    *
13690    * If the row pointed at by node does not have a height set, we default
13691    * to expander_size, which is the minimum height for regular nodes.
13692    * Non-regular nodes (e.g. separators) can have a height set smaller
13693    * than expander_size and should not be overruled here.
13694    */
13695   height = GTK_RBNODE_GET_HEIGHT (node);
13696   if (height <= 0)
13697     height = tree_view->priv->expander_size;
13698
13699   return height;
13700 }
13701
13702 static inline gint
13703 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13704                                 GtkRBTree   *tree,
13705                                 GtkRBNode   *node)
13706 {
13707   int offset;
13708
13709   offset = _gtk_rbtree_node_find_offset (tree, node);
13710
13711   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13712 }
13713
13714 /**
13715  * gtk_tree_view_get_background_area:
13716  * @tree_view: a #GtkTreeView
13717  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13718  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13719  * @rect: rectangle to fill with cell background rect
13720  *
13721  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13722  * row specified by @path and the column specified by @column.  If @path is
13723  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13724  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13725  * fields will be filled with 0.  The returned rectangle is equivalent to the
13726  * @background_area passed to gtk_cell_renderer_render().  These background
13727  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13728  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13729  * itself, excluding surrounding borders and the tree expander area.
13730  *
13731  **/
13732 void
13733 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13734                                    GtkTreePath        *path,
13735                                    GtkTreeViewColumn  *column,
13736                                    GdkRectangle       *rect)
13737 {
13738   GtkRBTree *tree = NULL;
13739   GtkRBNode *node = NULL;
13740
13741   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13742   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13743   g_return_if_fail (rect != NULL);
13744
13745   rect->x = 0;
13746   rect->y = 0;
13747   rect->width = 0;
13748   rect->height = 0;
13749
13750   if (path)
13751     {
13752       /* Get vertical coords */
13753
13754       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13755           tree == NULL)
13756         return;
13757
13758       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13759       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13760     }
13761
13762   if (column)
13763     {
13764       gint x2 = 0;
13765
13766       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13767       rect->width = x2 - rect->x;
13768     }
13769 }
13770
13771 /**
13772  * gtk_tree_view_get_visible_rect:
13773  * @tree_view: a #GtkTreeView
13774  * @visible_rect: rectangle to fill
13775  *
13776  * Fills @visible_rect with the currently-visible region of the
13777  * buffer, in tree coordinates. Convert to bin_window coordinates with
13778  * gtk_tree_view_convert_tree_to_bin_window_coords().
13779  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13780  * scrollable area of the tree.
13781  **/
13782 void
13783 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13784                                 GdkRectangle *visible_rect)
13785 {
13786   GtkAllocation allocation;
13787   GtkWidget *widget;
13788
13789   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13790
13791   widget = GTK_WIDGET (tree_view);
13792
13793   if (visible_rect)
13794     {
13795       gtk_widget_get_allocation (widget, &allocation);
13796       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13797       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13798       visible_rect->width = allocation.width;
13799       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13800     }
13801 }
13802
13803 /**
13804  * gtk_tree_view_convert_widget_to_tree_coords:
13805  * @tree_view: a #GtkTreeView
13806  * @wx: X coordinate relative to the widget
13807  * @wy: Y coordinate relative to the widget
13808  * @tx: return location for tree X coordinate
13809  * @ty: return location for tree Y coordinate
13810  *
13811  * Converts widget coordinates to coordinates for the
13812  * tree (the full scrollable area of the tree).
13813  *
13814  * Since: 2.12
13815  **/
13816 void
13817 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13818                                              gint         wx,
13819                                              gint         wy,
13820                                              gint        *tx,
13821                                              gint        *ty)
13822 {
13823   gint x, y;
13824
13825   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13826
13827   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13828                                                      wx, wy,
13829                                                      &x, &y);
13830   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13831                                                    x, y,
13832                                                    tx, ty);
13833 }
13834
13835 /**
13836  * gtk_tree_view_convert_tree_to_widget_coords:
13837  * @tree_view: a #GtkTreeView
13838  * @tx: X coordinate relative to the tree
13839  * @ty: Y coordinate relative to the tree
13840  * @wx: return location for widget X coordinate
13841  * @wy: return location for widget Y coordinate
13842  *
13843  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13844  * to widget coordinates.
13845  *
13846  * Since: 2.12
13847  **/
13848 void
13849 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13850                                              gint         tx,
13851                                              gint         ty,
13852                                              gint        *wx,
13853                                              gint        *wy)
13854 {
13855   gint x, y;
13856
13857   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13858
13859   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13860                                                    tx, ty,
13861                                                    &x, &y);
13862   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13863                                                      x, y,
13864                                                      wx, wy);
13865 }
13866
13867 /**
13868  * gtk_tree_view_convert_widget_to_bin_window_coords:
13869  * @tree_view: a #GtkTreeView
13870  * @wx: X coordinate relative to the widget
13871  * @wy: Y coordinate relative to the widget
13872  * @bx: return location for bin_window X coordinate
13873  * @by: return location for bin_window Y coordinate
13874  *
13875  * Converts widget coordinates to coordinates for the bin_window
13876  * (see gtk_tree_view_get_bin_window()).
13877  *
13878  * Since: 2.12
13879  **/
13880 void
13881 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13882                                                    gint         wx,
13883                                                    gint         wy,
13884                                                    gint        *bx,
13885                                                    gint        *by)
13886 {
13887   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13888
13889   if (bx)
13890     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13891   if (by)
13892     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13893 }
13894
13895 /**
13896  * gtk_tree_view_convert_bin_window_to_widget_coords:
13897  * @tree_view: a #GtkTreeView
13898  * @bx: bin_window X coordinate
13899  * @by: bin_window Y coordinate
13900  * @wx: return location for widget X coordinate
13901  * @wy: return location for widget Y coordinate
13902  *
13903  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13904  * to widget relative coordinates.
13905  *
13906  * Since: 2.12
13907  **/
13908 void
13909 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13910                                                    gint         bx,
13911                                                    gint         by,
13912                                                    gint        *wx,
13913                                                    gint        *wy)
13914 {
13915   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13916
13917   if (wx)
13918     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13919   if (wy)
13920     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13921 }
13922
13923 /**
13924  * gtk_tree_view_convert_tree_to_bin_window_coords:
13925  * @tree_view: a #GtkTreeView
13926  * @tx: tree X coordinate
13927  * @ty: tree Y coordinate
13928  * @bx: return location for X coordinate relative to bin_window
13929  * @by: return location for Y coordinate relative to bin_window
13930  *
13931  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13932  * to bin_window coordinates.
13933  *
13934  * Since: 2.12
13935  **/
13936 void
13937 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13938                                                  gint         tx,
13939                                                  gint         ty,
13940                                                  gint        *bx,
13941                                                  gint        *by)
13942 {
13943   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13944
13945   if (bx)
13946     *bx = tx;
13947   if (by)
13948     *by = ty - tree_view->priv->dy;
13949 }
13950
13951 /**
13952  * gtk_tree_view_convert_bin_window_to_tree_coords:
13953  * @tree_view: a #GtkTreeView
13954  * @bx: X coordinate relative to bin_window
13955  * @by: Y coordinate relative to bin_window
13956  * @tx: return location for tree X coordinate
13957  * @ty: return location for tree Y coordinate
13958  *
13959  * Converts bin_window coordinates to coordinates for the
13960  * tree (the full scrollable area of the tree).
13961  *
13962  * Since: 2.12
13963  **/
13964 void
13965 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13966                                                  gint         bx,
13967                                                  gint         by,
13968                                                  gint        *tx,
13969                                                  gint        *ty)
13970 {
13971   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13972
13973   if (tx)
13974     *tx = bx;
13975   if (ty)
13976     *ty = by + tree_view->priv->dy;
13977 }
13978
13979
13980
13981 /**
13982  * gtk_tree_view_get_visible_range:
13983  * @tree_view: A #GtkTreeView
13984  * @start_path: (allow-none): Return location for start of region, or %NULL.
13985  * @end_path: (allow-none): Return location for end of region, or %NULL.
13986  *
13987  * Sets @start_path and @end_path to be the first and last visible path.
13988  * Note that there may be invisible paths in between.
13989  *
13990  * The paths should be freed with gtk_tree_path_free() after use.
13991  *
13992  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13993  *
13994  * Since: 2.8
13995  **/
13996 gboolean
13997 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13998                                  GtkTreePath **start_path,
13999                                  GtkTreePath **end_path)
14000 {
14001   GtkRBTree *tree;
14002   GtkRBNode *node;
14003   gboolean retval;
14004   
14005   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14006
14007   if (!tree_view->priv->tree)
14008     return FALSE;
14009
14010   retval = TRUE;
14011
14012   if (start_path)
14013     {
14014       _gtk_rbtree_find_offset (tree_view->priv->tree,
14015                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
14016                                &tree, &node);
14017       if (node)
14018         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
14019       else
14020         retval = FALSE;
14021     }
14022
14023   if (end_path)
14024     {
14025       gint y;
14026
14027       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
14028         y = tree_view->priv->height - 1;
14029       else
14030         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
14031
14032       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
14033       if (node)
14034         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
14035       else
14036         retval = FALSE;
14037     }
14038
14039   return retval;
14040 }
14041
14042 static void
14043 unset_reorderable (GtkTreeView *tree_view)
14044 {
14045   if (tree_view->priv->reorderable)
14046     {
14047       tree_view->priv->reorderable = FALSE;
14048       g_object_notify (G_OBJECT (tree_view), "reorderable");
14049     }
14050 }
14051
14052 /**
14053  * gtk_tree_view_enable_model_drag_source:
14054  * @tree_view: a #GtkTreeView
14055  * @start_button_mask: Mask of allowed buttons to start drag
14056  * @targets: (array): the table of targets that the drag will support
14057  * @n_targets: the number of items in @targets
14058  * @actions: the bitmask of possible actions for a drag from this
14059  *    widget
14060  *
14061  * Turns @tree_view into a drag source for automatic DND. Calling this
14062  * method sets #GtkTreeView:reorderable to %FALSE.
14063  **/
14064 void
14065 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14066                                         GdkModifierType           start_button_mask,
14067                                         const GtkTargetEntry     *targets,
14068                                         gint                      n_targets,
14069                                         GdkDragAction             actions)
14070 {
14071   TreeViewDragInfo *di;
14072
14073   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14074
14075   gtk_drag_source_set (GTK_WIDGET (tree_view),
14076                        0,
14077                        targets,
14078                        n_targets,
14079                        actions);
14080
14081   di = ensure_info (tree_view);
14082
14083   di->start_button_mask = start_button_mask;
14084   di->source_actions = actions;
14085   di->source_set = TRUE;
14086
14087   unset_reorderable (tree_view);
14088 }
14089
14090 /**
14091  * gtk_tree_view_enable_model_drag_dest:
14092  * @tree_view: a #GtkTreeView
14093  * @targets: (array): the table of targets that the drag will support
14094  * @n_targets: the number of items in @targets
14095  * @actions: the bitmask of possible actions for a drag from this
14096  *    widget
14097  * 
14098  * Turns @tree_view into a drop destination for automatic DND. Calling
14099  * this method sets #GtkTreeView:reorderable to %FALSE.
14100  **/
14101 void
14102 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14103                                       const GtkTargetEntry     *targets,
14104                                       gint                      n_targets,
14105                                       GdkDragAction             actions)
14106 {
14107   TreeViewDragInfo *di;
14108
14109   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14110
14111   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14112                      0,
14113                      targets,
14114                      n_targets,
14115                      actions);
14116
14117   di = ensure_info (tree_view);
14118   di->dest_set = TRUE;
14119
14120   unset_reorderable (tree_view);
14121 }
14122
14123 /**
14124  * gtk_tree_view_unset_rows_drag_source:
14125  * @tree_view: a #GtkTreeView
14126  *
14127  * Undoes the effect of
14128  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14129  * #GtkTreeView:reorderable to %FALSE.
14130  **/
14131 void
14132 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14133 {
14134   TreeViewDragInfo *di;
14135
14136   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14137
14138   di = get_info (tree_view);
14139
14140   if (di)
14141     {
14142       if (di->source_set)
14143         {
14144           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14145           di->source_set = FALSE;
14146         }
14147
14148       if (!di->dest_set && !di->source_set)
14149         remove_info (tree_view);
14150     }
14151   
14152   unset_reorderable (tree_view);
14153 }
14154
14155 /**
14156  * gtk_tree_view_unset_rows_drag_dest:
14157  * @tree_view: a #GtkTreeView
14158  *
14159  * Undoes the effect of
14160  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14161  * #GtkTreeView:reorderable to %FALSE.
14162  **/
14163 void
14164 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14165 {
14166   TreeViewDragInfo *di;
14167
14168   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14169
14170   di = get_info (tree_view);
14171
14172   if (di)
14173     {
14174       if (di->dest_set)
14175         {
14176           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14177           di->dest_set = FALSE;
14178         }
14179
14180       if (!di->dest_set && !di->source_set)
14181         remove_info (tree_view);
14182     }
14183
14184   unset_reorderable (tree_view);
14185 }
14186
14187 /**
14188  * gtk_tree_view_set_drag_dest_row:
14189  * @tree_view: a #GtkTreeView
14190  * @path: (allow-none): The path of the row to highlight, or %NULL.
14191  * @pos: Specifies whether to drop before, after or into the row
14192  * 
14193  * Sets the row that is highlighted for feedback.
14194  **/
14195 void
14196 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14197                                  GtkTreePath            *path,
14198                                  GtkTreeViewDropPosition pos)
14199 {
14200   GtkTreePath *current_dest;
14201
14202   /* Note; this function is exported to allow a custom DND
14203    * implementation, so it can't touch TreeViewDragInfo
14204    */
14205
14206   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14207
14208   current_dest = NULL;
14209
14210   if (tree_view->priv->drag_dest_row)
14211     {
14212       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14213       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14214     }
14215
14216   /* special case a drop on an empty model */
14217   tree_view->priv->empty_view_drop = 0;
14218
14219   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14220       && gtk_tree_path_get_depth (path) == 1
14221       && gtk_tree_path_get_indices (path)[0] == 0)
14222     {
14223       gint n_children;
14224
14225       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14226                                                    NULL);
14227
14228       if (!n_children)
14229         tree_view->priv->empty_view_drop = 1;
14230     }
14231
14232   tree_view->priv->drag_dest_pos = pos;
14233
14234   if (path)
14235     {
14236       tree_view->priv->drag_dest_row =
14237         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14238       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14239     }
14240   else
14241     tree_view->priv->drag_dest_row = NULL;
14242
14243   if (current_dest)
14244     {
14245       GtkRBTree *tree, *new_tree;
14246       GtkRBNode *node, *new_node;
14247
14248       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14249       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14250
14251       if (tree && node)
14252         {
14253           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14254           if (new_tree && new_node)
14255             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14256
14257           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14258           if (new_tree && new_node)
14259             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14260         }
14261       gtk_tree_path_free (current_dest);
14262     }
14263 }
14264
14265 /**
14266  * gtk_tree_view_get_drag_dest_row:
14267  * @tree_view: a #GtkTreeView
14268  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14269  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14270  * 
14271  * Gets information about the row that is highlighted for feedback.
14272  **/
14273 void
14274 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14275                                  GtkTreePath             **path,
14276                                  GtkTreeViewDropPosition  *pos)
14277 {
14278   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14279
14280   if (path)
14281     {
14282       if (tree_view->priv->drag_dest_row)
14283         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14284       else
14285         {
14286           if (tree_view->priv->empty_view_drop)
14287             *path = gtk_tree_path_new_from_indices (0, -1);
14288           else
14289             *path = NULL;
14290         }
14291     }
14292
14293   if (pos)
14294     *pos = tree_view->priv->drag_dest_pos;
14295 }
14296
14297 /**
14298  * gtk_tree_view_get_dest_row_at_pos:
14299  * @tree_view: a #GtkTreeView
14300  * @drag_x: the position to determine the destination row for
14301  * @drag_y: the position to determine the destination row for
14302  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14303  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14304  * 
14305  * Determines the destination row for a given position.  @drag_x and
14306  * @drag_y are expected to be in widget coordinates.  This function is only
14307  * meaningful if @tree_view is realized.  Therefore this function will always
14308  * return %FALSE if @tree_view is not realized or does not have a model.
14309  * 
14310  * Return value: whether there is a row at the given position, %TRUE if this
14311  * is indeed the case.
14312  **/
14313 gboolean
14314 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14315                                    gint                     drag_x,
14316                                    gint                     drag_y,
14317                                    GtkTreePath            **path,
14318                                    GtkTreeViewDropPosition *pos)
14319 {
14320   gint cell_y;
14321   gint bin_x, bin_y;
14322   gdouble offset_into_row;
14323   gdouble third;
14324   GdkRectangle cell;
14325   GtkTreeViewColumn *column = NULL;
14326   GtkTreePath *tmp_path = NULL;
14327
14328   /* Note; this function is exported to allow a custom DND
14329    * implementation, so it can't touch TreeViewDragInfo
14330    */
14331
14332   g_return_val_if_fail (tree_view != NULL, FALSE);
14333   g_return_val_if_fail (drag_x >= 0, FALSE);
14334   g_return_val_if_fail (drag_y >= 0, FALSE);
14335
14336   if (path)
14337     *path = NULL;
14338
14339   if (tree_view->priv->bin_window == NULL)
14340     return FALSE;
14341
14342   if (tree_view->priv->tree == NULL)
14343     return FALSE;
14344
14345   /* If in the top third of a row, we drop before that row; if
14346    * in the bottom third, drop after that row; if in the middle,
14347    * and the row has children, drop into the row.
14348    */
14349   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14350                                                      &bin_x, &bin_y);
14351
14352   if (!gtk_tree_view_get_path_at_pos (tree_view,
14353                                       bin_x,
14354                                       bin_y,
14355                                       &tmp_path,
14356                                       &column,
14357                                       NULL,
14358                                       &cell_y))
14359     return FALSE;
14360
14361   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14362                                      &cell);
14363
14364   offset_into_row = cell_y;
14365
14366   if (path)
14367     *path = tmp_path;
14368   else
14369     gtk_tree_path_free (tmp_path);
14370
14371   tmp_path = NULL;
14372
14373   third = cell.height / 3.0;
14374
14375   if (pos)
14376     {
14377       if (offset_into_row < third)
14378         {
14379           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14380         }
14381       else if (offset_into_row < (cell.height / 2.0))
14382         {
14383           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14384         }
14385       else if (offset_into_row < third * 2.0)
14386         {
14387           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14388         }
14389       else
14390         {
14391           *pos = GTK_TREE_VIEW_DROP_AFTER;
14392         }
14393     }
14394
14395   return TRUE;
14396 }
14397
14398
14399
14400 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14401 /**
14402  * gtk_tree_view_create_row_drag_icon:
14403  * @tree_view: a #GtkTreeView
14404  * @path: a #GtkTreePath in @tree_view
14405  *
14406  * Creates a #cairo_surface_t representation of the row at @path.  
14407  * This image is used for a drag icon.
14408  *
14409  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14410  **/
14411 cairo_surface_t *
14412 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14413                                     GtkTreePath  *path)
14414 {
14415   GtkTreeIter   iter;
14416   GtkRBTree    *tree;
14417   GtkRBNode    *node;
14418   GtkStyle *style;
14419   gint cell_offset;
14420   GList *list;
14421   GdkRectangle background_area;
14422   GtkWidget *widget;
14423   gint depth;
14424   /* start drawing inside the black outline */
14425   gint x = 1, y = 1;
14426   cairo_surface_t *surface;
14427   gint bin_window_width;
14428   gboolean is_separator = FALSE;
14429   gboolean rtl;
14430   cairo_t *cr;
14431
14432   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14433   g_return_val_if_fail (path != NULL, NULL);
14434
14435   widget = GTK_WIDGET (tree_view);
14436
14437   if (!gtk_widget_get_realized (widget))
14438     return NULL;
14439
14440   depth = gtk_tree_path_get_depth (path);
14441
14442   _gtk_tree_view_find_node (tree_view,
14443                             path,
14444                             &tree,
14445                             &node);
14446
14447   if (tree == NULL)
14448     return NULL;
14449
14450   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14451                                 &iter,
14452                                 path))
14453     return NULL;
14454
14455   style = gtk_widget_get_style (widget);
14456
14457   is_separator = row_is_separator (tree_view, &iter, NULL);
14458
14459   cell_offset = x;
14460
14461   background_area.y = y;
14462   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14463
14464   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14465
14466   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14467                                                CAIRO_CONTENT_COLOR,
14468                                                bin_window_width + 2,
14469                                                background_area.height + 2);
14470
14471   cr = cairo_create (surface);
14472   gdk_cairo_set_source_color (cr, &style->base [gtk_widget_get_state (widget)]);
14473   cairo_paint (cr);
14474
14475   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14476
14477   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14478       list;
14479       list = (rtl ? list->prev : list->next))
14480     {
14481       GtkTreeViewColumn *column = list->data;
14482       GdkRectangle cell_area;
14483       gint vertical_separator;
14484
14485       if (!gtk_tree_view_column_get_visible (column))
14486         continue;
14487
14488       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14489                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14490                                                node->children?TRUE:FALSE);
14491
14492       background_area.x = cell_offset;
14493       background_area.width = gtk_tree_view_column_get_width (column);
14494
14495       gtk_widget_style_get (widget,
14496                             "vertical-separator", &vertical_separator,
14497                             NULL);
14498
14499       cell_area = background_area;
14500
14501       cell_area.y += vertical_separator / 2;
14502       cell_area.height -= vertical_separator;
14503
14504       if (gtk_tree_view_is_expander_column (tree_view, column))
14505         {
14506           if (!rtl)
14507             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14508           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14509
14510           if (gtk_tree_view_draw_expanders (tree_view))
14511             {
14512               if (!rtl)
14513                 cell_area.x += depth * tree_view->priv->expander_size;
14514               cell_area.width -= depth * tree_view->priv->expander_size;
14515             }
14516         }
14517
14518       if (gtk_tree_view_column_cell_is_visible (column))
14519         {
14520           if (is_separator)
14521             gtk_paint_hline (style,
14522                                    cr,
14523                                    GTK_STATE_NORMAL,
14524                                    widget,
14525                                    NULL,
14526                                    cell_area.x,
14527                                    cell_area.x + cell_area.width,
14528                                    cell_area.y + cell_area.height / 2);
14529           else
14530             _gtk_tree_view_column_cell_render (column,
14531                                                cr,
14532                                                &background_area,
14533                                                &cell_area,
14534                                                0, FALSE);
14535         }
14536       cell_offset += gtk_tree_view_column_get_width (column);
14537     }
14538
14539   cairo_set_source_rgb (cr, 0, 0, 0);
14540   cairo_rectangle (cr, 
14541                    0.5, 0.5, 
14542                    bin_window_width + 1,
14543                    background_area.height + 1);
14544   cairo_set_line_width (cr, 1.0);
14545   cairo_stroke (cr);
14546
14547   cairo_destroy (cr);
14548
14549   cairo_surface_set_device_offset (surface, 2, 2);
14550
14551   return surface;
14552 }
14553
14554
14555 /**
14556  * gtk_tree_view_set_destroy_count_func:
14557  * @tree_view: A #GtkTreeView
14558  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14559  * @data: (allow-none): User data to be passed to @func, or %NULL
14560  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14561  *
14562  * This function should almost never be used.  It is meant for private use by
14563  * ATK for determining the number of visible children that are removed when the
14564  * user collapses a row, or a row is deleted.
14565  **/
14566 void
14567 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14568                                       GtkTreeDestroyCountFunc  func,
14569                                       gpointer                 data,
14570                                       GDestroyNotify           destroy)
14571 {
14572   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14573
14574   if (tree_view->priv->destroy_count_destroy)
14575     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14576
14577   tree_view->priv->destroy_count_func = func;
14578   tree_view->priv->destroy_count_data = data;
14579   tree_view->priv->destroy_count_destroy = destroy;
14580 }
14581
14582
14583 /*
14584  * Interactive search
14585  */
14586
14587 /**
14588  * gtk_tree_view_set_enable_search:
14589  * @tree_view: A #GtkTreeView
14590  * @enable_search: %TRUE, if the user can search interactively
14591  *
14592  * If @enable_search is set, then the user can type in text to search through
14593  * the tree interactively (this is sometimes called "typeahead find").
14594  * 
14595  * Note that even if this is %FALSE, the user can still initiate a search 
14596  * using the "start-interactive-search" key binding.
14597  */
14598 void
14599 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14600                                  gboolean     enable_search)
14601 {
14602   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14603
14604   enable_search = !!enable_search;
14605   
14606   if (tree_view->priv->enable_search != enable_search)
14607     {
14608        tree_view->priv->enable_search = enable_search;
14609        g_object_notify (G_OBJECT (tree_view), "enable-search");
14610     }
14611 }
14612
14613 /**
14614  * gtk_tree_view_get_enable_search:
14615  * @tree_view: A #GtkTreeView
14616  *
14617  * Returns whether or not the tree allows to start interactive searching 
14618  * by typing in text.
14619  *
14620  * Return value: whether or not to let the user search interactively
14621  */
14622 gboolean
14623 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14624 {
14625   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14626
14627   return tree_view->priv->enable_search;
14628 }
14629
14630
14631 /**
14632  * gtk_tree_view_get_search_column:
14633  * @tree_view: A #GtkTreeView
14634  *
14635  * Gets the column searched on by the interactive search code.
14636  *
14637  * Return value: the column the interactive search code searches in.
14638  */
14639 gint
14640 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14641 {
14642   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14643
14644   return (tree_view->priv->search_column);
14645 }
14646
14647 /**
14648  * gtk_tree_view_set_search_column:
14649  * @tree_view: A #GtkTreeView
14650  * @column: the column of the model to search in, or -1 to disable searching
14651  *
14652  * Sets @column as the column where the interactive search code should
14653  * search in for the current model. 
14654  * 
14655  * If the search column is set, users can use the "start-interactive-search"
14656  * key binding to bring up search popup. The enable-search property controls
14657  * whether simply typing text will also start an interactive search.
14658  *
14659  * Note that @column refers to a column of the current model. The search 
14660  * column is reset to -1 when the model is changed.
14661  */
14662 void
14663 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14664                                  gint         column)
14665 {
14666   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14667   g_return_if_fail (column >= -1);
14668
14669   if (tree_view->priv->search_column == column)
14670     return;
14671
14672   tree_view->priv->search_column = column;
14673   g_object_notify (G_OBJECT (tree_view), "search-column");
14674 }
14675
14676 /**
14677  * gtk_tree_view_get_search_equal_func:
14678  * @tree_view: A #GtkTreeView
14679  *
14680  * Returns the compare function currently in use.
14681  *
14682  * Return value: the currently used compare function for the search code.
14683  */
14684
14685 GtkTreeViewSearchEqualFunc
14686 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14687 {
14688   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14689
14690   return tree_view->priv->search_equal_func;
14691 }
14692
14693 /**
14694  * gtk_tree_view_set_search_equal_func:
14695  * @tree_view: A #GtkTreeView
14696  * @search_equal_func: the compare function to use during the search
14697  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14698  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14699  *
14700  * Sets the compare function for the interactive search capabilities; note
14701  * that somewhat like strcmp() returning 0 for equality
14702  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14703  **/
14704 void
14705 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14706                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14707                                      gpointer                    search_user_data,
14708                                      GDestroyNotify              search_destroy)
14709 {
14710   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14711   g_return_if_fail (search_equal_func != NULL);
14712
14713   if (tree_view->priv->search_destroy)
14714     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14715
14716   tree_view->priv->search_equal_func = search_equal_func;
14717   tree_view->priv->search_user_data = search_user_data;
14718   tree_view->priv->search_destroy = search_destroy;
14719   if (tree_view->priv->search_equal_func == NULL)
14720     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14721 }
14722
14723 /**
14724  * gtk_tree_view_get_search_entry:
14725  * @tree_view: A #GtkTreeView
14726  *
14727  * Returns the #GtkEntry which is currently in use as interactive search
14728  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14729  * will be returned.
14730  *
14731  * Return value: (transfer none): the entry currently in use as search entry.
14732  *
14733  * Since: 2.10
14734  */
14735 GtkEntry *
14736 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14737 {
14738   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14739
14740   if (tree_view->priv->search_custom_entry_set)
14741     return GTK_ENTRY (tree_view->priv->search_entry);
14742
14743   return NULL;
14744 }
14745
14746 /**
14747  * gtk_tree_view_set_search_entry:
14748  * @tree_view: A #GtkTreeView
14749  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14750  *
14751  * Sets the entry which the interactive search code will use for this
14752  * @tree_view.  This is useful when you want to provide a search entry
14753  * in our interface at all time at a fixed position.  Passing %NULL for
14754  * @entry will make the interactive search code use the built-in popup
14755  * entry again.
14756  *
14757  * Since: 2.10
14758  */
14759 void
14760 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14761                                 GtkEntry    *entry)
14762 {
14763   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14764   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14765
14766   if (tree_view->priv->search_custom_entry_set)
14767     {
14768       if (tree_view->priv->search_entry_changed_id)
14769         {
14770           g_signal_handler_disconnect (tree_view->priv->search_entry,
14771                                        tree_view->priv->search_entry_changed_id);
14772           tree_view->priv->search_entry_changed_id = 0;
14773         }
14774       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14775                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14776                                             tree_view);
14777
14778       g_object_unref (tree_view->priv->search_entry);
14779     }
14780   else if (tree_view->priv->search_window)
14781     {
14782       gtk_widget_destroy (tree_view->priv->search_window);
14783
14784       tree_view->priv->search_window = NULL;
14785     }
14786
14787   if (entry)
14788     {
14789       tree_view->priv->search_entry = g_object_ref (entry);
14790       tree_view->priv->search_custom_entry_set = TRUE;
14791
14792       if (tree_view->priv->search_entry_changed_id == 0)
14793         {
14794           tree_view->priv->search_entry_changed_id =
14795             g_signal_connect (tree_view->priv->search_entry, "changed",
14796                               G_CALLBACK (gtk_tree_view_search_init),
14797                               tree_view);
14798         }
14799       
14800         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14801                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14802                           tree_view);
14803
14804         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14805     }
14806   else
14807     {
14808       tree_view->priv->search_entry = NULL;
14809       tree_view->priv->search_custom_entry_set = FALSE;
14810     }
14811 }
14812
14813 /**
14814  * gtk_tree_view_set_search_position_func:
14815  * @tree_view: A #GtkTreeView
14816  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14817  *    to use the default search position function
14818  * @data: (allow-none): user data to pass to @func, or %NULL
14819  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14820  *
14821  * Sets the function to use when positioning the search dialog.
14822  *
14823  * Since: 2.10
14824  **/
14825 void
14826 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14827                                         GtkTreeViewSearchPositionFunc  func,
14828                                         gpointer                       user_data,
14829                                         GDestroyNotify                 destroy)
14830 {
14831   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14832
14833   if (tree_view->priv->search_position_destroy)
14834     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14835
14836   tree_view->priv->search_position_func = func;
14837   tree_view->priv->search_position_user_data = user_data;
14838   tree_view->priv->search_position_destroy = destroy;
14839   if (tree_view->priv->search_position_func == NULL)
14840     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14841 }
14842
14843 /**
14844  * gtk_tree_view_get_search_position_func:
14845  * @tree_view: A #GtkTreeView
14846  *
14847  * Returns the positioning function currently in use.
14848  *
14849  * Return value: the currently used function for positioning the search dialog.
14850  *
14851  * Since: 2.10
14852  */
14853 GtkTreeViewSearchPositionFunc
14854 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14855 {
14856   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14857
14858   return tree_view->priv->search_position_func;
14859 }
14860
14861
14862 static void
14863 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14864                                   GtkTreeView *tree_view,
14865                                   GdkDevice   *device)
14866 {
14867   if (tree_view->priv->disable_popdown)
14868     return;
14869
14870   if (tree_view->priv->search_entry_changed_id)
14871     {
14872       g_signal_handler_disconnect (tree_view->priv->search_entry,
14873                                    tree_view->priv->search_entry_changed_id);
14874       tree_view->priv->search_entry_changed_id = 0;
14875     }
14876   if (tree_view->priv->typeselect_flush_timeout)
14877     {
14878       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14879       tree_view->priv->typeselect_flush_timeout = 0;
14880     }
14881         
14882   if (gtk_widget_get_visible (search_dialog))
14883     {
14884       /* send focus-in event */
14885       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14886       gtk_widget_hide (search_dialog);
14887       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14888       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14889     }
14890 }
14891
14892 static void
14893 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14894                                     GtkWidget   *search_dialog,
14895                                     gpointer     user_data)
14896 {
14897   gint x, y;
14898   gint tree_x, tree_y;
14899   gint tree_width, tree_height;
14900   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14901   GdkScreen *screen = gdk_window_get_screen (tree_window);
14902   GtkRequisition requisition;
14903   gint monitor_num;
14904   GdkRectangle monitor;
14905
14906   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14907   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14908
14909   gtk_widget_realize (search_dialog);
14910
14911   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14912   tree_width = gdk_window_get_width (tree_window);
14913   tree_height = gdk_window_get_height (tree_window);
14914   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14915
14916   if (tree_x + tree_width > gdk_screen_get_width (screen))
14917     x = gdk_screen_get_width (screen) - requisition.width;
14918   else if (tree_x + tree_width - requisition.width < 0)
14919     x = 0;
14920   else
14921     x = tree_x + tree_width - requisition.width;
14922
14923   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14924     y = gdk_screen_get_height (screen) - requisition.height;
14925   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14926     y = 0;
14927   else
14928     y = tree_y + tree_height;
14929
14930   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14931 }
14932
14933 static void
14934 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14935                                       GtkMenu  *menu,
14936                                       gpointer  data)
14937 {
14938   GtkTreeView *tree_view = (GtkTreeView *)data;
14939
14940   tree_view->priv->disable_popdown = 1;
14941   g_signal_connect (menu, "hide",
14942                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14943 }
14944
14945 /* Because we're visible but offscreen, we just set a flag in the preedit
14946  * callback.
14947  */
14948 static void
14949 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14950                                       GtkTreeView  *tree_view)
14951 {
14952   tree_view->priv->imcontext_changed = 1;
14953   if (tree_view->priv->typeselect_flush_timeout)
14954     {
14955       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14956       tree_view->priv->typeselect_flush_timeout =
14957         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14958                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14959                        tree_view);
14960     }
14961
14962 }
14963
14964 static void
14965 gtk_tree_view_search_activate (GtkEntry    *entry,
14966                                GtkTreeView *tree_view)
14967 {
14968   GtkTreePath *path;
14969   GtkRBNode *node;
14970   GtkRBTree *tree;
14971
14972   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14973                                     tree_view,
14974                                     gtk_get_current_event_device ());
14975
14976   /* If we have a row selected and it's the cursor row, we activate
14977    * the row XXX */
14978   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14979     {
14980       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14981       
14982       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14983       
14984       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14985         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14986       
14987       gtk_tree_path_free (path);
14988     }
14989 }
14990
14991 static gboolean
14992 gtk_tree_view_real_search_enable_popdown (gpointer data)
14993 {
14994   GtkTreeView *tree_view = (GtkTreeView *)data;
14995
14996   tree_view->priv->disable_popdown = 0;
14997
14998   return FALSE;
14999 }
15000
15001 static void
15002 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15003                                      gpointer   data)
15004 {
15005   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15006 }
15007
15008 static gboolean
15009 gtk_tree_view_search_delete_event (GtkWidget *widget,
15010                                    GdkEventAny *event,
15011                                    GtkTreeView *tree_view)
15012 {
15013   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15014
15015   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15016
15017   return TRUE;
15018 }
15019
15020 static gboolean
15021 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15022                                          GdkEventButton *event,
15023                                          GtkTreeView *tree_view)
15024 {
15025   GdkDevice *keyb_device;
15026
15027   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15028
15029   keyb_device = gdk_device_get_associated_device (event->device);
15030   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15031
15032   if (event->window == tree_view->priv->bin_window)
15033     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15034
15035   return TRUE;
15036 }
15037
15038 static gboolean
15039 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15040                                    GdkEventScroll *event,
15041                                    GtkTreeView *tree_view)
15042 {
15043   gboolean retval = FALSE;
15044
15045   if (event->direction == GDK_SCROLL_UP)
15046     {
15047       gtk_tree_view_search_move (widget, tree_view, TRUE);
15048       retval = TRUE;
15049     }
15050   else if (event->direction == GDK_SCROLL_DOWN)
15051     {
15052       gtk_tree_view_search_move (widget, tree_view, FALSE);
15053       retval = TRUE;
15054     }
15055
15056   /* renew the flush timeout */
15057   if (retval && tree_view->priv->typeselect_flush_timeout
15058       && !tree_view->priv->search_custom_entry_set)
15059     {
15060       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15061       tree_view->priv->typeselect_flush_timeout =
15062         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15063                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15064                        tree_view);
15065     }
15066
15067   return retval;
15068 }
15069
15070 static gboolean
15071 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15072                                       GdkEventKey *event,
15073                                       GtkTreeView *tree_view)
15074 {
15075   gboolean retval = FALSE;
15076
15077   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15078   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15079
15080   /* close window and cancel the search */
15081   if (!tree_view->priv->search_custom_entry_set
15082       && (event->keyval == GDK_KEY_Escape ||
15083           event->keyval == GDK_KEY_Tab ||
15084             event->keyval == GDK_KEY_KP_Tab ||
15085             event->keyval == GDK_KEY_ISO_Left_Tab))
15086     {
15087       gtk_tree_view_search_dialog_hide (widget, tree_view,
15088                                         gdk_event_get_device ((GdkEvent *) event));
15089       return TRUE;
15090     }
15091
15092   /* select previous matching iter */
15093   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15094     {
15095       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15096         gtk_widget_error_bell (widget);
15097
15098       retval = TRUE;
15099     }
15100
15101   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
15102       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15103     {
15104       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15105         gtk_widget_error_bell (widget);
15106
15107       retval = TRUE;
15108     }
15109
15110   /* select next matching iter */
15111   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15112     {
15113       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15114         gtk_widget_error_bell (widget);
15115
15116       retval = TRUE;
15117     }
15118
15119   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
15120       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15121     {
15122       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15123         gtk_widget_error_bell (widget);
15124
15125       retval = TRUE;
15126     }
15127
15128   /* renew the flush timeout */
15129   if (retval && tree_view->priv->typeselect_flush_timeout
15130       && !tree_view->priv->search_custom_entry_set)
15131     {
15132       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15133       tree_view->priv->typeselect_flush_timeout =
15134         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15135                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15136                        tree_view);
15137     }
15138
15139   return retval;
15140 }
15141
15142 /*  this function returns FALSE if there is a search string but
15143  *  nothing was found, and TRUE otherwise.
15144  */
15145 static gboolean
15146 gtk_tree_view_search_move (GtkWidget   *window,
15147                            GtkTreeView *tree_view,
15148                            gboolean     up)
15149 {
15150   gboolean ret;
15151   gint len;
15152   gint count = 0;
15153   const gchar *text;
15154   GtkTreeIter iter;
15155   GtkTreeModel *model;
15156   GtkTreeSelection *selection;
15157
15158   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15159
15160   g_return_val_if_fail (text != NULL, FALSE);
15161
15162   len = strlen (text);
15163
15164   if (up && tree_view->priv->selected_iter == 1)
15165     return strlen (text) < 1;
15166
15167   len = strlen (text);
15168
15169   if (len < 1)
15170     return TRUE;
15171
15172   model = gtk_tree_view_get_model (tree_view);
15173   selection = gtk_tree_view_get_selection (tree_view);
15174
15175   /* search */
15176   gtk_tree_selection_unselect_all (selection);
15177   if (!gtk_tree_model_get_iter_first (model, &iter))
15178     return TRUE;
15179
15180   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15181                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15182
15183   if (ret)
15184     {
15185       /* found */
15186       tree_view->priv->selected_iter += up?(-1):(1);
15187       return TRUE;
15188     }
15189   else
15190     {
15191       /* return to old iter */
15192       count = 0;
15193       gtk_tree_model_get_iter_first (model, &iter);
15194       gtk_tree_view_search_iter (model, selection,
15195                                  &iter, text,
15196                                  &count, tree_view->priv->selected_iter);
15197       return FALSE;
15198     }
15199 }
15200
15201 static gboolean
15202 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15203                                  gint          column,
15204                                  const gchar  *key,
15205                                  GtkTreeIter  *iter,
15206                                  gpointer      search_data)
15207 {
15208   gboolean retval = TRUE;
15209   const gchar *str;
15210   gchar *normalized_string;
15211   gchar *normalized_key;
15212   gchar *case_normalized_string = NULL;
15213   gchar *case_normalized_key = NULL;
15214   GValue value = {0,};
15215   GValue transformed = {0,};
15216
15217   gtk_tree_model_get_value (model, iter, column, &value);
15218
15219   g_value_init (&transformed, G_TYPE_STRING);
15220
15221   if (!g_value_transform (&value, &transformed))
15222     {
15223       g_value_unset (&value);
15224       return TRUE;
15225     }
15226
15227   g_value_unset (&value);
15228
15229   str = g_value_get_string (&transformed);
15230   if (!str)
15231     {
15232       g_value_unset (&transformed);
15233       return TRUE;
15234     }
15235
15236   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15237   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15238
15239   if (normalized_string && normalized_key)
15240     {
15241       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15242       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15243
15244       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15245         retval = FALSE;
15246     }
15247
15248   g_value_unset (&transformed);
15249   g_free (normalized_key);
15250   g_free (normalized_string);
15251   g_free (case_normalized_key);
15252   g_free (case_normalized_string);
15253
15254   return retval;
15255 }
15256
15257 static gboolean
15258 gtk_tree_view_search_iter (GtkTreeModel     *model,
15259                            GtkTreeSelection *selection,
15260                            GtkTreeIter      *iter,
15261                            const gchar      *text,
15262                            gint             *count,
15263                            gint              n)
15264 {
15265   GtkRBTree *tree = NULL;
15266   GtkRBNode *node = NULL;
15267   GtkTreePath *path;
15268
15269   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15270
15271   path = gtk_tree_model_get_path (model, iter);
15272   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15273
15274   do
15275     {
15276       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15277         {
15278           (*count)++;
15279           if (*count == n)
15280             {
15281               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15282                                             TRUE, 0.5, 0.0);
15283               gtk_tree_selection_select_iter (selection, iter);
15284               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15285
15286               if (path)
15287                 gtk_tree_path_free (path);
15288
15289               return TRUE;
15290             }
15291         }
15292
15293       if (node->children)
15294         {
15295           gboolean has_child;
15296           GtkTreeIter tmp;
15297
15298           tree = node->children;
15299           node = tree->root;
15300
15301           while (node->left != tree->nil)
15302             node = node->left;
15303
15304           tmp = *iter;
15305           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15306           gtk_tree_path_down (path);
15307
15308           /* sanity check */
15309           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15310         }
15311       else
15312         {
15313           gboolean done = FALSE;
15314
15315           do
15316             {
15317               node = _gtk_rbtree_next (tree, node);
15318
15319               if (node)
15320                 {
15321                   gboolean has_next;
15322
15323                   has_next = gtk_tree_model_iter_next (model, iter);
15324
15325                   done = TRUE;
15326                   gtk_tree_path_next (path);
15327
15328                   /* sanity check */
15329                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15330                 }
15331               else
15332                 {
15333                   gboolean has_parent;
15334                   GtkTreeIter tmp_iter = *iter;
15335
15336                   node = tree->parent_node;
15337                   tree = tree->parent_tree;
15338
15339                   if (!tree)
15340                     {
15341                       if (path)
15342                         gtk_tree_path_free (path);
15343
15344                       /* we've run out of tree, done with this func */
15345                       return FALSE;
15346                     }
15347
15348                   has_parent = gtk_tree_model_iter_parent (model,
15349                                                            iter,
15350                                                            &tmp_iter);
15351                   gtk_tree_path_up (path);
15352
15353                   /* sanity check */
15354                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15355                 }
15356             }
15357           while (!done);
15358         }
15359     }
15360   while (1);
15361
15362   return FALSE;
15363 }
15364
15365 static void
15366 gtk_tree_view_search_init (GtkWidget   *entry,
15367                            GtkTreeView *tree_view)
15368 {
15369   gint ret;
15370   gint count = 0;
15371   const gchar *text;
15372   GtkTreeIter iter;
15373   GtkTreeModel *model;
15374   GtkTreeSelection *selection;
15375
15376   g_return_if_fail (GTK_IS_ENTRY (entry));
15377   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15378
15379   text = gtk_entry_get_text (GTK_ENTRY (entry));
15380
15381   model = gtk_tree_view_get_model (tree_view);
15382   selection = gtk_tree_view_get_selection (tree_view);
15383
15384   /* search */
15385   gtk_tree_selection_unselect_all (selection);
15386   if (tree_view->priv->typeselect_flush_timeout
15387       && !tree_view->priv->search_custom_entry_set)
15388     {
15389       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15390       tree_view->priv->typeselect_flush_timeout =
15391         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15392                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15393                        tree_view);
15394     }
15395
15396   if (*text == '\0')
15397     return;
15398
15399   if (!gtk_tree_model_get_iter_first (model, &iter))
15400     return;
15401
15402   ret = gtk_tree_view_search_iter (model, selection,
15403                                    &iter, text,
15404                                    &count, 1);
15405
15406   if (ret)
15407     tree_view->priv->selected_iter = 1;
15408 }
15409
15410 void
15411 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15412                                 GtkTreeViewColumn *column,
15413                                 GtkCellEditable   *cell_editable)
15414 {
15415   if (tree_view->priv->edited_column == NULL)
15416     return;
15417
15418   g_return_if_fail (column == tree_view->priv->edited_column);
15419
15420   tree_view->priv->edited_column = NULL;
15421
15422   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15423     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15424
15425   gtk_container_remove (GTK_CONTAINER (tree_view),
15426                         GTK_WIDGET (cell_editable));
15427
15428   /* FIXME should only redraw a single node */
15429   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15430 }
15431
15432 static gboolean
15433 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15434                              GtkTreePath *cursor_path,
15435                              gboolean     edit_only)
15436 {
15437   GtkTreeIter iter;
15438   GdkRectangle cell_area;
15439   GtkTreeViewColumn *focus_column;
15440   gchar *path_string;
15441   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15442   gint retval = FALSE;
15443   GtkRBTree *cursor_tree;
15444   GtkRBNode *cursor_node;
15445
15446   g_assert (tree_view->priv->focus_column);
15447   focus_column = tree_view->priv->focus_column;
15448
15449   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15450     return FALSE;
15451
15452   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15453       cursor_node == NULL)
15454     return FALSE;
15455
15456   path_string = gtk_tree_path_to_string (cursor_path);
15457   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15458
15459   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15460
15461   gtk_tree_view_column_cell_set_cell_data (focus_column,
15462                                            tree_view->priv->model,
15463                                            &iter,
15464                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15465                                            cursor_node->children?TRUE:FALSE);
15466   gtk_tree_view_get_cell_area (tree_view,
15467                                cursor_path,
15468                                focus_column,
15469                                &cell_area);
15470
15471   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15472                               _gtk_tree_view_column_get_context (focus_column),
15473                               GTK_WIDGET (tree_view),
15474                               &cell_area,
15475                               flags, edit_only))
15476     retval = TRUE;
15477
15478   return retval;
15479 }
15480
15481 void
15482 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15483                              GtkTreeViewColumn *column,
15484                              GtkTreePath       *path,
15485                              GtkCellEditable   *cell_editable,
15486                              GdkRectangle      *cell_area)
15487 {
15488   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15489   GtkRequisition requisition;
15490
15491   tree_view->priv->edited_column = column;
15492
15493   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15494   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15495
15496   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15497                                  &requisition, NULL);
15498
15499   tree_view->priv->draw_keyfocus = TRUE;
15500
15501   if (requisition.height < cell_area->height)
15502     {
15503       gint diff = cell_area->height - requisition.height;
15504       gtk_tree_view_put (tree_view,
15505                          GTK_WIDGET (cell_editable),
15506                          cell_area->x, cell_area->y + diff/2,
15507                          cell_area->width, requisition.height);
15508     }
15509   else
15510     {
15511       gtk_tree_view_put (tree_view,
15512                          GTK_WIDGET (cell_editable),
15513                          cell_area->x, cell_area->y,
15514                          cell_area->width, cell_area->height);
15515     }
15516 }
15517
15518 static void
15519 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15520                             gboolean     cancel_editing)
15521 {
15522   GtkTreeViewColumn *column;
15523
15524   if (tree_view->priv->edited_column == NULL)
15525     return;
15526
15527   /*
15528    * This is very evil. We need to do this, because
15529    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15530    * later on. If gtk_tree_view_row_changed notices
15531    * tree_view->priv->edited_column != NULL, it'll call
15532    * gtk_tree_view_stop_editing again. Bad things will happen then.
15533    *
15534    * Please read that again if you intend to modify anything here.
15535    */
15536
15537   column = tree_view->priv->edited_column;
15538   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15539   tree_view->priv->edited_column = NULL;
15540 }
15541
15542
15543 /**
15544  * gtk_tree_view_set_hover_selection:
15545  * @tree_view: a #GtkTreeView
15546  * @hover: %TRUE to enable hover selection mode
15547  *
15548  * Enables of disables the hover selection mode of @tree_view.
15549  * Hover selection makes the selected row follow the pointer.
15550  * Currently, this works only for the selection modes 
15551  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15552  * 
15553  * Since: 2.6
15554  **/
15555 void     
15556 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15557                                    gboolean     hover)
15558 {
15559   hover = hover != FALSE;
15560
15561   if (hover != tree_view->priv->hover_selection)
15562     {
15563       tree_view->priv->hover_selection = hover;
15564
15565       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15566     }
15567 }
15568
15569 /**
15570  * gtk_tree_view_get_hover_selection:
15571  * @tree_view: a #GtkTreeView
15572  * 
15573  * Returns whether hover selection mode is turned on for @tree_view.
15574  * 
15575  * Return value: %TRUE if @tree_view is in hover selection mode
15576  *
15577  * Since: 2.6 
15578  **/
15579 gboolean 
15580 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15581 {
15582   return tree_view->priv->hover_selection;
15583 }
15584
15585 /**
15586  * gtk_tree_view_set_hover_expand:
15587  * @tree_view: a #GtkTreeView
15588  * @expand: %TRUE to enable hover selection mode
15589  *
15590  * Enables of disables the hover expansion mode of @tree_view.
15591  * Hover expansion makes rows expand or collapse if the pointer 
15592  * moves over them.
15593  * 
15594  * Since: 2.6
15595  **/
15596 void     
15597 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15598                                 gboolean     expand)
15599 {
15600   expand = expand != FALSE;
15601
15602   if (expand != tree_view->priv->hover_expand)
15603     {
15604       tree_view->priv->hover_expand = expand;
15605
15606       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15607     }
15608 }
15609
15610 /**
15611  * gtk_tree_view_get_hover_expand:
15612  * @tree_view: a #GtkTreeView
15613  * 
15614  * Returns whether hover expansion mode is turned on for @tree_view.
15615  * 
15616  * Return value: %TRUE if @tree_view is in hover expansion mode
15617  *
15618  * Since: 2.6 
15619  **/
15620 gboolean 
15621 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15622 {
15623   return tree_view->priv->hover_expand;
15624 }
15625
15626 /**
15627  * gtk_tree_view_set_rubber_banding:
15628  * @tree_view: a #GtkTreeView
15629  * @enable: %TRUE to enable rubber banding
15630  *
15631  * Enables or disables rubber banding in @tree_view.  If the selection mode
15632  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15633  * multiple rows by dragging the mouse.
15634  * 
15635  * Since: 2.10
15636  **/
15637 void
15638 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15639                                   gboolean     enable)
15640 {
15641   enable = enable != FALSE;
15642
15643   if (enable != tree_view->priv->rubber_banding_enable)
15644     {
15645       tree_view->priv->rubber_banding_enable = enable;
15646
15647       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15648     }
15649 }
15650
15651 /**
15652  * gtk_tree_view_get_rubber_banding:
15653  * @tree_view: a #GtkTreeView
15654  * 
15655  * Returns whether rubber banding is turned on for @tree_view.  If the
15656  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15657  * user to select multiple rows by dragging the mouse.
15658  * 
15659  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15660  *
15661  * Since: 2.10
15662  **/
15663 gboolean
15664 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15665 {
15666   return tree_view->priv->rubber_banding_enable;
15667 }
15668
15669 /**
15670  * gtk_tree_view_is_rubber_banding_active:
15671  * @tree_view: a #GtkTreeView
15672  * 
15673  * Returns whether a rubber banding operation is currently being done
15674  * in @tree_view.
15675  *
15676  * Return value: %TRUE if a rubber banding operation is currently being
15677  * done in @tree_view.
15678  *
15679  * Since: 2.12
15680  **/
15681 gboolean
15682 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15683 {
15684   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15685
15686   if (tree_view->priv->rubber_banding_enable
15687       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15688     return TRUE;
15689
15690   return FALSE;
15691 }
15692
15693 /**
15694  * gtk_tree_view_get_row_separator_func:
15695  * @tree_view: a #GtkTreeView
15696  * 
15697  * Returns the current row separator function.
15698  * 
15699  * Return value: the current row separator function.
15700  *
15701  * Since: 2.6
15702  **/
15703 GtkTreeViewRowSeparatorFunc 
15704 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15705 {
15706   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15707
15708   return tree_view->priv->row_separator_func;
15709 }
15710
15711 /**
15712  * gtk_tree_view_set_row_separator_func:
15713  * @tree_view: a #GtkTreeView
15714  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15715  * @data: (allow-none): user data to pass to @func, or %NULL
15716  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15717  * 
15718  * Sets the row separator function, which is used to determine
15719  * whether a row should be drawn as a separator. If the row separator
15720  * function is %NULL, no separators are drawn. This is the default value.
15721  *
15722  * Since: 2.6
15723  **/
15724 void
15725 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15726                                       GtkTreeViewRowSeparatorFunc  func,
15727                                       gpointer                     data,
15728                                       GDestroyNotify               destroy)
15729 {
15730   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15731
15732   if (tree_view->priv->row_separator_destroy)
15733     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15734
15735   tree_view->priv->row_separator_func = func;
15736   tree_view->priv->row_separator_data = data;
15737   tree_view->priv->row_separator_destroy = destroy;
15738
15739   /* Have the tree recalculate heights */
15740   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15741   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15742 }
15743
15744   
15745 static void
15746 gtk_tree_view_grab_notify (GtkWidget *widget,
15747                            gboolean   was_grabbed)
15748 {
15749   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15750
15751   tree_view->priv->in_grab = !was_grabbed;
15752
15753   if (!was_grabbed)
15754     {
15755       tree_view->priv->pressed_button = -1;
15756
15757       if (tree_view->priv->rubber_band_status)
15758         gtk_tree_view_stop_rubber_band (tree_view);
15759     }
15760 }
15761
15762 static void
15763 gtk_tree_view_state_changed (GtkWidget      *widget,
15764                              GtkStateType    previous_state)
15765 {
15766   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15767
15768   if (gtk_widget_get_realized (widget))
15769     {
15770       gdk_window_set_background (tree_view->priv->bin_window,
15771                                  &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
15772     }
15773
15774   gtk_widget_queue_draw (widget);
15775 }
15776
15777 /**
15778  * gtk_tree_view_get_grid_lines:
15779  * @tree_view: a #GtkTreeView
15780  *
15781  * Returns which grid lines are enabled in @tree_view.
15782  *
15783  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15784  * are enabled.
15785  *
15786  * Since: 2.10
15787  */
15788 GtkTreeViewGridLines
15789 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15790 {
15791   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15792
15793   return tree_view->priv->grid_lines;
15794 }
15795
15796 /**
15797  * gtk_tree_view_set_grid_lines:
15798  * @tree_view: a #GtkTreeView
15799  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15800  * enable.
15801  *
15802  * Sets which grid lines to draw in @tree_view.
15803  *
15804  * Since: 2.10
15805  */
15806 void
15807 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15808                               GtkTreeViewGridLines   grid_lines)
15809 {
15810   GtkTreeViewPrivate *priv;
15811   GtkWidget *widget;
15812   GtkTreeViewGridLines old_grid_lines;
15813
15814   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15815
15816   priv = tree_view->priv;
15817   widget = GTK_WIDGET (tree_view);
15818
15819   old_grid_lines = priv->grid_lines;
15820   priv->grid_lines = grid_lines;
15821   
15822   if (gtk_widget_get_realized (widget))
15823     {
15824       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15825           priv->grid_line_width)
15826         {
15827           priv->grid_line_width = 0;
15828         }
15829       
15830       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15831           !priv->grid_line_width)
15832         {
15833           gint8 *dash_list;
15834
15835           gtk_widget_style_get (widget,
15836                                 "grid-line-width", &priv->grid_line_width,
15837                                 "grid-line-pattern", (gchar *)&dash_list,
15838                                 NULL);
15839       
15840           if (dash_list)
15841             {
15842               priv->grid_line_dashes[0] = dash_list[0];
15843               if (dash_list[0])
15844                 priv->grid_line_dashes[1] = dash_list[1];
15845               
15846               g_free (dash_list);
15847             }
15848           else
15849             {
15850               priv->grid_line_dashes[0] = 1;
15851               priv->grid_line_dashes[1] = 1;
15852             }
15853         }      
15854     }
15855
15856   if (old_grid_lines != grid_lines)
15857     {
15858       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15859       
15860       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15861     }
15862 }
15863
15864 /**
15865  * gtk_tree_view_get_enable_tree_lines:
15866  * @tree_view: a #GtkTreeView.
15867  *
15868  * Returns whether or not tree lines are drawn in @tree_view.
15869  *
15870  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15871  * otherwise.
15872  *
15873  * Since: 2.10
15874  */
15875 gboolean
15876 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15877 {
15878   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15879
15880   return tree_view->priv->tree_lines_enabled;
15881 }
15882
15883 /**
15884  * gtk_tree_view_set_enable_tree_lines:
15885  * @tree_view: a #GtkTreeView
15886  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15887  *
15888  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15889  * This does not have any visible effects for lists.
15890  *
15891  * Since: 2.10
15892  */
15893 void
15894 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15895                                      gboolean     enabled)
15896 {
15897   GtkTreeViewPrivate *priv;
15898   GtkWidget *widget;
15899   gboolean was_enabled;
15900
15901   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15902
15903   enabled = enabled != FALSE;
15904
15905   priv = tree_view->priv;
15906   widget = GTK_WIDGET (tree_view);
15907
15908   was_enabled = priv->tree_lines_enabled;
15909
15910   priv->tree_lines_enabled = enabled;
15911
15912   if (gtk_widget_get_realized (widget))
15913     {
15914       if (!enabled && priv->tree_line_width)
15915         {
15916           priv->tree_line_width = 0;
15917         }
15918       
15919       if (enabled && !priv->tree_line_width)
15920         {
15921           gint8 *dash_list;
15922           gtk_widget_style_get (widget,
15923                                 "tree-line-width", &priv->tree_line_width,
15924                                 "tree-line-pattern", (gchar *)&dash_list,
15925                                 NULL);
15926           
15927           if (dash_list)
15928             {
15929               priv->tree_line_dashes[0] = dash_list[0];
15930               if (dash_list[0])
15931                 priv->tree_line_dashes[1] = dash_list[1];
15932               
15933               g_free (dash_list);
15934             }
15935           else
15936             {
15937               priv->tree_line_dashes[0] = 1;
15938               priv->tree_line_dashes[1] = 1;
15939             }
15940         }
15941     }
15942
15943   if (was_enabled != enabled)
15944     {
15945       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15946
15947       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15948     }
15949 }
15950
15951
15952 /**
15953  * gtk_tree_view_set_show_expanders:
15954  * @tree_view: a #GtkTreeView
15955  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15956  *
15957  * Sets whether to draw and enable expanders and indent child rows in
15958  * @tree_view.  When disabled there will be no expanders visible in trees
15959  * and there will be no way to expand and collapse rows by default.  Also
15960  * note that hiding the expanders will disable the default indentation.  You
15961  * can set a custom indentation in this case using
15962  * gtk_tree_view_set_level_indentation().
15963  * This does not have any visible effects for lists.
15964  *
15965  * Since: 2.12
15966  */
15967 void
15968 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15969                                   gboolean     enabled)
15970 {
15971   gboolean was_enabled;
15972
15973   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15974
15975   enabled = enabled != FALSE;
15976   was_enabled = tree_view->priv->show_expanders;
15977
15978   tree_view->priv->show_expanders = enabled == TRUE;
15979
15980   if (enabled != was_enabled)
15981     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15982 }
15983
15984 /**
15985  * gtk_tree_view_get_show_expanders:
15986  * @tree_view: a #GtkTreeView.
15987  *
15988  * Returns whether or not expanders are drawn in @tree_view.
15989  *
15990  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15991  * otherwise.
15992  *
15993  * Since: 2.12
15994  */
15995 gboolean
15996 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15997 {
15998   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15999
16000   return tree_view->priv->show_expanders;
16001 }
16002
16003 /**
16004  * gtk_tree_view_set_level_indentation:
16005  * @tree_view: a #GtkTreeView
16006  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16007  *
16008  * Sets the amount of extra indentation for child levels to use in @tree_view
16009  * in addition to the default indentation.  The value should be specified in
16010  * pixels, a value of 0 disables this feature and in this case only the default
16011  * indentation will be used.
16012  * This does not have any visible effects for lists.
16013  *
16014  * Since: 2.12
16015  */
16016 void
16017 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16018                                      gint         indentation)
16019 {
16020   tree_view->priv->level_indentation = indentation;
16021
16022   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16023 }
16024
16025 /**
16026  * gtk_tree_view_get_level_indentation:
16027  * @tree_view: a #GtkTreeView.
16028  *
16029  * Returns the amount, in pixels, of extra indentation for child levels
16030  * in @tree_view.
16031  *
16032  * Return value: the amount of extra indentation for child levels in
16033  * @tree_view.  A return value of 0 means that this feature is disabled.
16034  *
16035  * Since: 2.12
16036  */
16037 gint
16038 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16039 {
16040   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16041
16042   return tree_view->priv->level_indentation;
16043 }
16044
16045 /**
16046  * gtk_tree_view_set_tooltip_row:
16047  * @tree_view: a #GtkTreeView
16048  * @tooltip: a #GtkTooltip
16049  * @path: a #GtkTreePath
16050  *
16051  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16052  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16053  * See also gtk_tooltip_set_tip_area().
16054  *
16055  * Since: 2.12
16056  */
16057 void
16058 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16059                                GtkTooltip  *tooltip,
16060                                GtkTreePath *path)
16061 {
16062   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16063   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16064
16065   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16066 }
16067
16068 /**
16069  * gtk_tree_view_set_tooltip_cell:
16070  * @tree_view: a #GtkTreeView
16071  * @tooltip: a #GtkTooltip
16072  * @path: (allow-none): a #GtkTreePath or %NULL
16073  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16074  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16075  *
16076  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16077  * in common.  For example if @path is %NULL and @column is set, the tip
16078  * area will be set to the full area covered by @column.  See also
16079  * gtk_tooltip_set_tip_area().
16080  *
16081  * Note that if @path is not specified and @cell is set and part of a column
16082  * containing the expander, the tooltip might not show and hide at the correct
16083  * position.  In such cases @path must be set to the current node under the
16084  * mouse cursor for this function to operate correctly.
16085  *
16086  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16087  *
16088  * Since: 2.12
16089  */
16090 void
16091 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16092                                 GtkTooltip        *tooltip,
16093                                 GtkTreePath       *path,
16094                                 GtkTreeViewColumn *column,
16095                                 GtkCellRenderer   *cell)
16096 {
16097   GtkAllocation allocation;
16098   GdkRectangle rect;
16099
16100   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16101   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16102   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16103   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16104
16105   /* Determine x values. */
16106   if (column && cell)
16107     {
16108       GdkRectangle tmp;
16109       gint start, width;
16110
16111       /* We always pass in path here, whether it is NULL or not.
16112        * For cells in expander columns path must be specified so that
16113        * we can correctly account for the indentation.  This also means
16114        * that the tooltip is constrained vertically by the "Determine y
16115        * values" code below; this is not a real problem since cells actually
16116        * don't stretch vertically in constrast to columns.
16117        */
16118       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16119       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16120
16121       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16122                                                          tmp.x + start, 0,
16123                                                          &rect.x, NULL);
16124       rect.width = width;
16125     }
16126   else if (column)
16127     {
16128       GdkRectangle tmp;
16129
16130       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16131       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16132                                                          tmp.x, 0,
16133                                                          &rect.x, NULL);
16134       rect.width = tmp.width;
16135     }
16136   else
16137     {
16138       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16139       rect.x = 0;
16140       rect.width = allocation.width;
16141     }
16142
16143   /* Determine y values. */
16144   if (path)
16145     {
16146       GdkRectangle tmp;
16147
16148       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16149       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16150                                                          0, tmp.y,
16151                                                          NULL, &rect.y);
16152       rect.height = tmp.height;
16153     }
16154   else
16155     {
16156       rect.y = 0;
16157       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16158     }
16159
16160   gtk_tooltip_set_tip_area (tooltip, &rect);
16161 }
16162
16163 /**
16164  * gtk_tree_view_get_tooltip_context:
16165  * @tree_view: a #GtkTreeView
16166  * @x: the x coordinate (relative to widget coordinates)
16167  * @y: the y coordinate (relative to widget coordinates)
16168  * @keyboard_tip: whether this is a keyboard tooltip or not
16169  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
16170  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16171  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16172  *
16173  * This function is supposed to be used in a #GtkWidget::query-tooltip
16174  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16175  * which are received in the signal handler, should be passed to this
16176  * function without modification.
16177  *
16178  * The return value indicates whether there is a tree view row at the given
16179  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16180  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16181  * @model, @path and @iter which have been provided will be set to point to
16182  * that row and the corresponding model.  @x and @y will always be converted
16183  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16184  *
16185  * Return value: whether or not the given tooltip context points to a row.
16186  *
16187  * Since: 2.12
16188  */
16189 gboolean
16190 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16191                                    gint          *x,
16192                                    gint          *y,
16193                                    gboolean       keyboard_tip,
16194                                    GtkTreeModel **model,
16195                                    GtkTreePath  **path,
16196                                    GtkTreeIter   *iter)
16197 {
16198   GtkTreePath *tmppath = NULL;
16199
16200   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16201   g_return_val_if_fail (x != NULL, FALSE);
16202   g_return_val_if_fail (y != NULL, FALSE);
16203
16204   if (keyboard_tip)
16205     {
16206       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16207
16208       if (!tmppath)
16209         return FALSE;
16210     }
16211   else
16212     {
16213       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16214                                                          x, y);
16215
16216       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16217                                           &tmppath, NULL, NULL, NULL))
16218         return FALSE;
16219     }
16220
16221   if (model)
16222     *model = gtk_tree_view_get_model (tree_view);
16223
16224   if (iter)
16225     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16226                              iter, tmppath);
16227
16228   if (path)
16229     *path = tmppath;
16230   else
16231     gtk_tree_path_free (tmppath);
16232
16233   return TRUE;
16234 }
16235
16236 static gboolean
16237 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16238                                     gint        x,
16239                                     gint        y,
16240                                     gboolean    keyboard_tip,
16241                                     GtkTooltip *tooltip,
16242                                     gpointer    data)
16243 {
16244   GValue value = { 0, };
16245   GValue transformed = { 0, };
16246   GtkTreeIter iter;
16247   GtkTreePath *path;
16248   GtkTreeModel *model;
16249   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16250
16251   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16252                                           &x, &y,
16253                                           keyboard_tip,
16254                                           &model, &path, &iter))
16255     return FALSE;
16256
16257   gtk_tree_model_get_value (model, &iter,
16258                             tree_view->priv->tooltip_column, &value);
16259
16260   g_value_init (&transformed, G_TYPE_STRING);
16261
16262   if (!g_value_transform (&value, &transformed))
16263     {
16264       g_value_unset (&value);
16265       gtk_tree_path_free (path);
16266
16267       return FALSE;
16268     }
16269
16270   g_value_unset (&value);
16271
16272   if (!g_value_get_string (&transformed))
16273     {
16274       g_value_unset (&transformed);
16275       gtk_tree_path_free (path);
16276
16277       return FALSE;
16278     }
16279
16280   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16281   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16282
16283   gtk_tree_path_free (path);
16284   g_value_unset (&transformed);
16285
16286   return TRUE;
16287 }
16288
16289 /**
16290  * gtk_tree_view_set_tooltip_column:
16291  * @tree_view: a #GtkTreeView
16292  * @column: an integer, which is a valid column number for @tree_view's model
16293  *
16294  * If you only plan to have simple (text-only) tooltips on full rows, you
16295  * can use this function to have #GtkTreeView handle these automatically
16296  * for you. @column should be set to the column in @tree_view's model
16297  * containing the tooltip texts, or -1 to disable this feature.
16298  *
16299  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
16300  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16301  *
16302  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16303  * so &amp;, &lt;, etc have to be escaped in the text.
16304  *
16305  * Since: 2.12
16306  */
16307 void
16308 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16309                                   gint         column)
16310 {
16311   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16312
16313   if (column == tree_view->priv->tooltip_column)
16314     return;
16315
16316   if (column == -1)
16317     {
16318       g_signal_handlers_disconnect_by_func (tree_view,
16319                                             gtk_tree_view_set_tooltip_query_cb,
16320                                             NULL);
16321       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16322     }
16323   else
16324     {
16325       if (tree_view->priv->tooltip_column == -1)
16326         {
16327           g_signal_connect (tree_view, "query-tooltip",
16328                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16329           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16330         }
16331     }
16332
16333   tree_view->priv->tooltip_column = column;
16334   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16335 }
16336
16337 /**
16338  * gtk_tree_view_get_tooltip_column:
16339  * @tree_view: a #GtkTreeView
16340  *
16341  * Returns the column of @tree_view's model which is being used for
16342  * displaying tooltips on @tree_view's rows.
16343  *
16344  * Return value: the index of the tooltip column that is currently being
16345  * used, or -1 if this is disabled.
16346  *
16347  * Since: 2.12
16348  */
16349 gint
16350 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16351 {
16352   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16353
16354   return tree_view->priv->tooltip_column;
16355 }