]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Don't use *DISABLE_DEPRECATED guards
[~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 "gtkmarshalers.h"
32 #include "gtkbuildable.h"
33 #include "gtkbutton.h"
34 #include "gtklabel.h"
35 #include "gtkbox.h"
36 #include "gtkarrow.h"
37 #include "gtkintl.h"
38 #include "gtkbindings.h"
39 #include "gtkcontainer.h"
40 #include "gtkentry.h"
41 #include "gtkframe.h"
42 #include "gtktreemodelsort.h"
43 #include "gtktooltip.h"
44 #include "gtkscrollable.h"
45 #include "gtkcelllayout.h"
46 #include "gtkprivate.h"
47 #include "gtkwidgetprivate.h"
48 #include "gtkentryprivate.h"
49 #include "gtkstylecontextprivate.h"
50 #include "gtktypebuiltins.h"
51 #include "a11y/gtktreeviewaccessible.h"
52
53
54 /**
55  * SECTION:gtktreeview
56  * @Short_description: A widget for displaying both trees and lists
57  * @Title: GtkTreeView
58  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
59  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
60  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
61  *   #GtkCellRendererText, #GtkCellRendererToggle
62  *
63  * Widget that displays any object that implements the #GtkTreeModel interface.
64  *
65  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
66  * overview</link> for an overview of all the objects and data types related
67  * to the tree widget and how they work together.
68  *
69  * Several different coordinate systems are exposed in the GtkTreeView API.
70  * These are:
71  *
72  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
73  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
74  * <varlistentry><term>Widget coordinates</term>
75  * <listitem>
76  * <para>
77  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
78  * </para>
79  * </listitem>
80  * </varlistentry>
81  * <varlistentry><term>Bin window coordinates</term>
82  * <listitem>
83  * <para>
84  * Coordinates relative to the window that GtkTreeView renders to.
85  * </para>
86  * </listitem>
87  * </varlistentry>
88  * <varlistentry><term>Tree coordinates</term>
89  * <listitem>
90  * <para>
91  * Coordinates relative to the entire scrollable area of GtkTreeView. These
92  * coordinates start at (0, 0) for row 0 of the tree.
93  * </para>
94  * </listitem>
95  * </varlistentry>
96  * </variablelist>
97  *
98  * Several functions are available for converting between the different
99  * coordinate systems.  The most common translations are between widget and bin
100  * window coordinates and between bin window and tree coordinates. For the
101  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
102  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
103  * (and vice versa).
104  *
105  * <refsect2 id="GtkTreeView-BUILDER-UI">
106  * <title>GtkTreeView as GtkBuildable</title>
107  * The GtkTreeView implementation of the GtkBuildable interface accepts
108  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
109  * internal #GtkTreeSelection in UI definitions.
110  * <example>
111  * <title>A UI definition fragment with GtkTreeView</title>
112  * <programlisting><![CDATA[
113  * <object class="GtkTreeView" id="treeview">
114  *   <property name="model">liststore1</property>
115  *   <child>
116  *     <object class="GtkTreeViewColumn" id="test-column">
117  *       <property name="title">Test</property>
118  *       <child>
119  *         <object class="GtkCellRendererText" id="test-renderer"/>
120  *         <attributes>
121  *           <attribute name="text">1</attribute>
122  *         </attributes>
123  *       </child>
124  *     </object>
125  *   </child>
126  *   <child internal-child="selection">
127  *     <object class="GtkTreeSelection" id="selection">
128  *       <signal name="changed" handler="on_treeview_selection_changed"/>
129  *     </object>
130  *   </child>
131  * </object>
132  * ]]></programlisting>
133  * </example>
134  * </refsect2>
135  */
136
137 enum
138 {
139   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
140   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
141   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
142   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
143   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
144 };
145
146 enum
147 {
148   RUBBER_BAND_OFF = 0,
149   RUBBER_BAND_MAYBE_START = 1,
150   RUBBER_BAND_ACTIVE = 2
151 };
152
153  /* This lovely little value is used to determine how far away from the title bar
154   * you can move the mouse and still have a column drag work.
155   */
156 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
157
158 #ifdef __GNUC__
159
160 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
161      if (!(expr))                                                       \
162        {                                                                \
163          g_log (G_LOG_DOMAIN,                                           \
164                 G_LOG_LEVEL_CRITICAL,                                   \
165                 "%s (%s): assertion `%s' failed.\n"                     \
166                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
167                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
168                 "without letting the view know.  Any display from now on is likely to\n"  \
169                 "be incorrect.\n",                                                        \
170                 G_STRLOC,                                               \
171                 G_STRFUNC,                                              \
172                 #expr);                                                 \
173          return ret;                                                    \
174        };                               }G_STMT_END
175
176 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
177      if (!(expr))                                                       \
178        {                                                                \
179          g_log (G_LOG_DOMAIN,                                           \
180                 G_LOG_LEVEL_CRITICAL,                                   \
181                 "%s (%s): assertion `%s' failed.\n"                     \
182                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
183                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
184                 "without letting the view know.  Any display from now on is likely to\n"  \
185                 "be incorrect.\n",                                                        \
186                 G_STRLOC,                                               \
187                 G_STRFUNC,                                              \
188                 #expr);                                                 \
189          return;                                                        \
190        };                               }G_STMT_END
191
192 #else
193
194 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
195      if (!(expr))                                                       \
196        {                                                                \
197          g_log (G_LOG_DOMAIN,                                           \
198                 G_LOG_LEVEL_CRITICAL,                                   \
199                 "file %s: line %d: assertion `%s' failed.\n"       \
200                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
201                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
202                 "without letting the view know.  Any display from now on is likely to\n"  \
203                 "be incorrect.\n",                                                        \
204                 __FILE__,                                               \
205                 __LINE__,                                               \
206                 #expr);                                                 \
207          return ret;                                                    \
208        };                               }G_STMT_END
209
210 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
211      if (!(expr))                                                       \
212        {                                                                \
213          g_log (G_LOG_DOMAIN,                                           \
214                 G_LOG_LEVEL_CRITICAL,                                   \
215                 "file %s: line %d: assertion '%s' failed.\n"            \
216                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
217                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
218                 "without letting the view know.  Any display from now on is likely to\n"  \
219                 "be incorrect.\n",                                                        \
220                 __FILE__,                                               \
221                 __LINE__,                                               \
222                 #expr);                                                 \
223          return;                                                        \
224        };                               }G_STMT_END
225 #endif
226
227 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
228 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
229 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
230 #define SCROLL_EDGE_SIZE 15
231 #define EXPANDER_EXTRA_PADDING 4
232 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
233 #define AUTO_EXPAND_TIMEOUT 500
234
235 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
236  * vice versa.
237  */
238 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
239 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
240
241 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
242 struct _GtkTreeViewColumnReorder
243 {
244   gint left_align;
245   gint right_align;
246   GtkTreeViewColumn *left_column;
247   GtkTreeViewColumn *right_column;
248 };
249
250 typedef struct _GtkTreeViewChild GtkTreeViewChild;
251 struct _GtkTreeViewChild
252 {
253   GtkWidget *widget;
254   gint x;
255   gint y;
256   gint width;
257   gint height;
258 };
259
260
261 typedef struct _TreeViewDragInfo TreeViewDragInfo;
262 struct _TreeViewDragInfo
263 {
264   GdkModifierType start_button_mask;
265   GtkTargetList *_unused_source_target_list;
266   GdkDragAction source_actions;
267
268   GtkTargetList *_unused_dest_target_list;
269
270   guint source_set : 1;
271   guint dest_set : 1;
272 };
273
274
275 struct _GtkTreeViewPrivate
276 {
277   GtkTreeModel *model;
278
279   /* tree information */
280   GtkRBTree *tree;
281
282   /* Container info */
283   GList *children;
284   gint width;
285   gint height;
286
287   /* Adjustments */
288   GtkAdjustment *hadjustment;
289   GtkAdjustment *vadjustment;
290   gint           min_display_width;
291   gint           min_display_height;
292
293   /* Sub windows */
294   GdkWindow *bin_window;
295   GdkWindow *header_window;
296
297   /* Scroll position state keeping */
298   GtkTreeRowReference *top_row;
299   gint top_row_dy;
300   /* dy == y pos of top_row + top_row_dy */
301   /* we cache it for simplicity of the code */
302   gint dy;
303
304   guint presize_handler_timer;
305   guint validate_rows_timer;
306   guint scroll_sync_timer;
307
308   /* Indentation and expander layout */
309   gint expander_size;
310   GtkTreeViewColumn *expander_column;
311
312   gint level_indentation;
313
314   /* Key navigation (focus), selection */
315   gint cursor_offset;
316
317   GtkTreeRowReference *anchor;
318   GtkTreeRowReference *cursor;
319
320   GtkTreeViewColumn *focus_column;
321
322   /* Current pressed node, previously pressed, prelight */
323   GtkRBNode *button_pressed_node;
324   GtkRBTree *button_pressed_tree;
325
326   gint pressed_button;
327   gint press_start_x;
328   gint press_start_y;
329
330   gint event_last_x;
331   gint event_last_y;
332
333   guint last_button_time;
334   gint last_button_x;
335   gint last_button_y;
336
337   GtkRBNode *prelight_node;
338   GtkRBTree *prelight_tree;
339
340   /* Cell Editing */
341   GtkTreeViewColumn *edited_column;
342
343   /* The node that's currently being collapsed or expanded */
344   GtkRBNode *expanded_collapsed_node;
345   GtkRBTree *expanded_collapsed_tree;
346   guint expand_collapse_timeout;
347
348   /* Auto expand/collapse timeout in hover mode */
349   guint auto_expand_timeout;
350
351   /* Selection information */
352   GtkTreeSelection *selection;
353
354   /* Header information */
355   gint n_columns;
356   GList *columns;
357   gint header_height;
358
359   GtkTreeViewColumnDropFunc column_drop_func;
360   gpointer column_drop_func_data;
361   GDestroyNotify column_drop_func_data_destroy;
362   GList *column_drag_info;
363   GtkTreeViewColumnReorder *cur_reorder;
364
365   gint prev_width_before_expander;
366
367   /* Interactive Header reordering */
368   GdkWindow *drag_window;
369   GdkWindow *drag_highlight_window;
370   GtkTreeViewColumn *drag_column;
371   gint drag_column_x;
372
373   /* Interactive Header Resizing */
374   gint drag_pos;
375   gint x_drag;
376
377   /* Non-interactive Header Resizing, expand flag support */
378   gint prev_width;
379
380   gint last_extra_space;
381   gint last_extra_space_per_column;
382   gint last_number_of_expand_columns;
383
384   /* ATK Hack */
385   GtkTreeDestroyCountFunc destroy_count_func;
386   gpointer destroy_count_data;
387   GDestroyNotify destroy_count_destroy;
388
389   /* Scroll timeout (e.g. during dnd, rubber banding) */
390   guint scroll_timeout;
391
392   /* Row drag-and-drop */
393   GtkTreeRowReference *drag_dest_row;
394   GtkTreeViewDropPosition drag_dest_pos;
395   guint open_dest_timeout;
396
397   /* Rubber banding */
398   gint rubber_band_status;
399   gint rubber_band_x;
400   gint rubber_band_y;
401   gint rubber_band_extend;
402   gint rubber_band_modify;
403
404   GtkRBNode *rubber_band_start_node;
405   GtkRBTree *rubber_band_start_tree;
406
407   GtkRBNode *rubber_band_end_node;
408   GtkRBTree *rubber_band_end_tree;
409
410   /* fixed height */
411   gint fixed_height;
412
413   /* Scroll-to functionality when unrealized */
414   GtkTreeRowReference *scroll_to_path;
415   GtkTreeViewColumn *scroll_to_column;
416   gfloat scroll_to_row_align;
417   gfloat scroll_to_col_align;
418
419   /* Interactive search */
420   gint selected_iter;
421   gint search_column;
422   GtkTreeViewSearchPositionFunc search_position_func;
423   GtkTreeViewSearchEqualFunc search_equal_func;
424   gpointer search_user_data;
425   GDestroyNotify search_destroy;
426   gpointer search_position_user_data;
427   GDestroyNotify search_position_destroy;
428   GtkWidget *search_window;
429   GtkWidget *search_entry;
430   gulong search_entry_changed_id;
431   guint typeselect_flush_timeout;
432
433   /* Grid and tree lines */
434   GtkTreeViewGridLines grid_lines;
435   double grid_line_dashes[2];
436   int grid_line_width;
437
438   gboolean tree_lines_enabled;
439   double tree_line_dashes[2];
440   int tree_line_width;
441
442   /* Row separators */
443   GtkTreeViewRowSeparatorFunc row_separator_func;
444   gpointer row_separator_data;
445   GDestroyNotify row_separator_destroy;
446
447   /* Tooltip support */
448   gint tooltip_column;
449
450   /* Here comes the bitfield */
451   guint scroll_to_use_align : 1;
452
453   guint fixed_height_mode : 1;
454   guint fixed_height_check : 1;
455
456   guint reorderable : 1;
457   guint header_has_focus : 1;
458   guint drag_column_window_state : 3;
459   /* hint to display rows in alternating colors */
460   guint has_rules : 1;
461   guint mark_rows_col_dirty : 1;
462
463   /* for DnD */
464   guint empty_view_drop : 1;
465
466   guint modify_selection_pressed : 1;
467   guint extend_selection_pressed : 1;
468
469   guint init_hadjust_value : 1;
470
471   guint in_top_row_to_dy : 1;
472
473   /* interactive search */
474   guint enable_search : 1;
475   guint disable_popdown : 1;
476   guint search_custom_entry_set : 1;
477   
478   guint hover_selection : 1;
479   guint hover_expand : 1;
480   guint imcontext_changed : 1;
481
482   guint rubber_banding_enable : 1;
483
484   guint in_grab : 1;
485
486   guint post_validation_flag : 1;
487
488   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
489   guint search_entry_avoid_unhandled_binding : 1;
490
491   /* GtkScrollablePolicy needs to be checked when
492    * driving the scrollable adjustment values */
493   guint hscroll_policy : 1;
494   guint vscroll_policy : 1;
495
496   /* GtkTreeView flags */
497   guint is_list : 1;
498   guint show_expanders : 1;
499   guint in_column_resize : 1;
500   guint arrow_prelit : 1;
501   guint headers_visible : 1;
502   guint draw_keyfocus : 1;
503   guint model_setup : 1;
504   guint in_column_drag : 1;
505 };
506
507
508 /* Signals */
509 enum
510 {
511   ROW_ACTIVATED,
512   TEST_EXPAND_ROW,
513   TEST_COLLAPSE_ROW,
514   ROW_EXPANDED,
515   ROW_COLLAPSED,
516   COLUMNS_CHANGED,
517   CURSOR_CHANGED,
518   MOVE_CURSOR,
519   SELECT_ALL,
520   UNSELECT_ALL,
521   SELECT_CURSOR_ROW,
522   TOGGLE_CURSOR_ROW,
523   EXPAND_COLLAPSE_CURSOR_ROW,
524   SELECT_CURSOR_PARENT,
525   START_INTERACTIVE_SEARCH,
526   LAST_SIGNAL
527 };
528
529 /* Properties */
530 enum {
531   PROP_0,
532   PROP_MODEL,
533   PROP_HADJUSTMENT,
534   PROP_VADJUSTMENT,
535   PROP_HSCROLL_POLICY,
536   PROP_VSCROLL_POLICY,
537   PROP_HEADERS_VISIBLE,
538   PROP_HEADERS_CLICKABLE,
539   PROP_EXPANDER_COLUMN,
540   PROP_REORDERABLE,
541   PROP_RULES_HINT,
542   PROP_ENABLE_SEARCH,
543   PROP_SEARCH_COLUMN,
544   PROP_FIXED_HEIGHT_MODE,
545   PROP_HOVER_SELECTION,
546   PROP_HOVER_EXPAND,
547   PROP_SHOW_EXPANDERS,
548   PROP_LEVEL_INDENTATION,
549   PROP_RUBBER_BANDING,
550   PROP_ENABLE_GRID_LINES,
551   PROP_ENABLE_TREE_LINES,
552   PROP_TOOLTIP_COLUMN
553 };
554
555 /* object signals */
556 static void     gtk_tree_view_finalize             (GObject          *object);
557 static void     gtk_tree_view_set_property         (GObject         *object,
558                                                     guint            prop_id,
559                                                     const GValue    *value,
560                                                     GParamSpec      *pspec);
561 static void     gtk_tree_view_get_property         (GObject         *object,
562                                                     guint            prop_id,
563                                                     GValue          *value,
564                                                     GParamSpec      *pspec);
565
566 /* gtkwidget signals */
567 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
568 static void     gtk_tree_view_realize              (GtkWidget        *widget);
569 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
570 static void     gtk_tree_view_map                  (GtkWidget        *widget);
571 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
572                                                     gint             *minimum,
573                                                     gint             *natural);
574 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
575                                                     gint             *minimum,
576                                                     gint             *natural);
577 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
578                                                     GtkRequisition   *requisition,
579                                                     gboolean          may_validate);
580 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
581                                                     GtkAllocation    *allocation);
582 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
583                                                     cairo_t          *cr);
584 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
585                                                     GdkEventKey      *event);
586 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
587                                                     GdkEventKey      *event);
588 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
589                                                     GdkEventMotion   *event);
590 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
591                                                     GdkEventCrossing *event);
592 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
593                                                     GdkEventCrossing *event);
594 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
595                                                     GdkEventButton   *event);
596 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
597                                                     GdkEventButton   *event);
598 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
599                                                     GdkEventGrabBroken *event);
600 #if 0
601 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
602                                                     GdkEventConfigure *event);
603 #endif
604
605 static GtkWidgetPath * gtk_tree_view_get_path_for_child (GtkContainer *container,
606                                                          GtkWidget    *child);
607
608 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
609                                                     GtkWidget        *child);
610 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
611                                                     GdkEventFocus    *event);
612 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
613                                                     GtkDirectionType  direction);
614 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
615 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
616 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
617                                                     gboolean          was_grabbed);
618 static void     gtk_tree_view_state_flags_changed  (GtkWidget        *widget,
619                                                     GtkStateFlags     previous_state);
620
621 /* container signals */
622 static void     gtk_tree_view_remove               (GtkContainer     *container,
623                                                     GtkWidget        *widget);
624 static void     gtk_tree_view_forall               (GtkContainer     *container,
625                                                     gboolean          include_internals,
626                                                     GtkCallback       callback,
627                                                     gpointer          callback_data);
628
629 /* Source side drag signals */
630 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
631                                             GdkDragContext   *context);
632 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
633                                             GdkDragContext   *context);
634 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
635                                             GdkDragContext   *context,
636                                             GtkSelectionData *selection_data,
637                                             guint             info,
638                                             guint             time);
639 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
640                                             GdkDragContext   *context);
641
642 /* Target side drag signals */
643 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
644                                                   GdkDragContext   *context,
645                                                   guint             time);
646 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
647                                                   GdkDragContext   *context,
648                                                   gint              x,
649                                                   gint              y,
650                                                   guint             time);
651 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
652                                                   GdkDragContext   *context,
653                                                   gint              x,
654                                                   gint              y,
655                                                   guint             time);
656 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
657                                                   GdkDragContext   *context,
658                                                   gint              x,
659                                                   gint              y,
660                                                   GtkSelectionData *selection_data,
661                                                   guint             info,
662                                                   guint             time);
663
664 /* tree_model signals */
665 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
666                                                            GtkMovementStep  step,
667                                                            gint             count);
668 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
669 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
670 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
671                                                            gboolean         start_editing);
672 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
673 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
674                                                                gboolean         logical,
675                                                                gboolean         expand,
676                                                                gboolean         open_all);
677 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
678 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
679                                                            GtkTreePath     *path,
680                                                            GtkTreeIter     *iter,
681                                                            gpointer         data);
682 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
683                                                            GtkTreePath     *path,
684                                                            GtkTreeIter     *iter,
685                                                            gpointer         data);
686 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
687                                                            GtkTreePath     *path,
688                                                            GtkTreeIter     *iter,
689                                                            gpointer         data);
690 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
691                                                            GtkTreePath     *path,
692                                                            gpointer         data);
693 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
694                                                            GtkTreePath     *parent,
695                                                            GtkTreeIter     *iter,
696                                                            gint            *new_order,
697                                                            gpointer         data);
698
699 /* Incremental reflow */
700 static gboolean validate_row             (GtkTreeView *tree_view,
701                                           GtkRBTree   *tree,
702                                           GtkRBNode   *node,
703                                           GtkTreeIter *iter,
704                                           GtkTreePath *path);
705 static void     validate_visible_area    (GtkTreeView *tree_view);
706 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
707 static gboolean do_validate_rows         (GtkTreeView *tree_view,
708                                           gboolean     size_request);
709 static gboolean validate_rows            (GtkTreeView *tree_view);
710 static gboolean presize_handler_callback (gpointer     data);
711 static void     install_presize_handler  (GtkTreeView *tree_view);
712 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
713 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
714                                              GtkTreePath *path,
715                                              gint         offset);
716 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
717 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
718 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
719
720 /* Internal functions */
721 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
722                                                               GtkTreeViewColumn  *column);
723 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
724 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
725                                                               guint               keyval,
726                                                               guint               modmask,
727                                                               gboolean            add_shifted_binding,
728                                                               GtkMovementStep     step,
729                                                               gint                count);
730 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
731                                                               GtkRBTree          *tree);
732 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
733                                                               GtkTreePath        *path,
734                                                               const GdkRectangle *clip_rect);
735 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
736                                                               GtkRBTree          *tree,
737                                                               GtkRBNode          *node);
738 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
739                                                               cairo_t            *cr,
740                                                               GtkRBTree          *tree,
741                                                               GtkRBNode          *node,
742                                                               gint                x,
743                                                               gint                y);
744 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
745                                                               GtkRBTree          *tree,
746                                                               gint               *x1,
747                                                               gint               *x2);
748 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
749                                                               gint                i,
750                                                               gint               *x);
751 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
752                                                               GtkTreeView        *tree_view);
753 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
754                                                               GtkRBTree          *tree,
755                                                               GtkTreeIter        *iter,
756                                                               gint                depth,
757                                                               gboolean            recurse);
758 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
759                                                               GtkRBTree          *tree,
760                                                               GtkRBNode          *node);
761 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
762                                                               GtkTreeViewColumn  *column,
763                                                               gboolean            focus_to_cell);
764 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
765                                                               GdkEventMotion     *event);
766 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
767 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
768                                                               gint                count);
769 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
770                                                               gint                count);
771 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
772                                                               gint                count);
773 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
774                                                               gint                count);
775 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
776                                                               GtkTreePath        *path,
777                                                               GtkRBTree          *tree,
778                                                               GtkRBNode          *node,
779                                                               gboolean            animate);
780 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
781                                                               GtkTreePath        *path,
782                                                               GtkRBTree          *tree,
783                                                               GtkRBNode          *node,
784                                                               gboolean            open_all,
785                                                               gboolean            animate);
786 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
787                                                               GtkTreePath        *path,
788                                                               gboolean            clear_and_select,
789                                                               gboolean            clamp_node);
790 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
791 static void     column_sizing_notify                         (GObject            *object,
792                                                               GParamSpec         *pspec,
793                                                               gpointer            data);
794 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
795 static void     update_prelight                              (GtkTreeView        *tree_view,
796                                                               int                 x,
797                                                               int                 y);
798
799 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
800
801 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
802                                                               GtkRBTree   *tree,
803                                                               GtkRBNode   *node,
804                                                               gint         vertical_separator);
805 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
806                                                               GtkRBNode   *node,
807                                                               gint         vertical_separator);
808
809 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
810                                                               GtkRBTree   *tree,
811                                                               GtkRBNode   *node);
812 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
813                                                               GtkRBNode   *node);
814
815 /* interactive search */
816 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
817 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
818                                                          GtkTreeView      *tree_view,
819                                                          GdkDevice        *device);
820 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
821                                                          GtkWidget        *search_dialog,
822                                                          gpointer          user_data);
823 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
824                                                          GtkMenu          *menu,
825                                                          gpointer          data);
826 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
827                                                          GtkTreeView      *tree_view);
828 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
829                                                          GtkTreeView      *tree_view);
830 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
831 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
832                                                          gpointer          data);
833 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
834                                                          GdkEventAny      *event,
835                                                          GtkTreeView      *tree_view);
836 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
837                                                          GdkEventButton   *event,
838                                                          GtkTreeView      *tree_view);
839 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
840                                                          GdkEventScroll   *event,
841                                                          GtkTreeView      *tree_view);
842 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
843                                                          GdkEventKey      *event,
844                                                          GtkTreeView      *tree_view);
845 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
846                                                          GtkTreeView      *tree_view,
847                                                          gboolean          up);
848 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
849                                                          gint              column,
850                                                          const gchar      *key,
851                                                          GtkTreeIter      *iter,
852                                                          gpointer          search_data);
853 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
854                                                          GtkTreeSelection *selection,
855                                                          GtkTreeIter      *iter,
856                                                          const gchar      *text,
857                                                          gint             *count,
858                                                          gint              n);
859 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
860                                                          GtkTreeView      *tree_view);
861 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
862                                                          GtkWidget        *child_widget,
863                                                          gint              x,
864                                                          gint              y,
865                                                          gint              width,
866                                                          gint              height);
867 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
868                                                          GtkTreePath      *cursor_path,
869                                                          gboolean          edit_only);
870 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
871                                                          gboolean     cancel_editing);
872 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
873                                                              GdkDevice   *device,
874                                                              gboolean     keybinding);
875 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
876 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
877                                                          GtkTreeViewColumn *column,
878                                                          gint               drop_position);
879
880 /* GtkBuildable */
881 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
882                                                             GtkBuilder        *builder,
883                                                             GObject           *child,
884                                                             const gchar       *type);
885 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
886                                                             GtkBuilder        *builder,
887                                                             const gchar       *childname);
888 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
889
890
891 static gboolean scroll_row_timeout                   (gpointer     data);
892 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
893 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
894
895 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
896
897 \f
898
899 /* GType Methods
900  */
901
902 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
903                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
904                                                 gtk_tree_view_buildable_init)
905                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
906
907 static void
908 gtk_tree_view_class_init (GtkTreeViewClass *class)
909 {
910   GObjectClass *o_class;
911   GtkWidgetClass *widget_class;
912   GtkContainerClass *container_class;
913   GtkBindingSet *binding_set;
914
915   binding_set = gtk_binding_set_by_class (class);
916
917   o_class = (GObjectClass *) class;
918   widget_class = (GtkWidgetClass *) class;
919   container_class = (GtkContainerClass *) class;
920
921   /* GObject signals */
922   o_class->set_property = gtk_tree_view_set_property;
923   o_class->get_property = gtk_tree_view_get_property;
924   o_class->finalize = gtk_tree_view_finalize;
925
926   /* GtkWidget signals */
927   widget_class->destroy = gtk_tree_view_destroy;
928   widget_class->map = gtk_tree_view_map;
929   widget_class->realize = gtk_tree_view_realize;
930   widget_class->unrealize = gtk_tree_view_unrealize;
931   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
932   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
933   widget_class->size_allocate = gtk_tree_view_size_allocate;
934   widget_class->button_press_event = gtk_tree_view_button_press;
935   widget_class->button_release_event = gtk_tree_view_button_release;
936   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
937   /*widget_class->configure_event = gtk_tree_view_configure;*/
938   widget_class->motion_notify_event = gtk_tree_view_motion;
939   widget_class->draw = gtk_tree_view_draw;
940   widget_class->key_press_event = gtk_tree_view_key_press;
941   widget_class->key_release_event = gtk_tree_view_key_release;
942   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
943   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
944   widget_class->focus_out_event = gtk_tree_view_focus_out;
945   widget_class->drag_begin = gtk_tree_view_drag_begin;
946   widget_class->drag_end = gtk_tree_view_drag_end;
947   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
948   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
949   widget_class->drag_leave = gtk_tree_view_drag_leave;
950   widget_class->drag_motion = gtk_tree_view_drag_motion;
951   widget_class->drag_drop = gtk_tree_view_drag_drop;
952   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
953   widget_class->focus = gtk_tree_view_focus;
954   widget_class->grab_focus = gtk_tree_view_grab_focus;
955   widget_class->style_updated = gtk_tree_view_style_updated;
956   widget_class->grab_notify = gtk_tree_view_grab_notify;
957   widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
958
959   /* GtkContainer signals */
960   container_class->remove = gtk_tree_view_remove;
961   container_class->forall = gtk_tree_view_forall;
962   container_class->set_focus_child = gtk_tree_view_set_focus_child;
963   container_class->get_path_for_child = gtk_tree_view_get_path_for_child;
964
965   class->move_cursor = gtk_tree_view_real_move_cursor;
966   class->select_all = gtk_tree_view_real_select_all;
967   class->unselect_all = gtk_tree_view_real_unselect_all;
968   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
969   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
970   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
971   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
972   class->start_interactive_search = gtk_tree_view_start_interactive_search;
973
974   /* Properties */
975
976   g_object_class_install_property (o_class,
977                                    PROP_MODEL,
978                                    g_param_spec_object ("model",
979                                                         P_("TreeView Model"),
980                                                         P_("The model for the tree view"),
981                                                         GTK_TYPE_TREE_MODEL,
982                                                         GTK_PARAM_READWRITE));
983
984   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
985   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
986   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
987   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
988
989   g_object_class_install_property (o_class,
990                                    PROP_HEADERS_VISIBLE,
991                                    g_param_spec_boolean ("headers-visible",
992                                                          P_("Headers Visible"),
993                                                          P_("Show the column header buttons"),
994                                                          TRUE,
995                                                          GTK_PARAM_READWRITE));
996
997   g_object_class_install_property (o_class,
998                                    PROP_HEADERS_CLICKABLE,
999                                    g_param_spec_boolean ("headers-clickable",
1000                                                          P_("Headers Clickable"),
1001                                                          P_("Column headers respond to click events"),
1002                                                          TRUE,
1003                                                          GTK_PARAM_READWRITE));
1004
1005   g_object_class_install_property (o_class,
1006                                    PROP_EXPANDER_COLUMN,
1007                                    g_param_spec_object ("expander-column",
1008                                                         P_("Expander Column"),
1009                                                         P_("Set the column for the expander column"),
1010                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1011                                                         GTK_PARAM_READWRITE));
1012
1013   g_object_class_install_property (o_class,
1014                                    PROP_REORDERABLE,
1015                                    g_param_spec_boolean ("reorderable",
1016                                                          P_("Reorderable"),
1017                                                          P_("View is reorderable"),
1018                                                          FALSE,
1019                                                          GTK_PARAM_READWRITE));
1020
1021   g_object_class_install_property (o_class,
1022                                    PROP_RULES_HINT,
1023                                    g_param_spec_boolean ("rules-hint",
1024                                                          P_("Rules Hint"),
1025                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1026                                                          FALSE,
1027                                                          GTK_PARAM_READWRITE));
1028
1029     g_object_class_install_property (o_class,
1030                                      PROP_ENABLE_SEARCH,
1031                                      g_param_spec_boolean ("enable-search",
1032                                                            P_("Enable Search"),
1033                                                            P_("View allows user to search through columns interactively"),
1034                                                            TRUE,
1035                                                            GTK_PARAM_READWRITE));
1036
1037     g_object_class_install_property (o_class,
1038                                      PROP_SEARCH_COLUMN,
1039                                      g_param_spec_int ("search-column",
1040                                                        P_("Search Column"),
1041                                                        P_("Model column to search through during interactive search"),
1042                                                        -1,
1043                                                        G_MAXINT,
1044                                                        -1,
1045                                                        GTK_PARAM_READWRITE));
1046
1047     /**
1048      * GtkTreeView:fixed-height-mode:
1049      *
1050      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1051      * #GtkTreeView by assuming that all rows have the same height. 
1052      * Only enable this option if all rows are the same height.  
1053      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1054      * information on this option.
1055      *
1056      * Since: 2.4
1057      **/
1058     g_object_class_install_property (o_class,
1059                                      PROP_FIXED_HEIGHT_MODE,
1060                                      g_param_spec_boolean ("fixed-height-mode",
1061                                                            P_("Fixed Height Mode"),
1062                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1063                                                            FALSE,
1064                                                            GTK_PARAM_READWRITE));
1065     
1066     /**
1067      * GtkTreeView:hover-selection:
1068      * 
1069      * Enables or disables the hover selection mode of @tree_view.
1070      * Hover selection makes the selected row follow the pointer.
1071      * Currently, this works only for the selection modes 
1072      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1073      *
1074      * This mode is primarily intended for treeviews in popups, e.g.
1075      * in #GtkComboBox or #GtkEntryCompletion.
1076      *
1077      * Since: 2.6
1078      */
1079     g_object_class_install_property (o_class,
1080                                      PROP_HOVER_SELECTION,
1081                                      g_param_spec_boolean ("hover-selection",
1082                                                            P_("Hover Selection"),
1083                                                            P_("Whether the selection should follow the pointer"),
1084                                                            FALSE,
1085                                                            GTK_PARAM_READWRITE));
1086
1087     /**
1088      * GtkTreeView:hover-expand:
1089      * 
1090      * Enables or disables the hover expansion mode of @tree_view.
1091      * Hover expansion makes rows expand or collapse if the pointer moves 
1092      * over them.
1093      *
1094      * This mode is primarily intended for treeviews in popups, e.g.
1095      * in #GtkComboBox or #GtkEntryCompletion.
1096      *
1097      * Since: 2.6
1098      */
1099     g_object_class_install_property (o_class,
1100                                      PROP_HOVER_EXPAND,
1101                                      g_param_spec_boolean ("hover-expand",
1102                                                            P_("Hover Expand"),
1103                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1104                                                            FALSE,
1105                                                            GTK_PARAM_READWRITE));
1106
1107     /**
1108      * GtkTreeView:show-expanders:
1109      *
1110      * %TRUE if the view has expanders.
1111      *
1112      * Since: 2.12
1113      */
1114     g_object_class_install_property (o_class,
1115                                      PROP_SHOW_EXPANDERS,
1116                                      g_param_spec_boolean ("show-expanders",
1117                                                            P_("Show Expanders"),
1118                                                            P_("View has expanders"),
1119                                                            TRUE,
1120                                                            GTK_PARAM_READWRITE));
1121
1122     /**
1123      * GtkTreeView:level-indentation:
1124      *
1125      * Extra indentation for each level.
1126      *
1127      * Since: 2.12
1128      */
1129     g_object_class_install_property (o_class,
1130                                      PROP_LEVEL_INDENTATION,
1131                                      g_param_spec_int ("level-indentation",
1132                                                        P_("Level Indentation"),
1133                                                        P_("Extra indentation for each level"),
1134                                                        0,
1135                                                        G_MAXINT,
1136                                                        0,
1137                                                        GTK_PARAM_READWRITE));
1138
1139     g_object_class_install_property (o_class,
1140                                      PROP_RUBBER_BANDING,
1141                                      g_param_spec_boolean ("rubber-banding",
1142                                                            P_("Rubber Banding"),
1143                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1144                                                            FALSE,
1145                                                            GTK_PARAM_READWRITE));
1146
1147     g_object_class_install_property (o_class,
1148                                      PROP_ENABLE_GRID_LINES,
1149                                      g_param_spec_enum ("enable-grid-lines",
1150                                                         P_("Enable Grid Lines"),
1151                                                         P_("Whether grid lines should be drawn in the tree view"),
1152                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1153                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1154                                                         GTK_PARAM_READWRITE));
1155
1156     g_object_class_install_property (o_class,
1157                                      PROP_ENABLE_TREE_LINES,
1158                                      g_param_spec_boolean ("enable-tree-lines",
1159                                                            P_("Enable Tree Lines"),
1160                                                            P_("Whether tree lines should be drawn in the tree view"),
1161                                                            FALSE,
1162                                                            GTK_PARAM_READWRITE));
1163
1164     g_object_class_install_property (o_class,
1165                                      PROP_TOOLTIP_COLUMN,
1166                                      g_param_spec_int ("tooltip-column",
1167                                                        P_("Tooltip Column"),
1168                                                        P_("The column in the model containing the tooltip texts for the rows"),
1169                                                        -1,
1170                                                        G_MAXINT,
1171                                                        -1,
1172                                                        GTK_PARAM_READWRITE));
1173
1174   /* Style properties */
1175 #define _TREE_VIEW_EXPANDER_SIZE 14
1176 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1177 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1178
1179   gtk_widget_class_install_style_property (widget_class,
1180                                            g_param_spec_int ("expander-size",
1181                                                              P_("Expander Size"),
1182                                                              P_("Size of the expander arrow"),
1183                                                              0,
1184                                                              G_MAXINT,
1185                                                              _TREE_VIEW_EXPANDER_SIZE,
1186                                                              GTK_PARAM_READABLE));
1187
1188   gtk_widget_class_install_style_property (widget_class,
1189                                            g_param_spec_int ("vertical-separator",
1190                                                              P_("Vertical Separator Width"),
1191                                                              P_("Vertical space between cells.  Must be an even number"),
1192                                                              0,
1193                                                              G_MAXINT,
1194                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1195                                                              GTK_PARAM_READABLE));
1196
1197   gtk_widget_class_install_style_property (widget_class,
1198                                            g_param_spec_int ("horizontal-separator",
1199                                                              P_("Horizontal Separator Width"),
1200                                                              P_("Horizontal space between cells.  Must be an even number"),
1201                                                              0,
1202                                                              G_MAXINT,
1203                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1204                                                              GTK_PARAM_READABLE));
1205
1206   gtk_widget_class_install_style_property (widget_class,
1207                                            g_param_spec_boolean ("allow-rules",
1208                                                                  P_("Allow Rules"),
1209                                                                  P_("Allow drawing of alternating color rows"),
1210                                                                  TRUE,
1211                                                                  GTK_PARAM_READABLE));
1212
1213   gtk_widget_class_install_style_property (widget_class,
1214                                            g_param_spec_boolean ("indent-expanders",
1215                                                                  P_("Indent Expanders"),
1216                                                                  P_("Make the expanders indented"),
1217                                                                  TRUE,
1218                                                                  GTK_PARAM_READABLE));
1219
1220   gtk_widget_class_install_style_property (widget_class,
1221                                            g_param_spec_boxed ("even-row-color",
1222                                                                P_("Even Row Color"),
1223                                                                P_("Color to use for even rows"),
1224                                                                GDK_TYPE_COLOR,
1225                                                                GTK_PARAM_READABLE));
1226
1227   gtk_widget_class_install_style_property (widget_class,
1228                                            g_param_spec_boxed ("odd-row-color",
1229                                                                P_("Odd Row Color"),
1230                                                                P_("Color to use for odd rows"),
1231                                                                GDK_TYPE_COLOR,
1232                                                                GTK_PARAM_READABLE));
1233
1234   gtk_widget_class_install_style_property (widget_class,
1235                                            g_param_spec_int ("grid-line-width",
1236                                                              P_("Grid line width"),
1237                                                              P_("Width, in pixels, of the tree view grid lines"),
1238                                                              0, G_MAXINT, 1,
1239                                                              GTK_PARAM_READABLE));
1240
1241   gtk_widget_class_install_style_property (widget_class,
1242                                            g_param_spec_int ("tree-line-width",
1243                                                              P_("Tree line width"),
1244                                                              P_("Width, in pixels, of the tree view lines"),
1245                                                              0, G_MAXINT, 1,
1246                                                              GTK_PARAM_READABLE));
1247
1248   gtk_widget_class_install_style_property (widget_class,
1249                                            g_param_spec_string ("grid-line-pattern",
1250                                                                 P_("Grid line pattern"),
1251                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1252                                                                 "\1\1",
1253                                                                 GTK_PARAM_READABLE));
1254
1255   gtk_widget_class_install_style_property (widget_class,
1256                                            g_param_spec_string ("tree-line-pattern",
1257                                                                 P_("Tree line pattern"),
1258                                                                 P_("Dash pattern used to draw the tree view lines"),
1259                                                                 "\1\1",
1260                                                                 GTK_PARAM_READABLE));
1261
1262   /* Signals */
1263   /**
1264    * GtkTreeView::row-activated:
1265    * @tree_view: the object on which the signal is emitted
1266    * @path: the #GtkTreePath for the activated row
1267    * @column: the #GtkTreeViewColumn in which the activation occurred
1268    *
1269    * The "row-activated" signal is emitted when the method
1270    * gtk_tree_view_row_activated() is called or the user double clicks 
1271    * a treeview row. It is also emitted when a non-editable row is 
1272    * selected and one of the keys: Space, Shift+Space, Return or 
1273    * Enter is pressed.
1274    * 
1275    * For selection handling refer to the <link linkend="TreeWidget">tree 
1276    * widget conceptual overview</link> as well as #GtkTreeSelection.
1277    */
1278   tree_view_signals[ROW_ACTIVATED] =
1279     g_signal_new (I_("row-activated"),
1280                   G_TYPE_FROM_CLASS (o_class),
1281                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1282                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1283                   NULL, NULL,
1284                   _gtk_marshal_VOID__BOXED_OBJECT,
1285                   G_TYPE_NONE, 2,
1286                   GTK_TYPE_TREE_PATH,
1287                   GTK_TYPE_TREE_VIEW_COLUMN);
1288
1289   /**
1290    * GtkTreeView::test-expand-row:
1291    * @tree_view: the object on which the signal is emitted
1292    * @iter: the tree iter of the row to expand
1293    * @path: a tree path that points to the row 
1294    * 
1295    * The given row is about to be expanded (show its children nodes). Use this
1296    * signal if you need to control the expandability of individual rows.
1297    *
1298    * Returns: %FALSE to allow expansion, %TRUE to reject
1299    */
1300   tree_view_signals[TEST_EXPAND_ROW] =
1301     g_signal_new (I_("test-expand-row"),
1302                   G_TYPE_FROM_CLASS (o_class),
1303                   G_SIGNAL_RUN_LAST,
1304                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1305                   _gtk_boolean_handled_accumulator, NULL,
1306                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1307                   G_TYPE_BOOLEAN, 2,
1308                   GTK_TYPE_TREE_ITER,
1309                   GTK_TYPE_TREE_PATH);
1310
1311   /**
1312    * GtkTreeView::test-collapse-row:
1313    * @tree_view: the object on which the signal is emitted
1314    * @iter: the tree iter of the row to collapse
1315    * @path: a tree path that points to the row 
1316    * 
1317    * The given row is about to be collapsed (hide its children nodes). Use this
1318    * signal if you need to control the collapsibility of individual rows.
1319    *
1320    * Returns: %FALSE to allow collapsing, %TRUE to reject
1321    */
1322   tree_view_signals[TEST_COLLAPSE_ROW] =
1323     g_signal_new (I_("test-collapse-row"),
1324                   G_TYPE_FROM_CLASS (o_class),
1325                   G_SIGNAL_RUN_LAST,
1326                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1327                   _gtk_boolean_handled_accumulator, NULL,
1328                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1329                   G_TYPE_BOOLEAN, 2,
1330                   GTK_TYPE_TREE_ITER,
1331                   GTK_TYPE_TREE_PATH);
1332
1333   /**
1334    * GtkTreeView::row-expanded:
1335    * @tree_view: the object on which the signal is emitted
1336    * @iter: the tree iter of the expanded row
1337    * @path: a tree path that points to the row 
1338    * 
1339    * The given row has been expanded (child nodes are shown).
1340    */
1341   tree_view_signals[ROW_EXPANDED] =
1342     g_signal_new (I_("row-expanded"),
1343                   G_TYPE_FROM_CLASS (o_class),
1344                   G_SIGNAL_RUN_LAST,
1345                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1346                   NULL, NULL,
1347                   _gtk_marshal_VOID__BOXED_BOXED,
1348                   G_TYPE_NONE, 2,
1349                   GTK_TYPE_TREE_ITER,
1350                   GTK_TYPE_TREE_PATH);
1351
1352   /**
1353    * GtkTreeView::row-collapsed:
1354    * @tree_view: the object on which the signal is emitted
1355    * @iter: the tree iter of the collapsed row
1356    * @path: a tree path that points to the row 
1357    * 
1358    * The given row has been collapsed (child nodes are hidden).
1359    */
1360   tree_view_signals[ROW_COLLAPSED] =
1361     g_signal_new (I_("row-collapsed"),
1362                   G_TYPE_FROM_CLASS (o_class),
1363                   G_SIGNAL_RUN_LAST,
1364                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1365                   NULL, NULL,
1366                   _gtk_marshal_VOID__BOXED_BOXED,
1367                   G_TYPE_NONE, 2,
1368                   GTK_TYPE_TREE_ITER,
1369                   GTK_TYPE_TREE_PATH);
1370
1371   /**
1372    * GtkTreeView::columns-changed:
1373    * @tree_view: the object on which the signal is emitted 
1374    * 
1375    * The number of columns of the treeview has changed.
1376    */
1377   tree_view_signals[COLUMNS_CHANGED] =
1378     g_signal_new (I_("columns-changed"),
1379                   G_TYPE_FROM_CLASS (o_class),
1380                   G_SIGNAL_RUN_LAST,
1381                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1382                   NULL, NULL,
1383                   _gtk_marshal_VOID__VOID,
1384                   G_TYPE_NONE, 0);
1385
1386   /**
1387    * GtkTreeView::cursor-changed:
1388    * @tree_view: the object on which the signal is emitted
1389    * 
1390    * The position of the cursor (focused cell) has changed.
1391    */
1392   tree_view_signals[CURSOR_CHANGED] =
1393     g_signal_new (I_("cursor-changed"),
1394                   G_TYPE_FROM_CLASS (o_class),
1395                   G_SIGNAL_RUN_LAST,
1396                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1397                   NULL, NULL,
1398                   _gtk_marshal_VOID__VOID,
1399                   G_TYPE_NONE, 0);
1400
1401   tree_view_signals[MOVE_CURSOR] =
1402     g_signal_new (I_("move-cursor"),
1403                   G_TYPE_FROM_CLASS (o_class),
1404                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1405                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1406                   NULL, NULL,
1407                   _gtk_marshal_BOOLEAN__ENUM_INT,
1408                   G_TYPE_BOOLEAN, 2,
1409                   GTK_TYPE_MOVEMENT_STEP,
1410                   G_TYPE_INT);
1411
1412   tree_view_signals[SELECT_ALL] =
1413     g_signal_new (I_("select-all"),
1414                   G_TYPE_FROM_CLASS (o_class),
1415                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1416                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1417                   NULL, NULL,
1418                   _gtk_marshal_BOOLEAN__VOID,
1419                   G_TYPE_BOOLEAN, 0);
1420
1421   tree_view_signals[UNSELECT_ALL] =
1422     g_signal_new (I_("unselect-all"),
1423                   G_TYPE_FROM_CLASS (o_class),
1424                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1425                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1426                   NULL, NULL,
1427                   _gtk_marshal_BOOLEAN__VOID,
1428                   G_TYPE_BOOLEAN, 0);
1429
1430   tree_view_signals[SELECT_CURSOR_ROW] =
1431     g_signal_new (I_("select-cursor-row"),
1432                   G_TYPE_FROM_CLASS (o_class),
1433                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1434                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1435                   NULL, NULL,
1436                   _gtk_marshal_BOOLEAN__BOOLEAN,
1437                   G_TYPE_BOOLEAN, 1,
1438                   G_TYPE_BOOLEAN);
1439
1440   tree_view_signals[TOGGLE_CURSOR_ROW] =
1441     g_signal_new (I_("toggle-cursor-row"),
1442                   G_TYPE_FROM_CLASS (o_class),
1443                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1444                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1445                   NULL, NULL,
1446                   _gtk_marshal_BOOLEAN__VOID,
1447                   G_TYPE_BOOLEAN, 0);
1448
1449   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1450     g_signal_new (I_("expand-collapse-cursor-row"),
1451                   G_TYPE_FROM_CLASS (o_class),
1452                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1453                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1454                   NULL, NULL,
1455                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1456                   G_TYPE_BOOLEAN, 3,
1457                   G_TYPE_BOOLEAN,
1458                   G_TYPE_BOOLEAN,
1459                   G_TYPE_BOOLEAN);
1460
1461   tree_view_signals[SELECT_CURSOR_PARENT] =
1462     g_signal_new (I_("select-cursor-parent"),
1463                   G_TYPE_FROM_CLASS (o_class),
1464                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1465                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1466                   NULL, NULL,
1467                   _gtk_marshal_BOOLEAN__VOID,
1468                   G_TYPE_BOOLEAN, 0);
1469
1470   tree_view_signals[START_INTERACTIVE_SEARCH] =
1471     g_signal_new (I_("start-interactive-search"),
1472                   G_TYPE_FROM_CLASS (o_class),
1473                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1474                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1475                   NULL, NULL,
1476                   _gtk_marshal_BOOLEAN__VOID,
1477                   G_TYPE_BOOLEAN, 0);
1478
1479   /* Key bindings */
1480   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1481                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1482   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1483                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1484
1485   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1486                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1487   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1488                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1489
1490   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1491                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1492
1493   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1494                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1495
1496   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1497                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1498   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1499                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1500
1501   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1502                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1503   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1504                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1505
1506   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1507                                   GTK_MOVEMENT_PAGES, -1);
1508   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1509                                   GTK_MOVEMENT_PAGES, -1);
1510
1511   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1512                                   GTK_MOVEMENT_PAGES, 1);
1513   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1514                                   GTK_MOVEMENT_PAGES, 1);
1515
1516
1517   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1518                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1519                                 G_TYPE_INT, 1);
1520
1521   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1522                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1523                                 G_TYPE_INT, -1);
1524
1525   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1526                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1527                                 G_TYPE_INT, 1);
1528
1529   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1530                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1531                                 G_TYPE_INT, -1);
1532
1533   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1534                                 "move-cursor", 2,
1535                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1536                                 G_TYPE_INT, 1);
1537
1538   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1539                                 "move-cursor", 2,
1540                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1541                                 G_TYPE_INT, -1);
1542
1543   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_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_KP_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_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1554   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1555
1556   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1557   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1558
1559   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1560   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1561
1562   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1563                                 G_TYPE_BOOLEAN, TRUE);
1564   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1565                                 G_TYPE_BOOLEAN, TRUE);
1566
1567   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1568                                 G_TYPE_BOOLEAN, TRUE);
1569   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1570                                 G_TYPE_BOOLEAN, TRUE);
1571   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1572                                 G_TYPE_BOOLEAN, TRUE);
1573   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1574                                 G_TYPE_BOOLEAN, TRUE);
1575   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1576                                 G_TYPE_BOOLEAN, TRUE);
1577
1578   /* expand and collapse rows */
1579   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1580                                 G_TYPE_BOOLEAN, TRUE,
1581                                 G_TYPE_BOOLEAN, TRUE,
1582                                 G_TYPE_BOOLEAN, FALSE);
1583
1584   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1585                                 "expand-collapse-cursor-row", 3,
1586                                 G_TYPE_BOOLEAN, TRUE,
1587                                 G_TYPE_BOOLEAN, TRUE,
1588                                 G_TYPE_BOOLEAN, TRUE);
1589   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1590                                 "expand-collapse-cursor-row", 3,
1591                                 G_TYPE_BOOLEAN, TRUE,
1592                                 G_TYPE_BOOLEAN, TRUE,
1593                                 G_TYPE_BOOLEAN, TRUE);
1594
1595   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1596                                 "expand-collapse-cursor-row", 3,
1597                                 G_TYPE_BOOLEAN, TRUE,
1598                                 G_TYPE_BOOLEAN, FALSE,
1599                                 G_TYPE_BOOLEAN, FALSE);
1600   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1601                                 "expand-collapse-cursor-row", 3,
1602                                 G_TYPE_BOOLEAN, TRUE,
1603                                 G_TYPE_BOOLEAN, FALSE,
1604                                 G_TYPE_BOOLEAN, FALSE);
1605
1606   /* Not doable on US keyboards */
1607   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1608                                 G_TYPE_BOOLEAN, TRUE,
1609                                 G_TYPE_BOOLEAN, TRUE,
1610                                 G_TYPE_BOOLEAN, TRUE);
1611   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1612                                 G_TYPE_BOOLEAN, TRUE,
1613                                 G_TYPE_BOOLEAN, TRUE,
1614                                 G_TYPE_BOOLEAN, FALSE);
1615   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1616                                 G_TYPE_BOOLEAN, TRUE,
1617                                 G_TYPE_BOOLEAN, TRUE,
1618                                 G_TYPE_BOOLEAN, TRUE);
1619   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1620                                 G_TYPE_BOOLEAN, TRUE,
1621                                 G_TYPE_BOOLEAN, TRUE,
1622                                 G_TYPE_BOOLEAN, TRUE);
1623   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1624                                 "expand-collapse-cursor-row", 3,
1625                                 G_TYPE_BOOLEAN, FALSE,
1626                                 G_TYPE_BOOLEAN, TRUE,
1627                                 G_TYPE_BOOLEAN, TRUE);
1628   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1629                                 "expand-collapse-cursor-row", 3,
1630                                 G_TYPE_BOOLEAN, FALSE,
1631                                 G_TYPE_BOOLEAN, TRUE,
1632                                 G_TYPE_BOOLEAN, TRUE);
1633   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1634                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1635                                 "expand-collapse-cursor-row", 3,
1636                                 G_TYPE_BOOLEAN, FALSE,
1637                                 G_TYPE_BOOLEAN, TRUE,
1638                                 G_TYPE_BOOLEAN, TRUE);
1639   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1640                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1641                                 "expand-collapse-cursor-row", 3,
1642                                 G_TYPE_BOOLEAN, FALSE,
1643                                 G_TYPE_BOOLEAN, TRUE,
1644                                 G_TYPE_BOOLEAN, TRUE);
1645
1646   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1647                                 G_TYPE_BOOLEAN, TRUE,
1648                                 G_TYPE_BOOLEAN, FALSE,
1649                                 G_TYPE_BOOLEAN, FALSE);
1650   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1651                                 G_TYPE_BOOLEAN, TRUE,
1652                                 G_TYPE_BOOLEAN, FALSE,
1653                                 G_TYPE_BOOLEAN, TRUE);
1654   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1655                                 G_TYPE_BOOLEAN, TRUE,
1656                                 G_TYPE_BOOLEAN, FALSE,
1657                                 G_TYPE_BOOLEAN, FALSE);
1658   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1659                                 G_TYPE_BOOLEAN, TRUE,
1660                                 G_TYPE_BOOLEAN, FALSE,
1661                                 G_TYPE_BOOLEAN, TRUE);
1662   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1663                                 "expand-collapse-cursor-row", 3,
1664                                 G_TYPE_BOOLEAN, FALSE,
1665                                 G_TYPE_BOOLEAN, FALSE,
1666                                 G_TYPE_BOOLEAN, TRUE);
1667   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1668                                 "expand-collapse-cursor-row", 3,
1669                                 G_TYPE_BOOLEAN, FALSE,
1670                                 G_TYPE_BOOLEAN, FALSE,
1671                                 G_TYPE_BOOLEAN, TRUE);
1672   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1673                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1674                                 "expand-collapse-cursor-row", 3,
1675                                 G_TYPE_BOOLEAN, FALSE,
1676                                 G_TYPE_BOOLEAN, FALSE,
1677                                 G_TYPE_BOOLEAN, TRUE);
1678   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1679                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1680                                 "expand-collapse-cursor-row", 3,
1681                                 G_TYPE_BOOLEAN, FALSE,
1682                                 G_TYPE_BOOLEAN, FALSE,
1683                                 G_TYPE_BOOLEAN, TRUE);
1684
1685   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1686   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1687
1688   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1689
1690   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1691
1692   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1693
1694   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TREE_VIEW_ACCESSIBLE);
1695 }
1696
1697 static void
1698 gtk_tree_view_init (GtkTreeView *tree_view)
1699 {
1700   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1701
1702   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1703   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1704
1705   tree_view->priv->show_expanders = TRUE;
1706   tree_view->priv->draw_keyfocus = TRUE;
1707   tree_view->priv->headers_visible = TRUE;
1708
1709   /* We need some padding */
1710   tree_view->priv->dy = 0;
1711   tree_view->priv->cursor_offset = 0;
1712   tree_view->priv->n_columns = 0;
1713   tree_view->priv->header_height = 1;
1714   tree_view->priv->x_drag = 0;
1715   tree_view->priv->drag_pos = -1;
1716   tree_view->priv->header_has_focus = FALSE;
1717   tree_view->priv->pressed_button = -1;
1718   tree_view->priv->press_start_x = -1;
1719   tree_view->priv->press_start_y = -1;
1720   tree_view->priv->reorderable = FALSE;
1721   tree_view->priv->presize_handler_timer = 0;
1722   tree_view->priv->scroll_sync_timer = 0;
1723   tree_view->priv->fixed_height = -1;
1724   tree_view->priv->fixed_height_mode = FALSE;
1725   tree_view->priv->fixed_height_check = 0;
1726   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1727   tree_view->priv->enable_search = TRUE;
1728   tree_view->priv->search_column = -1;
1729   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1730   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1731   tree_view->priv->search_custom_entry_set = FALSE;
1732   tree_view->priv->typeselect_flush_timeout = 0;
1733   tree_view->priv->init_hadjust_value = TRUE;    
1734   tree_view->priv->width = 0;
1735           
1736   tree_view->priv->hover_selection = FALSE;
1737   tree_view->priv->hover_expand = FALSE;
1738
1739   tree_view->priv->level_indentation = 0;
1740
1741   tree_view->priv->rubber_banding_enable = FALSE;
1742
1743   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1744   tree_view->priv->tree_lines_enabled = FALSE;
1745
1746   tree_view->priv->tooltip_column = -1;
1747
1748   tree_view->priv->post_validation_flag = FALSE;
1749
1750   tree_view->priv->last_button_x = -1;
1751   tree_view->priv->last_button_y = -1;
1752
1753   tree_view->priv->event_last_x = -10000;
1754   tree_view->priv->event_last_y = -10000;
1755
1756   gtk_tree_view_set_vadjustment (tree_view, NULL);
1757   gtk_tree_view_set_hadjustment (tree_view, NULL);
1758 }
1759
1760 \f
1761
1762 /* GObject Methods
1763  */
1764
1765 static void
1766 gtk_tree_view_set_property (GObject         *object,
1767                             guint            prop_id,
1768                             const GValue    *value,
1769                             GParamSpec      *pspec)
1770 {
1771   GtkTreeView *tree_view;
1772
1773   tree_view = GTK_TREE_VIEW (object);
1774
1775   switch (prop_id)
1776     {
1777     case PROP_MODEL:
1778       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1779       break;
1780     case PROP_HADJUSTMENT:
1781       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1782       break;
1783     case PROP_VADJUSTMENT:
1784       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1785       break;
1786     case PROP_HSCROLL_POLICY:
1787       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1788       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1789       break;
1790     case PROP_VSCROLL_POLICY:
1791       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1792       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1793       break;
1794     case PROP_HEADERS_VISIBLE:
1795       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1796       break;
1797     case PROP_HEADERS_CLICKABLE:
1798       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1799       break;
1800     case PROP_EXPANDER_COLUMN:
1801       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1802       break;
1803     case PROP_REORDERABLE:
1804       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1805       break;
1806     case PROP_RULES_HINT:
1807       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1808       break;
1809     case PROP_ENABLE_SEARCH:
1810       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1811       break;
1812     case PROP_SEARCH_COLUMN:
1813       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1814       break;
1815     case PROP_FIXED_HEIGHT_MODE:
1816       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1817       break;
1818     case PROP_HOVER_SELECTION:
1819       tree_view->priv->hover_selection = g_value_get_boolean (value);
1820       break;
1821     case PROP_HOVER_EXPAND:
1822       tree_view->priv->hover_expand = g_value_get_boolean (value);
1823       break;
1824     case PROP_SHOW_EXPANDERS:
1825       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1826       break;
1827     case PROP_LEVEL_INDENTATION:
1828       tree_view->priv->level_indentation = g_value_get_int (value);
1829       break;
1830     case PROP_RUBBER_BANDING:
1831       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1832       break;
1833     case PROP_ENABLE_GRID_LINES:
1834       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1835       break;
1836     case PROP_ENABLE_TREE_LINES:
1837       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1838       break;
1839     case PROP_TOOLTIP_COLUMN:
1840       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1841       break;
1842     default:
1843       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1844       break;
1845     }
1846 }
1847
1848 static void
1849 gtk_tree_view_get_property (GObject    *object,
1850                             guint       prop_id,
1851                             GValue     *value,
1852                             GParamSpec *pspec)
1853 {
1854   GtkTreeView *tree_view;
1855
1856   tree_view = GTK_TREE_VIEW (object);
1857
1858   switch (prop_id)
1859     {
1860     case PROP_MODEL:
1861       g_value_set_object (value, tree_view->priv->model);
1862       break;
1863     case PROP_HADJUSTMENT:
1864       g_value_set_object (value, tree_view->priv->hadjustment);
1865       break;
1866     case PROP_VADJUSTMENT:
1867       g_value_set_object (value, tree_view->priv->vadjustment);
1868       break;
1869     case PROP_HSCROLL_POLICY:
1870       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1871       break;
1872     case PROP_VSCROLL_POLICY:
1873       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1874       break;
1875     case PROP_HEADERS_VISIBLE:
1876       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1877       break;
1878     case PROP_HEADERS_CLICKABLE:
1879       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1880       break;
1881     case PROP_EXPANDER_COLUMN:
1882       g_value_set_object (value, tree_view->priv->expander_column);
1883       break;
1884     case PROP_REORDERABLE:
1885       g_value_set_boolean (value, tree_view->priv->reorderable);
1886       break;
1887     case PROP_RULES_HINT:
1888       g_value_set_boolean (value, tree_view->priv->has_rules);
1889       break;
1890     case PROP_ENABLE_SEARCH:
1891       g_value_set_boolean (value, tree_view->priv->enable_search);
1892       break;
1893     case PROP_SEARCH_COLUMN:
1894       g_value_set_int (value, tree_view->priv->search_column);
1895       break;
1896     case PROP_FIXED_HEIGHT_MODE:
1897       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1898       break;
1899     case PROP_HOVER_SELECTION:
1900       g_value_set_boolean (value, tree_view->priv->hover_selection);
1901       break;
1902     case PROP_HOVER_EXPAND:
1903       g_value_set_boolean (value, tree_view->priv->hover_expand);
1904       break;
1905     case PROP_SHOW_EXPANDERS:
1906       g_value_set_boolean (value, tree_view->priv->show_expanders);
1907       break;
1908     case PROP_LEVEL_INDENTATION:
1909       g_value_set_int (value, tree_view->priv->level_indentation);
1910       break;
1911     case PROP_RUBBER_BANDING:
1912       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1913       break;
1914     case PROP_ENABLE_GRID_LINES:
1915       g_value_set_enum (value, tree_view->priv->grid_lines);
1916       break;
1917     case PROP_ENABLE_TREE_LINES:
1918       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1919       break;
1920     case PROP_TOOLTIP_COLUMN:
1921       g_value_set_int (value, tree_view->priv->tooltip_column);
1922       break;
1923     default:
1924       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1925       break;
1926     }
1927 }
1928
1929 static void
1930 gtk_tree_view_finalize (GObject *object)
1931 {
1932   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1933 }
1934
1935
1936 static GtkBuildableIface *parent_buildable_iface;
1937
1938 static void
1939 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1940 {
1941   parent_buildable_iface = g_type_interface_peek_parent (iface);
1942   iface->add_child = gtk_tree_view_buildable_add_child;
1943   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1944 }
1945
1946 static void
1947 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1948                                    GtkBuilder  *builder,
1949                                    GObject     *child,
1950                                    const gchar *type)
1951 {
1952   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1953 }
1954
1955 static GObject *
1956 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1957                                             GtkBuilder        *builder,
1958                                             const gchar       *childname)
1959 {
1960     if (strcmp (childname, "selection") == 0)
1961       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1962     
1963     return parent_buildable_iface->get_internal_child (buildable,
1964                                                        builder,
1965                                                        childname);
1966 }
1967
1968 /* GtkWidget Methods
1969  */
1970
1971 static void
1972 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1973 {
1974   _gtk_rbtree_free (tree_view->priv->tree);
1975   
1976   tree_view->priv->tree = NULL;
1977   tree_view->priv->button_pressed_node = NULL;
1978   tree_view->priv->button_pressed_tree = NULL;
1979   tree_view->priv->prelight_tree = NULL;
1980   tree_view->priv->prelight_node = NULL;
1981   tree_view->priv->expanded_collapsed_node = NULL;
1982   tree_view->priv->expanded_collapsed_tree = NULL;
1983 }
1984
1985 static void
1986 gtk_tree_view_destroy (GtkWidget *widget)
1987 {
1988   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1989   GList *list;
1990
1991   gtk_tree_view_stop_editing (tree_view, TRUE);
1992
1993   if (tree_view->priv->columns != NULL)
1994     {
1995       list = tree_view->priv->columns;
1996       while (list)
1997         {
1998           GtkTreeViewColumn *column;
1999           column = GTK_TREE_VIEW_COLUMN (list->data);
2000           list = list->next;
2001           gtk_tree_view_remove_column (tree_view, column);
2002         }
2003       tree_view->priv->columns = NULL;
2004     }
2005
2006   if (tree_view->priv->tree != NULL)
2007     {
2008       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2009
2010       gtk_tree_view_free_rbtree (tree_view);
2011     }
2012
2013   if (tree_view->priv->selection != NULL)
2014     {
2015       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2016       g_object_unref (tree_view->priv->selection);
2017       tree_view->priv->selection = NULL;
2018     }
2019
2020   if (tree_view->priv->scroll_to_path != NULL)
2021     {
2022       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2023       tree_view->priv->scroll_to_path = NULL;
2024     }
2025
2026   if (tree_view->priv->drag_dest_row != NULL)
2027     {
2028       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2029       tree_view->priv->drag_dest_row = NULL;
2030     }
2031
2032   if (tree_view->priv->top_row != NULL)
2033     {
2034       gtk_tree_row_reference_free (tree_view->priv->top_row);
2035       tree_view->priv->top_row = NULL;
2036     }
2037
2038   if (tree_view->priv->column_drop_func_data &&
2039       tree_view->priv->column_drop_func_data_destroy)
2040     {
2041       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2042       tree_view->priv->column_drop_func_data = NULL;
2043     }
2044
2045   if (tree_view->priv->destroy_count_destroy &&
2046       tree_view->priv->destroy_count_data)
2047     {
2048       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2049       tree_view->priv->destroy_count_data = NULL;
2050     }
2051
2052   gtk_tree_row_reference_free (tree_view->priv->cursor);
2053   tree_view->priv->cursor = NULL;
2054
2055   gtk_tree_row_reference_free (tree_view->priv->anchor);
2056   tree_view->priv->anchor = NULL;
2057
2058   /* destroy interactive search dialog */
2059   if (tree_view->priv->search_window)
2060     {
2061       gtk_widget_destroy (tree_view->priv->search_window);
2062       tree_view->priv->search_window = NULL;
2063       tree_view->priv->search_entry = NULL;
2064       if (tree_view->priv->typeselect_flush_timeout)
2065         {
2066           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2067           tree_view->priv->typeselect_flush_timeout = 0;
2068         }
2069     }
2070
2071   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2072     {
2073       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2074       tree_view->priv->search_user_data = NULL;
2075     }
2076
2077   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2078     {
2079       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2080       tree_view->priv->search_position_user_data = NULL;
2081     }
2082
2083   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2084     {
2085       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2086       tree_view->priv->row_separator_data = NULL;
2087     }
2088   
2089   gtk_tree_view_set_model (tree_view, NULL);
2090
2091   if (tree_view->priv->hadjustment)
2092     {
2093       g_object_unref (tree_view->priv->hadjustment);
2094       tree_view->priv->hadjustment = NULL;
2095     }
2096   if (tree_view->priv->vadjustment)
2097     {
2098       g_object_unref (tree_view->priv->vadjustment);
2099       tree_view->priv->vadjustment = NULL;
2100     }
2101
2102   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2103 }
2104
2105 /* GtkWidget::map helper */
2106 static void
2107 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2108 {
2109   GList *list;
2110
2111   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2112
2113   if (tree_view->priv->headers_visible)
2114     {
2115       GtkTreeViewColumn *column;
2116       GtkWidget         *button;
2117       GdkWindow         *window;
2118
2119       for (list = tree_view->priv->columns; list; list = list->next)
2120         {
2121           column = list->data;
2122           button = gtk_tree_view_column_get_button (column);
2123
2124           if (gtk_tree_view_column_get_visible (column) && button)
2125             gtk_widget_show_now (button);
2126
2127           if (gtk_widget_get_visible (button) &&
2128               !gtk_widget_get_mapped (button))
2129             gtk_widget_map (button);
2130         }
2131       for (list = tree_view->priv->columns; list; list = list->next)
2132         {
2133           column = list->data;
2134           if (gtk_tree_view_column_get_visible (column) == FALSE)
2135             continue;
2136
2137           window = _gtk_tree_view_column_get_window (column);
2138           if (gtk_tree_view_column_get_resizable (column))
2139             {
2140               gdk_window_raise (window);
2141               gdk_window_show (window);
2142             }
2143           else
2144             gdk_window_hide (window);
2145         }
2146       gdk_window_show (tree_view->priv->header_window);
2147     }
2148 }
2149
2150 static void
2151 gtk_tree_view_map (GtkWidget *widget)
2152 {
2153   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2154   GList *tmp_list;
2155
2156   gtk_widget_set_mapped (widget, TRUE);
2157
2158   tmp_list = tree_view->priv->children;
2159   while (tmp_list)
2160     {
2161       GtkTreeViewChild *child = tmp_list->data;
2162       tmp_list = tmp_list->next;
2163
2164       if (gtk_widget_get_visible (child->widget))
2165         {
2166           if (!gtk_widget_get_mapped (child->widget))
2167             gtk_widget_map (child->widget);
2168         }
2169     }
2170   gdk_window_show (tree_view->priv->bin_window);
2171
2172   gtk_tree_view_map_buttons (tree_view);
2173
2174   gdk_window_show (gtk_widget_get_window (widget));
2175 }
2176
2177 static void
2178 gtk_tree_view_realize (GtkWidget *widget)
2179 {
2180   GtkAllocation allocation;
2181   GtkStyleContext *context;
2182   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2183   GdkWindow *window;
2184   GdkWindowAttr attributes;
2185   GList *tmp_list;
2186   gint attributes_mask;
2187
2188   gtk_widget_set_realized (widget, TRUE);
2189
2190   gtk_widget_get_allocation (widget, &allocation);
2191
2192   /* Make the main, clipping window */
2193   attributes.window_type = GDK_WINDOW_CHILD;
2194   attributes.x = allocation.x;
2195   attributes.y = allocation.y;
2196   attributes.width = allocation.width;
2197   attributes.height = allocation.height;
2198   attributes.wclass = GDK_INPUT_OUTPUT;
2199   attributes.visual = gtk_widget_get_visual (widget);
2200   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2201
2202   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2203
2204   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2205                            &attributes, attributes_mask);
2206   gtk_widget_set_window (widget, window);
2207   gdk_window_set_user_data (window, widget);
2208
2209   gtk_widget_get_allocation (widget, &allocation);
2210
2211   /* Make the window for the tree */
2212   attributes.x = 0;
2213   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2214   attributes.width = MAX (tree_view->priv->width, allocation.width);
2215   attributes.height = allocation.height;
2216   attributes.event_mask = (GDK_EXPOSURE_MASK |
2217                            GDK_SCROLL_MASK |
2218                            GDK_POINTER_MOTION_MASK |
2219                            GDK_ENTER_NOTIFY_MASK |
2220                            GDK_LEAVE_NOTIFY_MASK |
2221                            GDK_BUTTON_PRESS_MASK |
2222                            GDK_BUTTON_RELEASE_MASK |
2223                            gtk_widget_get_events (widget));
2224
2225   tree_view->priv->bin_window = gdk_window_new (window,
2226                                                 &attributes, attributes_mask);
2227   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2228
2229   gtk_widget_get_allocation (widget, &allocation);
2230
2231   /* Make the column header window */
2232   attributes.x = 0;
2233   attributes.y = 0;
2234   attributes.width = MAX (tree_view->priv->width, allocation.width);
2235   attributes.height = tree_view->priv->header_height;
2236   attributes.event_mask = (GDK_EXPOSURE_MASK |
2237                            GDK_SCROLL_MASK |
2238                            GDK_ENTER_NOTIFY_MASK |
2239                            GDK_LEAVE_NOTIFY_MASK |
2240                            GDK_BUTTON_PRESS_MASK |
2241                            GDK_BUTTON_RELEASE_MASK |
2242                            GDK_KEY_PRESS_MASK |
2243                            GDK_KEY_RELEASE_MASK |
2244                            gtk_widget_get_events (widget));
2245
2246   tree_view->priv->header_window = gdk_window_new (window,
2247                                                    &attributes, attributes_mask);
2248   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2249
2250   context = gtk_widget_get_style_context (widget);
2251
2252   gtk_style_context_save (context);
2253   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2254   gtk_style_context_set_background (context, tree_view->priv->bin_window);
2255   gtk_style_context_restore (context);
2256
2257   gtk_style_context_set_background (context, tree_view->priv->header_window);
2258
2259   tmp_list = tree_view->priv->children;
2260   while (tmp_list)
2261     {
2262       GtkTreeViewChild *child = tmp_list->data;
2263       tmp_list = tmp_list->next;
2264
2265       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2266     }
2267
2268   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2269     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2270
2271   /* Need to call those here, since they create GCs */
2272   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2273   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2274
2275   install_presize_handler (tree_view); 
2276 }
2277
2278 static void
2279 gtk_tree_view_unrealize (GtkWidget *widget)
2280 {
2281   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2282   GtkTreeViewPrivate *priv = tree_view->priv;
2283   GtkStyleContext *context;
2284   GList *list;
2285
2286   if (priv->scroll_timeout != 0)
2287     {
2288       g_source_remove (priv->scroll_timeout);
2289       priv->scroll_timeout = 0;
2290     }
2291
2292   if (priv->auto_expand_timeout != 0)
2293     {
2294       g_source_remove (priv->auto_expand_timeout);
2295       priv->auto_expand_timeout = 0;
2296     }
2297
2298   if (priv->open_dest_timeout != 0)
2299     {
2300       g_source_remove (priv->open_dest_timeout);
2301       priv->open_dest_timeout = 0;
2302     }
2303
2304   context = gtk_widget_get_style_context (widget);
2305   gtk_style_context_cancel_animations (context, NULL);
2306
2307   if (priv->presize_handler_timer != 0)
2308     {
2309       g_source_remove (priv->presize_handler_timer);
2310       priv->presize_handler_timer = 0;
2311     }
2312
2313   if (priv->validate_rows_timer != 0)
2314     {
2315       g_source_remove (priv->validate_rows_timer);
2316       priv->validate_rows_timer = 0;
2317     }
2318
2319   if (priv->scroll_sync_timer != 0)
2320     {
2321       g_source_remove (priv->scroll_sync_timer);
2322       priv->scroll_sync_timer = 0;
2323     }
2324
2325   if (priv->typeselect_flush_timeout)
2326     {
2327       g_source_remove (priv->typeselect_flush_timeout);
2328       priv->typeselect_flush_timeout = 0;
2329     }
2330   
2331   for (list = priv->columns; list; list = list->next)
2332     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2333
2334   gdk_window_set_user_data (priv->bin_window, NULL);
2335   gdk_window_destroy (priv->bin_window);
2336   priv->bin_window = NULL;
2337
2338   gdk_window_set_user_data (priv->header_window, NULL);
2339   gdk_window_destroy (priv->header_window);
2340   priv->header_window = NULL;
2341
2342   if (priv->drag_window)
2343     {
2344       gdk_window_set_user_data (priv->drag_window, NULL);
2345       gdk_window_destroy (priv->drag_window);
2346       priv->drag_window = NULL;
2347     }
2348
2349   if (priv->drag_highlight_window)
2350     {
2351       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2352       gdk_window_destroy (priv->drag_highlight_window);
2353       priv->drag_highlight_window = NULL;
2354     }
2355
2356   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2357 }
2358
2359 /* GtkWidget::size_request helper */
2360 static void
2361 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2362 {
2363   GList *list;
2364
2365   tree_view->priv->header_height = 0;
2366
2367   for (list = tree_view->priv->columns; list; list = list->next)
2368     {
2369       GtkRequisition     requisition;
2370       GtkTreeViewColumn *column = list->data;
2371       GtkWidget         *button = gtk_tree_view_column_get_button (column);
2372
2373       if (button == NULL)
2374         continue;
2375
2376       gtk_widget_get_preferred_size (button, &requisition, NULL);
2377       tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2378     }
2379 }
2380
2381
2382 /* Called only by ::size_request */
2383 static void
2384 gtk_tree_view_update_size (GtkTreeView *tree_view)
2385 {
2386   GList *list;
2387   GtkTreeViewColumn *column;
2388   gint i;
2389
2390   if (tree_view->priv->model == NULL)
2391     {
2392       tree_view->priv->width = 0;
2393       tree_view->priv->prev_width = 0;                   
2394       tree_view->priv->height = 0;
2395       return;
2396     }
2397
2398   tree_view->priv->prev_width = tree_view->priv->width;  
2399   tree_view->priv->width = 0;
2400
2401   /* keep this in sync with size_allocate below */
2402   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2403     {
2404       column = list->data;
2405       if (!gtk_tree_view_column_get_visible (column))
2406         continue;
2407
2408       tree_view->priv->width += _gtk_tree_view_column_request_width (column);
2409     }
2410
2411   if (tree_view->priv->tree == NULL)
2412     tree_view->priv->height = 0;
2413   else
2414     tree_view->priv->height = tree_view->priv->tree->root->offset;
2415 }
2416
2417 static void
2418 gtk_tree_view_size_request (GtkWidget      *widget,
2419                             GtkRequisition *requisition,
2420                             gboolean        may_validate)
2421 {
2422   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2423
2424   if (may_validate)
2425     {
2426       /* we validate some rows initially just to make sure we have some size.
2427        * In practice, with a lot of static lists, this should get a good width.
2428        */
2429       do_validate_rows (tree_view, FALSE);
2430     }
2431
2432   gtk_tree_view_size_request_columns (tree_view);
2433   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2434
2435   requisition->width = tree_view->priv->width;
2436   requisition->height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2437 }
2438
2439 static void
2440 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2441                                    gint      *minimum,
2442                                    gint      *natural)
2443 {
2444   GtkRequisition requisition;
2445
2446   gtk_tree_view_size_request (widget, &requisition, TRUE);
2447
2448   *minimum = *natural = requisition.width;
2449 }
2450
2451 static void
2452 gtk_tree_view_get_preferred_height (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.height;
2461 }
2462
2463 static int
2464 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2465 {
2466   int width = 0;
2467   GList *list;
2468   gboolean rtl;
2469
2470   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2471   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2472        list->data != tree_view->priv->expander_column;
2473        list = (rtl ? list->prev : list->next))
2474     {
2475       GtkTreeViewColumn *column = list->data;
2476
2477       width += gtk_tree_view_column_get_width (column);
2478     }
2479
2480   return width;
2481 }
2482
2483 /* GtkWidget::size_allocate helper */
2484 static void
2485 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2486                                      gboolean  *width_changed)
2487 {
2488   GtkTreeView *tree_view;
2489   GList *list, *first_column, *last_column;
2490   GtkTreeViewColumn *column;
2491   GtkAllocation widget_allocation;
2492   gint width = 0;
2493   gint extra, extra_per_column, extra_for_last;
2494   gint full_requested_width = 0;
2495   gint number_of_expand_columns = 0;
2496   gboolean rtl;
2497   gboolean update_expand;
2498   
2499   tree_view = GTK_TREE_VIEW (widget);
2500
2501   for (last_column = g_list_last (tree_view->priv->columns);
2502        last_column &&
2503        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2504        last_column = last_column->prev)
2505     ;
2506   if (last_column == NULL)
2507     return;
2508
2509   for (first_column = g_list_first (tree_view->priv->columns);
2510        first_column &&
2511        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2512        first_column = first_column->next)
2513     ;
2514
2515   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2516
2517   /* find out how many extra space and expandable columns we have */
2518   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2519     {
2520       column = (GtkTreeViewColumn *)list->data;
2521
2522       if (!gtk_tree_view_column_get_visible (column))
2523         continue;
2524
2525       full_requested_width += _gtk_tree_view_column_request_width (column);
2526
2527       if (gtk_tree_view_column_get_expand (column))
2528         number_of_expand_columns++;
2529     }
2530
2531   /* Only update the expand value if the width of the widget has changed,
2532    * or the number of expand columns has changed, or if there are no expand
2533    * columns, or if we didn't have an size-allocation yet after the
2534    * last validated node.
2535    */
2536   update_expand = (width_changed && *width_changed == TRUE)
2537       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2538       || number_of_expand_columns == 0
2539       || tree_view->priv->post_validation_flag == TRUE;
2540
2541   tree_view->priv->post_validation_flag = FALSE;
2542
2543   gtk_widget_get_allocation (widget, &widget_allocation);
2544   if (!update_expand)
2545     {
2546       extra = tree_view->priv->last_extra_space;
2547       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2548     }
2549   else
2550     {
2551       extra = MAX (widget_allocation.width - full_requested_width, 0);
2552       extra_for_last = 0;
2553
2554       tree_view->priv->last_extra_space = extra;
2555     }
2556
2557   if (number_of_expand_columns > 0)
2558     extra_per_column = extra/number_of_expand_columns;
2559   else
2560     extra_per_column = 0;
2561
2562   if (update_expand)
2563     {
2564       tree_view->priv->last_extra_space_per_column = extra_per_column;
2565       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2566     }
2567
2568   for (list = (rtl ? last_column : first_column); 
2569        list != (rtl ? first_column->prev : last_column->next);
2570        list = (rtl ? list->prev : list->next)) 
2571     {
2572       gint column_width;
2573
2574       column = list->data;
2575
2576       if (!gtk_tree_view_column_get_visible (column))
2577         continue;
2578
2579       /* We need to handle the dragged button specially.
2580        */
2581       if (column == tree_view->priv->drag_column)
2582         {
2583           GtkAllocation drag_allocation;
2584           GtkWidget    *button;
2585
2586           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2587
2588           drag_allocation.x = 0;
2589           drag_allocation.y = 0;
2590           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2591           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2592           gtk_widget_size_allocate (button, &drag_allocation);
2593           width += drag_allocation.width;
2594           continue;
2595         }
2596
2597       column_width = _gtk_tree_view_column_request_width (column);
2598
2599       if (gtk_tree_view_column_get_expand (column))
2600         {
2601           if (number_of_expand_columns == 1)
2602             {
2603               /* We add the remander to the last column as
2604                * */
2605               column_width += extra;
2606             }
2607           else
2608             {
2609               column_width += extra_per_column;
2610               extra -= extra_per_column;
2611               number_of_expand_columns --;
2612             }
2613         }
2614       else if (number_of_expand_columns == 0 &&
2615                list == last_column)
2616         {
2617           column_width += extra;
2618         }
2619
2620       /* In addition to expand, the last column can get even more
2621        * extra space so all available space is filled up.
2622        */
2623       if (extra_for_last > 0 && list == last_column)
2624         column_width += extra_for_last;
2625
2626       _gtk_tree_view_column_allocate (column, width, column_width);
2627
2628       width += column_width;
2629     }
2630
2631   /* We change the width here.  The user might have been resizing columns,
2632    * which changes the total width of the tree view.  This is of
2633    * importance for getting the horizontal scroll bar right.
2634    */
2635   if (tree_view->priv->width != width)
2636     {
2637       tree_view->priv->width = width;
2638       if (width_changed)
2639         *width_changed = TRUE;
2640     }
2641 }
2642
2643
2644 static void
2645 gtk_tree_view_size_allocate (GtkWidget     *widget,
2646                              GtkAllocation *allocation)
2647 {
2648   GtkAllocation widget_allocation;
2649   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2650   GList *tmp_list;
2651   gboolean width_changed = FALSE;
2652   gint old_width;
2653
2654   gtk_widget_get_allocation (widget, &widget_allocation);
2655   old_width = widget_allocation.width;
2656   if (allocation->width != widget_allocation.width)
2657     width_changed = TRUE;
2658
2659   gtk_widget_set_allocation (widget, allocation);
2660
2661   tmp_list = tree_view->priv->children;
2662
2663   while (tmp_list)
2664     {
2665       GtkAllocation allocation;
2666
2667       GtkTreeViewChild *child = tmp_list->data;
2668       tmp_list = tmp_list->next;
2669
2670       /* totally ignore our child's requisition */
2671       allocation.x = child->x;
2672       allocation.y = child->y;
2673       allocation.width = child->width;
2674       allocation.height = child->height;
2675       gtk_widget_size_allocate (child->widget, &allocation);
2676     }
2677
2678   /* We size-allocate the columns first because the width of the
2679    * tree view (used in updating the adjustments below) might change.
2680    */
2681   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2682
2683   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2684   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2685                                 allocation->width);
2686   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2687                                      allocation->width * 0.9);
2688   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2689                                      allocation->width * 0.1);
2690   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2691   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2692                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2693                                  tree_view->priv->width));
2694   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2695
2696   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2697     {
2698       if (allocation->width < tree_view->priv->width)
2699         {
2700           if (tree_view->priv->init_hadjust_value)
2701             {
2702               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2703                                         MAX (tree_view->priv->width -
2704                                              allocation->width, 0));
2705               tree_view->priv->init_hadjust_value = FALSE;
2706             }
2707           else if (allocation->width != old_width)
2708             {
2709               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2710                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2711                                                0,
2712                                                tree_view->priv->width - allocation->width));
2713             }
2714           else
2715             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2716                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)),
2717                                              0,
2718                                              tree_view->priv->width - allocation->width));
2719         }
2720       else
2721         {
2722           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2723           tree_view->priv->init_hadjust_value = TRUE;
2724         }
2725     }
2726   else
2727     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2728       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2729                                 MAX (tree_view->priv->width -
2730                                      allocation->width, 0));
2731
2732   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2733   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2734                                 allocation->height -
2735                                 gtk_tree_view_get_effective_header_height (tree_view));
2736   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2737                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2738   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2739                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2740   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2741   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2742                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2743                                  tree_view->priv->height));
2744   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2745
2746   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2747   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2748     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2749   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2750     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2751                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2752   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2753     gtk_tree_view_top_row_to_dy (tree_view);
2754   else
2755     gtk_tree_view_dy_to_top_row (tree_view);
2756   
2757   if (gtk_widget_get_realized (widget))
2758     {
2759       gdk_window_move_resize (gtk_widget_get_window (widget),
2760                               allocation->x, allocation->y,
2761                               allocation->width, allocation->height);
2762       gdk_window_move_resize (tree_view->priv->header_window,
2763                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2764                               0,
2765                               MAX (tree_view->priv->width, allocation->width),
2766                               tree_view->priv->header_height);
2767       gdk_window_move_resize (tree_view->priv->bin_window,
2768                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2769                               gtk_tree_view_get_effective_header_height (tree_view),
2770                               MAX (tree_view->priv->width, allocation->width),
2771                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2772
2773       if (tree_view->priv->tree == NULL)
2774         invalidate_empty_focus (tree_view);
2775
2776       if (width_changed && tree_view->priv->expander_column)
2777         {
2778           /* Might seem awkward, but is the best heuristic I could come up
2779            * with.  Only if the width of the columns before the expander
2780            * changes, we will update the prelight status.  It is this
2781            * width that makes the expander move vertically.  Always updating
2782            * prelight status causes trouble with hover selections.
2783            */
2784           gint width_before_expander;
2785
2786           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2787
2788           if (tree_view->priv->prev_width_before_expander
2789               != width_before_expander)
2790               update_prelight (tree_view,
2791                                tree_view->priv->event_last_x,
2792                                tree_view->priv->event_last_y);
2793
2794           tree_view->priv->prev_width_before_expander = width_before_expander;
2795         }
2796     }
2797 }
2798
2799 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2800 static void
2801 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2802 {
2803   GtkWidget *widget = GTK_WIDGET (tree_view);
2804
2805   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2806     gtk_widget_grab_focus (widget);
2807   tree_view->priv->draw_keyfocus = 0;
2808 }
2809
2810 static inline gboolean
2811 row_is_separator (GtkTreeView *tree_view,
2812                   GtkTreeIter *iter,
2813                   GtkTreePath *path)
2814 {
2815   gboolean is_separator = FALSE;
2816
2817   if (tree_view->priv->row_separator_func)
2818     {
2819       GtkTreeIter tmpiter;
2820
2821       if (iter)
2822         tmpiter = *iter;
2823       else
2824         {
2825           if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
2826             return FALSE;
2827         }
2828
2829       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2830                                                           &tmpiter,
2831                                                           tree_view->priv->row_separator_data);
2832     }
2833
2834   return is_separator;
2835 }
2836
2837 static gboolean
2838 gtk_tree_view_button_press (GtkWidget      *widget,
2839                             GdkEventButton *event)
2840 {
2841   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2842   GList *list;
2843   GtkTreeViewColumn *column = NULL;
2844   gint i;
2845   GdkRectangle background_area;
2846   GdkRectangle cell_area;
2847   gint vertical_separator;
2848   gint horizontal_separator;
2849   gboolean path_is_selectable;
2850   gboolean rtl;
2851
2852   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2853   gtk_tree_view_stop_editing (tree_view, FALSE);
2854   gtk_widget_style_get (widget,
2855                         "vertical-separator", &vertical_separator,
2856                         "horizontal-separator", &horizontal_separator,
2857                         NULL);
2858
2859   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2860    * we're done handling the button press.
2861    */
2862
2863   if (event->window == tree_view->priv->bin_window)
2864     {
2865       GtkRBNode *node;
2866       GtkRBTree *tree;
2867       GtkTreePath *path;
2868       gint depth;
2869       gint new_y;
2870       gint y_offset;
2871       gint dval;
2872       gint pre_val, aft_val;
2873       GtkTreeViewColumn *column = NULL;
2874       gint column_handled_click = FALSE;
2875       gboolean row_double_click = FALSE;
2876       gboolean rtl;
2877       gboolean node_selected;
2878       GdkModifierType extend_mod_mask;
2879       GdkModifierType modify_mod_mask;
2880
2881       /* Empty tree? */
2882       if (tree_view->priv->tree == NULL)
2883         {
2884           grab_focus_and_unset_draw_keyfocus (tree_view);
2885           return TRUE;
2886         }
2887
2888       /* are we in an arrow? */
2889       if (tree_view->priv->prelight_node &&
2890           tree_view->priv->arrow_prelit &&
2891           gtk_tree_view_draw_expanders (tree_view))
2892         {
2893           if (event->button == 1)
2894             {
2895               gtk_grab_add (widget);
2896               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2897               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2898               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2899                                               tree_view->priv->prelight_tree,
2900                                               tree_view->priv->prelight_node);
2901             }
2902
2903           grab_focus_and_unset_draw_keyfocus (tree_view);
2904           return TRUE;
2905         }
2906
2907       /* find the node that was clicked */
2908       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2909       if (new_y < 0)
2910         new_y = 0;
2911       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2912
2913       if (node == NULL)
2914         {
2915           /* We clicked in dead space */
2916           grab_focus_and_unset_draw_keyfocus (tree_view);
2917           return TRUE;
2918         }
2919
2920       /* Get the path and the node */
2921       path = _gtk_tree_view_find_path (tree_view, tree, node);
2922       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2923
2924       if (!path_is_selectable)
2925         {
2926           gtk_tree_path_free (path);
2927           grab_focus_and_unset_draw_keyfocus (tree_view);
2928           return TRUE;
2929         }
2930
2931       depth = gtk_tree_path_get_depth (path);
2932       background_area.y = y_offset + event->y;
2933       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
2934       background_area.x = 0;
2935
2936
2937       /* Let the column have a chance at selecting it. */
2938       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2939       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2940            list; list = (rtl ? list->prev : list->next))
2941         {
2942           GtkTreeViewColumn *candidate = list->data;
2943
2944           if (!gtk_tree_view_column_get_visible (candidate))
2945             continue;
2946
2947           background_area.width = gtk_tree_view_column_get_width (candidate);
2948           if ((background_area.x > (gint) event->x) ||
2949               (background_area.x + background_area.width <= (gint) event->x))
2950             {
2951               background_area.x += background_area.width;
2952               continue;
2953             }
2954
2955           /* we found the focus column */
2956           column = candidate;
2957           cell_area = background_area;
2958           cell_area.width -= horizontal_separator;
2959           cell_area.height -= vertical_separator;
2960           cell_area.x += horizontal_separator/2;
2961           cell_area.y += vertical_separator/2;
2962           if (gtk_tree_view_is_expander_column (tree_view, column))
2963             {
2964               if (!rtl)
2965                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2966               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2967
2968               if (gtk_tree_view_draw_expanders (tree_view))
2969                 {
2970                   if (!rtl)
2971                     cell_area.x += depth * tree_view->priv->expander_size;
2972                   cell_area.width -= depth * tree_view->priv->expander_size;
2973                 }
2974             }
2975           break;
2976         }
2977
2978       if (column == NULL)
2979         {
2980           gtk_tree_path_free (path);
2981           grab_focus_and_unset_draw_keyfocus (tree_view);
2982           return FALSE;
2983         }
2984
2985       tree_view->priv->focus_column = column;
2986
2987       /* decide if we edit */
2988       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2989           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2990         {
2991           GtkTreePath *anchor;
2992           GtkTreeIter iter;
2993
2994           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2995           gtk_tree_view_column_cell_set_cell_data (column,
2996                                                    tree_view->priv->model,
2997                                                    &iter,
2998                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2999                                                    node->children?TRUE:FALSE);
3000
3001           if (tree_view->priv->anchor)
3002             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3003           else
3004             anchor = NULL;
3005
3006           if ((anchor && !gtk_tree_path_compare (anchor, path))
3007               || !_gtk_tree_view_column_has_editable_cell (column))
3008             {
3009               GtkCellEditable *cell_editable = NULL;
3010
3011               /* FIXME: get the right flags */
3012               guint flags = 0;
3013
3014               if (_gtk_tree_view_column_cell_event (column,
3015                                                     (GdkEvent *)event,
3016                                                     &cell_area, flags))
3017                 {
3018                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3019                   cell_editable = gtk_cell_area_get_edit_widget (area);
3020
3021                   if (cell_editable != NULL)
3022                     {
3023                       gtk_tree_path_free (path);
3024                       gtk_tree_path_free (anchor);
3025                       return TRUE;
3026                     }
3027                   column_handled_click = TRUE;
3028                 }
3029             }
3030           if (anchor)
3031             gtk_tree_path_free (anchor);
3032         }
3033
3034       extend_mod_mask =
3035         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
3036
3037       modify_mod_mask =
3038         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
3039
3040       /* select */
3041       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3042       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3043
3044       /* we only handle selection modifications on the first button press
3045        */
3046       if (event->type == GDK_BUTTON_PRESS)
3047         {
3048           GtkCellRenderer *focus_cell;
3049
3050           if ((event->state & modify_mod_mask) == modify_mod_mask)
3051             tree_view->priv->modify_selection_pressed = TRUE;
3052           if ((event->state & extend_mod_mask) == extend_mod_mask)
3053             tree_view->priv->extend_selection_pressed = TRUE;
3054
3055           /* We update the focus cell here, this is also needed if the
3056            * column does not contain an editable cell.  In this case,
3057            * GtkCellArea did not receive the event for processing (and
3058            * could not update the focus cell).
3059            */
3060           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3061                                                               &cell_area,
3062                                                               &background_area,
3063                                                               event->x,
3064                                                               event->y);
3065
3066           if (focus_cell)
3067             gtk_tree_view_column_focus_cell (column, focus_cell);
3068
3069           if (event->state & modify_mod_mask)
3070             {
3071               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3072               gtk_tree_view_real_toggle_cursor_row (tree_view);
3073             }
3074           else if (event->state & extend_mod_mask)
3075             {
3076               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3077               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3078             }
3079           else
3080             {
3081               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
3082             }
3083
3084           tree_view->priv->modify_selection_pressed = FALSE;
3085           tree_view->priv->extend_selection_pressed = FALSE;
3086         }
3087
3088       /* the treeview may have been scrolled because of _set_cursor,
3089        * correct here
3090        */
3091
3092       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3093       dval = pre_val - aft_val;
3094
3095       cell_area.y += dval;
3096       background_area.y += dval;
3097
3098       /* Save press to possibly begin a drag
3099        */
3100       if (!column_handled_click &&
3101           !tree_view->priv->in_grab &&
3102           tree_view->priv->pressed_button < 0)
3103         {
3104           tree_view->priv->pressed_button = event->button;
3105           tree_view->priv->press_start_x = event->x;
3106           tree_view->priv->press_start_y = event->y;
3107
3108           if (tree_view->priv->rubber_banding_enable
3109               && !node_selected
3110               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3111             {
3112               tree_view->priv->press_start_y += tree_view->priv->dy;
3113               tree_view->priv->rubber_band_x = event->x;
3114               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3115               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3116
3117               if ((event->state & modify_mod_mask) == modify_mod_mask)
3118                 tree_view->priv->rubber_band_modify = TRUE;
3119               if ((event->state & extend_mod_mask) == extend_mod_mask)
3120                 tree_view->priv->rubber_band_extend = TRUE;
3121             }
3122         }
3123
3124       /* Test if a double click happened on the same row. */
3125       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
3126         {
3127           int double_click_time, double_click_distance;
3128
3129           g_object_get (gtk_settings_get_default (),
3130                         "gtk-double-click-time", &double_click_time,
3131                         "gtk-double-click-distance", &double_click_distance,
3132                         NULL);
3133
3134           /* Same conditions as _gdk_event_button_generate */
3135           if (tree_view->priv->last_button_x != -1 &&
3136               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3137               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3138               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3139             {
3140               /* We do no longer compare paths of this row and the
3141                * row clicked previously.  We use the double click
3142                * distance to decide whether this is a valid click,
3143                * allowing the mouse to slightly move over another row.
3144                */
3145               row_double_click = TRUE;
3146
3147               tree_view->priv->last_button_time = 0;
3148               tree_view->priv->last_button_x = -1;
3149               tree_view->priv->last_button_y = -1;
3150             }
3151           else
3152             {
3153               tree_view->priv->last_button_time = event->time;
3154               tree_view->priv->last_button_x = event->x;
3155               tree_view->priv->last_button_y = event->y;
3156             }
3157         }
3158
3159       if (row_double_click)
3160         {
3161           gtk_grab_remove (widget);
3162           gtk_tree_view_row_activated (tree_view, path, column);
3163
3164           if (tree_view->priv->pressed_button == event->button)
3165             tree_view->priv->pressed_button = -1;
3166         }
3167
3168       gtk_tree_path_free (path);
3169
3170       /* If we activated the row through a double click we don't want to grab
3171        * focus back, as moving focus to another widget is pretty common.
3172        */
3173       if (!row_double_click)
3174         grab_focus_and_unset_draw_keyfocus (tree_view);
3175
3176       return TRUE;
3177     }
3178
3179   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3180    */
3181   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3182     {
3183       column = list->data;
3184       if (event->window == _gtk_tree_view_column_get_window (column) &&
3185           gtk_tree_view_column_get_resizable (column) &&
3186           _gtk_tree_view_column_get_window (column))
3187         {
3188           gpointer drag_data;
3189
3190           if (event->type == GDK_2BUTTON_PRESS &&
3191               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3192             {
3193               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3194               _gtk_tree_view_column_autosize (tree_view, column);
3195               return TRUE;
3196             }
3197
3198           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3199                                _gtk_tree_view_column_get_window (column),
3200                                GDK_OWNERSHIP_NONE,
3201                                FALSE,
3202                                GDK_POINTER_MOTION_HINT_MASK
3203                                 | GDK_BUTTON1_MOTION_MASK
3204                                 | GDK_BUTTON_RELEASE_MASK,
3205                                NULL,
3206                                event->time) != GDK_GRAB_SUCCESS)
3207             return FALSE;
3208
3209           gtk_grab_add (widget);
3210           tree_view->priv->in_column_resize = TRUE;
3211
3212           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3213                                                    tree_view->priv->last_extra_space_per_column);
3214
3215           /* block attached dnd signal handler */
3216           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3217           if (drag_data)
3218             g_signal_handlers_block_matched (widget,
3219                                              G_SIGNAL_MATCH_DATA,
3220                                              0, 0, NULL, NULL,
3221                                              drag_data);
3222
3223           tree_view->priv->drag_pos = i;
3224           tree_view->priv->x_drag = gtk_tree_view_column_get_x_offset (column) + (rtl ? 0 : gtk_tree_view_column_get_width (column));
3225
3226           if (!gtk_widget_has_focus (widget))
3227             gtk_widget_grab_focus (widget);
3228
3229           return TRUE;
3230         }
3231     }
3232   return FALSE;
3233 }
3234
3235 /* GtkWidget::button_release_event helper */
3236 static gboolean
3237 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3238                                           GdkEventButton *event)
3239 {
3240   GtkTreeView *tree_view;
3241   GtkWidget *button;
3242   GList *l;
3243   gboolean rtl;
3244   GdkDevice *device, *other;
3245
3246   tree_view = GTK_TREE_VIEW (widget);
3247
3248   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3249   device = gdk_event_get_device ((GdkEvent*)event);
3250   other = gdk_device_get_associated_device (device);
3251   gdk_device_ungrab (device, event->time);
3252   gdk_device_ungrab (other, event->time);
3253
3254   /* Move the button back */
3255   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3256   g_object_ref (button);
3257   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3258   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3259   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3260   g_object_unref (button);
3261   gtk_widget_queue_resize (widget);
3262   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3263     {
3264       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3265       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3266     }
3267   else
3268     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3269
3270   gtk_widget_grab_focus (button);
3271
3272   if (rtl)
3273     {
3274       if (tree_view->priv->cur_reorder &&
3275           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3276         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3277                                          tree_view->priv->cur_reorder->right_column);
3278     }
3279   else
3280     {
3281       if (tree_view->priv->cur_reorder &&
3282           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3283         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3284                                          tree_view->priv->cur_reorder->left_column);
3285     }
3286   tree_view->priv->drag_column = NULL;
3287   gdk_window_hide (tree_view->priv->drag_window);
3288
3289   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3290     g_slice_free (GtkTreeViewColumnReorder, l->data);
3291   g_list_free (tree_view->priv->column_drag_info);
3292   tree_view->priv->column_drag_info = NULL;
3293   tree_view->priv->cur_reorder = NULL;
3294
3295   if (tree_view->priv->drag_highlight_window)
3296     gdk_window_hide (tree_view->priv->drag_highlight_window);
3297
3298   /* Reset our flags */
3299   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3300   tree_view->priv->in_column_drag = FALSE;
3301
3302   return TRUE;
3303 }
3304
3305 /* GtkWidget::button_release_event helper */
3306 static gboolean
3307 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3308                                             GdkEventButton *event)
3309 {
3310   GtkTreeView *tree_view;
3311   gpointer drag_data;
3312
3313   tree_view = GTK_TREE_VIEW (widget);
3314
3315   tree_view->priv->drag_pos = -1;
3316
3317   /* unblock attached dnd signal handler */
3318   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3319   if (drag_data)
3320     g_signal_handlers_unblock_matched (widget,
3321                                        G_SIGNAL_MATCH_DATA,
3322                                        0, 0, NULL, NULL,
3323                                        drag_data);
3324
3325   tree_view->priv->in_column_resize = FALSE;
3326   gtk_grab_remove (widget);
3327   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3328   return TRUE;
3329 }
3330
3331 static gboolean
3332 gtk_tree_view_button_release (GtkWidget      *widget,
3333                               GdkEventButton *event)
3334 {
3335   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3336
3337   if (tree_view->priv->in_column_drag)
3338     return gtk_tree_view_button_release_drag_column (widget, event);
3339
3340   if (tree_view->priv->rubber_band_status)
3341     gtk_tree_view_stop_rubber_band (tree_view);
3342
3343   if (tree_view->priv->pressed_button == event->button)
3344     tree_view->priv->pressed_button = -1;
3345
3346   if (tree_view->priv->in_column_resize)
3347     return gtk_tree_view_button_release_column_resize (widget, event);
3348
3349   if (tree_view->priv->button_pressed_node == NULL)
3350     return FALSE;
3351
3352   if (event->button == 1)
3353     {
3354       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3355           tree_view->priv->arrow_prelit)
3356         {
3357           GtkTreePath *path = NULL;
3358
3359           path = _gtk_tree_view_find_path (tree_view,
3360                                            tree_view->priv->button_pressed_tree,
3361                                            tree_view->priv->button_pressed_node);
3362           /* Actually activate the node */
3363           if (tree_view->priv->button_pressed_node->children == NULL)
3364             gtk_tree_view_real_expand_row (tree_view, path,
3365                                            tree_view->priv->button_pressed_tree,
3366                                            tree_view->priv->button_pressed_node,
3367                                            FALSE, TRUE);
3368           else
3369             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3370                                              tree_view->priv->button_pressed_tree,
3371                                              tree_view->priv->button_pressed_node, TRUE);
3372           gtk_tree_path_free (path);
3373         }
3374
3375       gtk_grab_remove (widget);
3376       tree_view->priv->button_pressed_tree = NULL;
3377       tree_view->priv->button_pressed_node = NULL;
3378     }
3379
3380   return TRUE;
3381 }
3382
3383 static gboolean
3384 gtk_tree_view_grab_broken (GtkWidget          *widget,
3385                            GdkEventGrabBroken *event)
3386 {
3387   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3388
3389   if (tree_view->priv->in_column_drag)
3390     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3391
3392   if (tree_view->priv->in_column_resize)
3393     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3394
3395   return TRUE;
3396 }
3397
3398 #if 0
3399 static gboolean
3400 gtk_tree_view_configure (GtkWidget *widget,
3401                          GdkEventConfigure *event)
3402 {
3403   GtkTreeView *tree_view;
3404
3405   tree_view = GTK_TREE_VIEW (widget);
3406   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3407
3408   return FALSE;
3409 }
3410 #endif
3411
3412 /* GtkWidget::motion_event function set.
3413  */
3414
3415 static gboolean
3416 coords_are_over_arrow (GtkTreeView *tree_view,
3417                        GtkRBTree   *tree,
3418                        GtkRBNode   *node,
3419                        /* these are in bin window coords */
3420                        gint         x,
3421                        gint         y)
3422 {
3423   GdkRectangle arrow;
3424   gint x2;
3425
3426   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3427     return FALSE;
3428
3429   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3430     return FALSE;
3431
3432   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3433   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3434
3435   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3436
3437   arrow.width = x2 - arrow.x;
3438
3439   return (x >= arrow.x &&
3440           x < (arrow.x + arrow.width) &&
3441           y >= arrow.y &&
3442           y < (arrow.y + arrow.height));
3443 }
3444
3445 static gboolean
3446 auto_expand_timeout (gpointer data)
3447 {
3448   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3449   GtkTreePath *path;
3450
3451   if (tree_view->priv->prelight_node)
3452     {
3453       path = _gtk_tree_view_find_path (tree_view,
3454                                        tree_view->priv->prelight_tree,
3455                                        tree_view->priv->prelight_node);   
3456
3457       if (tree_view->priv->prelight_node->children)
3458         gtk_tree_view_collapse_row (tree_view, path);
3459       else
3460         gtk_tree_view_expand_row (tree_view, path, FALSE);
3461
3462       gtk_tree_path_free (path);
3463     }
3464
3465   tree_view->priv->auto_expand_timeout = 0;
3466
3467   return FALSE;
3468 }
3469
3470 static void
3471 remove_auto_expand_timeout (GtkTreeView *tree_view)
3472 {
3473   if (tree_view->priv->auto_expand_timeout != 0)
3474     {
3475       g_source_remove (tree_view->priv->auto_expand_timeout);
3476       tree_view->priv->auto_expand_timeout = 0;
3477     }
3478 }
3479
3480 static void
3481 do_prelight (GtkTreeView *tree_view,
3482              GtkRBTree   *tree,
3483              GtkRBNode   *node,
3484              /* these are in bin_window coords */
3485              gint         x,
3486              gint         y)
3487 {
3488   if (tree_view->priv->prelight_tree == tree &&
3489       tree_view->priv->prelight_node == node)
3490     {
3491       /*  We are still on the same node,
3492           but we might need to take care of the arrow  */
3493
3494       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3495         {
3496           gboolean over_arrow;
3497
3498           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3499
3500           if (over_arrow != tree_view->priv->arrow_prelit)
3501             {
3502               if (over_arrow)
3503                 tree_view->priv->arrow_prelit = TRUE;
3504               else
3505                 tree_view->priv->arrow_prelit = FALSE;
3506
3507               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3508             }
3509         }
3510
3511       return;
3512     }
3513
3514   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3515     {
3516       /*  Unprelight the old node and arrow  */
3517
3518       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3519                              GTK_RBNODE_IS_PRELIT);
3520
3521       if (tree_view->priv->arrow_prelit
3522           && gtk_tree_view_draw_expanders (tree_view))
3523         {
3524           tree_view->priv->arrow_prelit = FALSE;
3525           
3526           gtk_tree_view_queue_draw_arrow (tree_view,
3527                                           tree_view->priv->prelight_tree,
3528                                           tree_view->priv->prelight_node);
3529         }
3530
3531       _gtk_tree_view_queue_draw_node (tree_view,
3532                                       tree_view->priv->prelight_tree,
3533                                       tree_view->priv->prelight_node,
3534                                       NULL);
3535     }
3536
3537
3538   if (tree_view->priv->hover_expand)
3539     remove_auto_expand_timeout (tree_view);
3540
3541   /*  Set the new prelight values  */
3542   tree_view->priv->prelight_node = node;
3543   tree_view->priv->prelight_tree = tree;
3544
3545   if (!node || !tree)
3546     return;
3547
3548   /*  Prelight the new node and arrow  */
3549
3550   if (gtk_tree_view_draw_expanders (tree_view)
3551       && coords_are_over_arrow (tree_view, tree, node, x, y))
3552     {
3553       tree_view->priv->arrow_prelit = TRUE;
3554
3555       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3556     }
3557
3558   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3559
3560   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3561
3562   if (tree_view->priv->hover_expand)
3563     {
3564       tree_view->priv->auto_expand_timeout = 
3565         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3566     }
3567 }
3568
3569 static void
3570 prelight_or_select (GtkTreeView *tree_view,
3571                     GtkRBTree   *tree,
3572                     GtkRBNode   *node,
3573                     /* these are in bin_window coords */
3574                     gint         x,
3575                     gint         y)
3576 {
3577   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3578   
3579   if (tree_view->priv->hover_selection &&
3580       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3581       !(tree_view->priv->edited_column &&
3582         gtk_cell_area_get_edit_widget 
3583         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3584     {
3585       if (node)
3586         {
3587           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3588             {
3589               GtkTreePath *path;
3590               
3591               path = _gtk_tree_view_find_path (tree_view, tree, node);
3592               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3593               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3594                 {
3595                   tree_view->priv->draw_keyfocus = FALSE;
3596                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3597                 }
3598               gtk_tree_path_free (path);
3599             }
3600         }
3601
3602       else if (mode == GTK_SELECTION_SINGLE)
3603         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3604     }
3605
3606     do_prelight (tree_view, tree, node, x, y);
3607 }
3608
3609 static void
3610 ensure_unprelighted (GtkTreeView *tree_view)
3611 {
3612   do_prelight (tree_view,
3613                NULL, NULL,
3614                -1000, -1000); /* coords not possibly over an arrow */
3615
3616   g_assert (tree_view->priv->prelight_node == NULL);
3617 }
3618
3619 static void
3620 update_prelight (GtkTreeView *tree_view,
3621                  gint         x,
3622                  gint         y)
3623 {
3624   int new_y;
3625   GtkRBTree *tree;
3626   GtkRBNode *node;
3627
3628   if (tree_view->priv->tree == NULL)
3629     return;
3630
3631   if (x == -10000)
3632     {
3633       ensure_unprelighted (tree_view);
3634       return;
3635     }
3636
3637   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3638   if (new_y < 0)
3639     new_y = 0;
3640
3641   _gtk_rbtree_find_offset (tree_view->priv->tree,
3642                            new_y, &tree, &node);
3643
3644   if (node)
3645     prelight_or_select (tree_view, tree, node, x, y);
3646 }
3647
3648
3649
3650
3651 /* Our motion arrow is either a box (in the case of the original spot)
3652  * or an arrow.  It is expander_size wide.
3653  */
3654 /*
3655  * 11111111111111
3656  * 01111111111110
3657  * 00111111111100
3658  * 00011111111000
3659  * 00001111110000
3660  * 00000111100000
3661  * 00000111100000
3662  * 00000111100000
3663  * ~ ~ ~ ~ ~ ~ ~
3664  * 00000111100000
3665  * 00000111100000
3666  * 00000111100000
3667  * 00001111110000
3668  * 00011111111000
3669  * 00111111111100
3670  * 01111111111110
3671  * 11111111111111
3672  */
3673
3674 static void
3675 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3676 {
3677   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3678   GtkWidget *widget = GTK_WIDGET (tree_view);
3679   cairo_surface_t *mask_image;
3680   cairo_region_t *mask_region;
3681   gint x;
3682   gint y;
3683   gint width;
3684   gint height;
3685   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3686   GdkWindowAttr attributes;
3687   guint attributes_mask;
3688   cairo_t *cr;
3689
3690   if (!reorder ||
3691       reorder->left_column == tree_view->priv->drag_column ||
3692       reorder->right_column == tree_view->priv->drag_column)
3693     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3694   else if (reorder->left_column || reorder->right_column)
3695     {
3696       GtkAllocation left_allocation, right_allocation;
3697       GdkRectangle visible_rect;
3698       GtkWidget *button;
3699
3700       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3701       if (reorder->left_column)
3702         {
3703           button = gtk_tree_view_column_get_button (reorder->left_column);
3704           gtk_widget_get_allocation (button, &left_allocation);
3705           x = left_allocation.x + left_allocation.width;
3706         }
3707       else
3708         {
3709           button = gtk_tree_view_column_get_button (reorder->right_column);
3710           gtk_widget_get_allocation (button, &right_allocation);
3711           x = right_allocation.x;
3712         }
3713
3714       if (x < visible_rect.x)
3715         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3716       else if (x > visible_rect.x + visible_rect.width)
3717         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3718       else
3719         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3720     }
3721
3722   /* We want to draw the rectangle over the initial location. */
3723   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3724     {
3725       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3726         {
3727           GtkAllocation drag_allocation;
3728           GtkWidget    *button;
3729
3730           if (tree_view->priv->drag_highlight_window)
3731             {
3732               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3733                                         NULL);
3734               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3735             }
3736
3737           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3738           attributes.window_type = GDK_WINDOW_CHILD;
3739           attributes.wclass = GDK_INPUT_OUTPUT;
3740           attributes.x = tree_view->priv->drag_column_x;
3741           attributes.y = 0;
3742           gtk_widget_get_allocation (button, &drag_allocation);
3743           width = attributes.width = drag_allocation.width;
3744           height = attributes.height = drag_allocation.height;
3745           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3746           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3747           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3748           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3749           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3750
3751           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3752           cr = cairo_create (mask_image);
3753
3754           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3755           cairo_stroke (cr);
3756           cairo_destroy (cr);
3757
3758           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3759           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3760                                            mask_region, 0, 0);
3761
3762           cairo_region_destroy (mask_region);
3763           cairo_surface_destroy (mask_image);
3764
3765           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3766         }
3767     }
3768   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3769     {
3770       GtkAllocation button_allocation;
3771       GtkWidget    *button;
3772
3773       width = tree_view->priv->expander_size;
3774
3775       /* Get x, y, width, height of arrow */
3776       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3777       if (reorder->left_column)
3778         {
3779           button = gtk_tree_view_column_get_button (reorder->left_column);
3780           gtk_widget_get_allocation (button, &button_allocation);
3781           x += button_allocation.x + button_allocation.width - width/2;
3782           height = button_allocation.height;
3783         }
3784       else
3785         {
3786           button = gtk_tree_view_column_get_button (reorder->right_column);
3787           gtk_widget_get_allocation (button, &button_allocation);
3788           x += button_allocation.x - width/2;
3789           height = button_allocation.height;
3790         }
3791       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3792       height += tree_view->priv->expander_size;
3793
3794       /* Create the new window */
3795       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3796         {
3797           if (tree_view->priv->drag_highlight_window)
3798             {
3799               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3800                                         NULL);
3801               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3802             }
3803
3804           attributes.window_type = GDK_WINDOW_TEMP;
3805           attributes.wclass = GDK_INPUT_OUTPUT;
3806           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3807           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3808           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3809           attributes.x = x;
3810           attributes.y = y;
3811           attributes.width = width;
3812           attributes.height = height;
3813           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3814                                                                    &attributes, attributes_mask);
3815           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3816
3817           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3818
3819           cr = cairo_create (mask_image);
3820           cairo_move_to (cr, 0, 0);
3821           cairo_line_to (cr, width, 0);
3822           cairo_line_to (cr, width / 2., width / 2);
3823           cairo_move_to (cr, 0, height);
3824           cairo_line_to (cr, width, height);
3825           cairo_line_to (cr, width / 2., height - width / 2.);
3826           cairo_fill (cr);
3827           cairo_destroy (cr);
3828
3829           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3830           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3831                                            mask_region, 0, 0);
3832
3833           cairo_region_destroy (mask_region);
3834           cairo_surface_destroy (mask_image);
3835         }
3836
3837       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3838       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3839     }
3840   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3841            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3842     {
3843       GtkAllocation allocation;
3844       GtkWidget    *button;
3845
3846       width = tree_view->priv->expander_size;
3847
3848       /* Get x, y, width, height of arrow */
3849       width = width/2; /* remember, the arrow only takes half the available width */
3850       gdk_window_get_origin (gtk_widget_get_window (widget),
3851                              &x, &y);
3852       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3853         {
3854           gtk_widget_get_allocation (widget, &allocation);
3855           x += allocation.width - width;
3856         }
3857
3858       if (reorder->left_column)
3859         {
3860           button = gtk_tree_view_column_get_button (reorder->left_column);
3861           gtk_widget_get_allocation (button, &allocation);
3862           height = allocation.height;
3863         }
3864       else
3865         {
3866           button = gtk_tree_view_column_get_button (reorder->right_column);
3867           gtk_widget_get_allocation (button, &allocation);
3868           height = allocation.height;
3869         }
3870
3871       y -= tree_view->priv->expander_size;
3872       height += 2*tree_view->priv->expander_size;
3873
3874       /* Create the new window */
3875       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3876           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3877         {
3878           if (tree_view->priv->drag_highlight_window)
3879             {
3880               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3881                                         NULL);
3882               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3883             }
3884
3885           attributes.window_type = GDK_WINDOW_TEMP;
3886           attributes.wclass = GDK_INPUT_OUTPUT;
3887           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3888           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3889           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3890           attributes.x = x;
3891           attributes.y = y;
3892           attributes.width = width;
3893           attributes.height = height;
3894           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3895           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3896
3897           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3898
3899           cr = cairo_create (mask_image);
3900           /* mirror if we're on the left */
3901           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3902             {
3903               cairo_translate (cr, width, 0);
3904               cairo_scale (cr, -1, 1);
3905             }
3906           cairo_move_to (cr, 0, 0);
3907           cairo_line_to (cr, width, width);
3908           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3909           cairo_move_to (cr, 0, height);
3910           cairo_line_to (cr, width, height - width);
3911           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3912           cairo_fill (cr);
3913           cairo_destroy (cr);
3914
3915           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3916           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3917                                            mask_region, 0, 0);
3918
3919           cairo_region_destroy (mask_region);
3920           cairo_surface_destroy (mask_image);
3921         }
3922
3923       tree_view->priv->drag_column_window_state = arrow_type;
3924       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3925    }
3926   else
3927     {
3928       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3929       gdk_window_hide (tree_view->priv->drag_highlight_window);
3930       return;
3931     }
3932
3933   gdk_window_show (tree_view->priv->drag_highlight_window);
3934   gdk_window_raise (tree_view->priv->drag_highlight_window);
3935 }
3936
3937 static gboolean
3938 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3939                                     GdkEventMotion *event)
3940 {
3941   gint x;
3942   gint new_width;
3943   GtkTreeViewColumn *column;
3944   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3945
3946   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3947
3948   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3949     gtk_widget_get_pointer (widget, &x, NULL);
3950   else
3951     x = event->x;
3952
3953   if (tree_view->priv->hadjustment)
3954     x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
3955
3956   new_width = gtk_tree_view_new_column_width (tree_view,
3957                                               tree_view->priv->drag_pos, &x);
3958   if (x != tree_view->priv->x_drag &&
3959       (new_width != gtk_tree_view_column_get_fixed_width (column)))
3960     {
3961       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
3962
3963       if (gtk_tree_view_column_get_expand (column))
3964         new_width -= tree_view->priv->last_extra_space_per_column;
3965
3966       _gtk_tree_view_column_set_resized_width (column, new_width);
3967
3968
3969       gtk_widget_queue_resize (widget);
3970     }
3971
3972   return FALSE;
3973 }
3974
3975
3976 static void
3977 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3978 {
3979   GtkTreeViewColumnReorder *reorder = NULL;
3980   GList *list;
3981   gint mouse_x;
3982
3983   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3984   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3985     {
3986       reorder = (GtkTreeViewColumnReorder *) list->data;
3987       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3988         break;
3989       reorder = NULL;
3990     }
3991
3992   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3993       return;*/
3994
3995   tree_view->priv->cur_reorder = reorder;
3996   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3997 }
3998
3999 static void
4000 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4001 {
4002   GdkRectangle visible_rect;
4003   gint y;
4004   gint offset;
4005
4006   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
4007   y += tree_view->priv->dy;
4008
4009   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4010
4011   /* see if we are near the edge. */
4012   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4013   if (offset > 0)
4014     {
4015       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4016       if (offset < 0)
4017         return;
4018     }
4019
4020   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4021                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4022 }
4023
4024 static gboolean
4025 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
4026 {
4027   GdkRectangle visible_rect;
4028   gint x;
4029   gint offset;
4030
4031   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
4032
4033   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4034
4035   /* See if we are near the edge. */
4036   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4037   if (offset > 0)
4038     {
4039       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4040       if (offset < 0)
4041         return TRUE;
4042     }
4043   offset = offset/3;
4044
4045   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4046                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4047
4048   return TRUE;
4049
4050 }
4051
4052 static gboolean
4053 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4054                                   GdkEventMotion *event)
4055 {
4056   GtkAllocation allocation, button_allocation;
4057   GtkTreeView *tree_view = (GtkTreeView *) widget;
4058   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4059   GtkWidget *button;
4060   gint x, y;
4061
4062   /* Sanity Check */
4063   if ((column == NULL) ||
4064       (event->window != tree_view->priv->drag_window))
4065     return FALSE;
4066
4067   button = gtk_tree_view_column_get_button (column);
4068
4069   /* Handle moving the header */
4070   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4071   gtk_widget_get_allocation (widget, &allocation);
4072   gtk_widget_get_allocation (button, &button_allocation);
4073   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4074              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4075   gdk_window_move (tree_view->priv->drag_window, x, y);
4076   
4077   /* autoscroll, if needed */
4078   gtk_tree_view_horizontal_autoscroll (tree_view);
4079   /* Update the current reorder position and arrow; */
4080   gtk_tree_view_update_current_reorder (tree_view);
4081
4082   return TRUE;
4083 }
4084
4085 static void
4086 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4087 {
4088   remove_scroll_timeout (tree_view);
4089   gtk_grab_remove (GTK_WIDGET (tree_view));
4090
4091   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4092     {
4093       GtkTreePath *tmp_path;
4094
4095       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4096
4097       /* The anchor path should be set to the start path */
4098       tmp_path = _gtk_tree_view_find_path (tree_view,
4099                                            tree_view->priv->rubber_band_start_tree,
4100                                            tree_view->priv->rubber_band_start_node);
4101
4102       if (tree_view->priv->anchor)
4103         gtk_tree_row_reference_free (tree_view->priv->anchor);
4104
4105       tree_view->priv->anchor =
4106         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4107                                           tree_view->priv->model,
4108                                           tmp_path);
4109
4110       gtk_tree_path_free (tmp_path);
4111
4112       /* ... and the cursor to the end path */
4113       tmp_path = _gtk_tree_view_find_path (tree_view,
4114                                            tree_view->priv->rubber_band_end_tree,
4115                                            tree_view->priv->rubber_band_end_node);
4116       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
4117       gtk_tree_path_free (tmp_path);
4118
4119       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4120     }
4121
4122   /* Clear status variables */
4123   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4124   tree_view->priv->rubber_band_extend = FALSE;
4125   tree_view->priv->rubber_band_modify = FALSE;
4126
4127   tree_view->priv->rubber_band_start_node = NULL;
4128   tree_view->priv->rubber_band_start_tree = NULL;
4129   tree_view->priv->rubber_band_end_node = NULL;
4130   tree_view->priv->rubber_band_end_tree = NULL;
4131 }
4132
4133 static void
4134 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4135                                                  GtkRBTree   *start_tree,
4136                                                  GtkRBNode   *start_node,
4137                                                  GtkRBTree   *end_tree,
4138                                                  GtkRBNode   *end_node,
4139                                                  gboolean     select,
4140                                                  gboolean     skip_start,
4141                                                  gboolean     skip_end)
4142 {
4143   if (start_node == end_node)
4144     return;
4145
4146   /* We skip the first node and jump inside the loop */
4147   if (skip_start)
4148     goto skip_first;
4149
4150   do
4151     {
4152       /* Small optimization by assuming insensitive nodes are never
4153        * selected.
4154        */
4155       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4156         {
4157           GtkTreePath *path;
4158           gboolean selectable;
4159
4160           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
4161           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4162           gtk_tree_path_free (path);
4163
4164           if (!selectable)
4165             goto node_not_selectable;
4166         }
4167
4168       if (select)
4169         {
4170           if (tree_view->priv->rubber_band_extend)
4171             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4172           else if (tree_view->priv->rubber_band_modify)
4173             {
4174               /* Toggle the selection state */
4175               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4176                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4177               else
4178                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4179             }
4180           else
4181             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4182         }
4183       else
4184         {
4185           /* Mirror the above */
4186           if (tree_view->priv->rubber_band_extend)
4187             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4188           else if (tree_view->priv->rubber_band_modify)
4189             {
4190               /* Toggle the selection state */
4191               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4192                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4193               else
4194                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4195             }
4196           else
4197             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4198         }
4199
4200       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4201
4202 node_not_selectable:
4203       if (start_node == end_node)
4204         break;
4205
4206 skip_first:
4207
4208       if (start_node->children)
4209         {
4210           start_tree = start_node->children;
4211           start_node = start_tree->root;
4212           while (start_node->left != start_tree->nil)
4213             start_node = start_node->left;
4214         }
4215       else
4216         {
4217           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4218
4219           if (!start_tree)
4220             /* Ran out of tree */
4221             break;
4222         }
4223
4224       if (skip_end && start_node == end_node)
4225         break;
4226     }
4227   while (TRUE);
4228 }
4229
4230 static void
4231 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4232 {
4233   GtkRBTree *start_tree, *end_tree;
4234   GtkRBNode *start_node, *end_node;
4235
4236   _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);
4237   _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);
4238
4239   /* Handle the start area first */
4240   if (!tree_view->priv->rubber_band_start_node)
4241     {
4242       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4243                                                        start_tree,
4244                                                        start_node,
4245                                                        end_tree,
4246                                                        end_node,
4247                                                        TRUE,
4248                                                        FALSE,
4249                                                        FALSE);
4250     }
4251   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4252            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4253     {
4254       /* New node is above the old one; selection became bigger */
4255       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4256                                                        start_tree,
4257                                                        start_node,
4258                                                        tree_view->priv->rubber_band_start_tree,
4259                                                        tree_view->priv->rubber_band_start_node,
4260                                                        TRUE,
4261                                                        FALSE,
4262                                                        TRUE);
4263     }
4264   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4265            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4266     {
4267       /* New node is below the old one; selection became smaller */
4268       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4269                                                        tree_view->priv->rubber_band_start_tree,
4270                                                        tree_view->priv->rubber_band_start_node,
4271                                                        start_tree,
4272                                                        start_node,
4273                                                        FALSE,
4274                                                        FALSE,
4275                                                        TRUE);
4276     }
4277
4278   tree_view->priv->rubber_band_start_tree = start_tree;
4279   tree_view->priv->rubber_band_start_node = start_node;
4280
4281   /* Next, handle the end area */
4282   if (!tree_view->priv->rubber_band_end_node)
4283     {
4284       /* In the event this happens, start_node was also NULL; this case is
4285        * handled above.
4286        */
4287     }
4288   else if (!end_node)
4289     {
4290       /* Find the last node in the tree */
4291       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4292                                &end_tree, &end_node);
4293
4294       /* Selection reached end of the tree */
4295       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4296                                                        tree_view->priv->rubber_band_end_tree,
4297                                                        tree_view->priv->rubber_band_end_node,
4298                                                        end_tree,
4299                                                        end_node,
4300                                                        TRUE,
4301                                                        TRUE,
4302                                                        FALSE);
4303     }
4304   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4305            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4306     {
4307       /* New node is below the old one; selection became bigger */
4308       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4309                                                        tree_view->priv->rubber_band_end_tree,
4310                                                        tree_view->priv->rubber_band_end_node,
4311                                                        end_tree,
4312                                                        end_node,
4313                                                        TRUE,
4314                                                        TRUE,
4315                                                        FALSE);
4316     }
4317   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4318            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4319     {
4320       /* New node is above the old one; selection became smaller */
4321       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4322                                                        end_tree,
4323                                                        end_node,
4324                                                        tree_view->priv->rubber_band_end_tree,
4325                                                        tree_view->priv->rubber_band_end_node,
4326                                                        FALSE,
4327                                                        TRUE,
4328                                                        FALSE);
4329     }
4330
4331   tree_view->priv->rubber_band_end_tree = end_tree;
4332   tree_view->priv->rubber_band_end_node = end_node;
4333 }
4334
4335 static void
4336 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4337 {
4338   gint x, y;
4339   GdkRectangle old_area;
4340   GdkRectangle new_area;
4341   GdkRectangle common;
4342   cairo_region_t *invalid_region;
4343
4344   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4345   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4346   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4347   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4348
4349   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4350
4351   x = MAX (x, 0);
4352   y = MAX (y, 0) + tree_view->priv->dy;
4353
4354   new_area.x = MIN (tree_view->priv->press_start_x, x);
4355   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4356   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4357   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4358
4359   invalid_region = cairo_region_create_rectangle (&old_area);
4360   cairo_region_union_rectangle (invalid_region, &new_area);
4361
4362   gdk_rectangle_intersect (&old_area, &new_area, &common);
4363   if (common.width > 2 && common.height > 2)
4364     {
4365       cairo_region_t *common_region;
4366
4367       /* make sure the border is invalidated */
4368       common.x += 1;
4369       common.y += 1;
4370       common.width -= 2;
4371       common.height -= 2;
4372
4373       common_region = cairo_region_create_rectangle (&common);
4374
4375       cairo_region_subtract (invalid_region, common_region);
4376       cairo_region_destroy (common_region);
4377     }
4378
4379   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4380
4381   cairo_region_destroy (invalid_region);
4382
4383   tree_view->priv->rubber_band_x = x;
4384   tree_view->priv->rubber_band_y = y;
4385
4386   gtk_tree_view_update_rubber_band_selection (tree_view);
4387 }
4388
4389 static void
4390 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4391                                  cairo_t      *cr)
4392 {
4393   GdkRectangle rect;
4394   GtkStyleContext *context;
4395
4396   cairo_save (cr);
4397
4398   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4399
4400   gtk_style_context_save (context);
4401   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
4402
4403   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4404   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4405   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4406   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4407
4408   gdk_cairo_rectangle (cr, &rect);
4409   cairo_clip (cr);
4410
4411   gtk_render_background (context, cr,
4412                          rect.x, rect.y,
4413                          rect.width, rect.height);
4414   gtk_render_frame (context, cr,
4415                     rect.x, rect.y,
4416                     rect.width, rect.height);
4417
4418   gtk_style_context_restore (context);
4419   cairo_restore (cr);
4420 }
4421
4422 static gboolean
4423 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4424                                  GdkEventMotion *event)
4425 {
4426   GtkTreeView *tree_view;
4427   GtkRBTree *tree;
4428   GtkRBNode *node;
4429   gint new_y;
4430
4431   tree_view = (GtkTreeView *) widget;
4432
4433   if (tree_view->priv->tree == NULL)
4434     return FALSE;
4435
4436   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4437     {
4438       gtk_grab_add (GTK_WIDGET (tree_view));
4439       gtk_tree_view_update_rubber_band (tree_view);
4440
4441       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4442     }
4443   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4444     {
4445       gtk_tree_view_update_rubber_band (tree_view);
4446
4447       add_scroll_timeout (tree_view);
4448     }
4449
4450   /* only check for an initiated drag when a button is pressed */
4451   if (tree_view->priv->pressed_button >= 0
4452       && !tree_view->priv->rubber_band_status)
4453     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4454
4455   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4456   if (new_y < 0)
4457     new_y = 0;
4458
4459   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4460
4461   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4462   if ((tree_view->priv->button_pressed_node != NULL) &&
4463       (tree_view->priv->button_pressed_node != node))
4464     node = NULL;
4465
4466   tree_view->priv->event_last_x = event->x;
4467   tree_view->priv->event_last_y = event->y;
4468
4469   prelight_or_select (tree_view, tree, node, event->x, event->y);
4470
4471   return TRUE;
4472 }
4473
4474 static gboolean
4475 gtk_tree_view_motion (GtkWidget      *widget,
4476                       GdkEventMotion *event)
4477 {
4478   GtkTreeView *tree_view;
4479
4480   tree_view = (GtkTreeView *) widget;
4481
4482   /* Resizing a column */
4483   if (tree_view->priv->in_column_resize)
4484     return gtk_tree_view_motion_resize_column (widget, event);
4485
4486   /* Drag column */
4487   if (tree_view->priv->in_column_drag)
4488     return gtk_tree_view_motion_drag_column (widget, event);
4489
4490   /* Sanity check it */
4491   if (event->window == tree_view->priv->bin_window)
4492     return gtk_tree_view_motion_bin_window (widget, event);
4493
4494   return FALSE;
4495 }
4496
4497 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4498  * the tree is empty.
4499  */
4500 static void
4501 invalidate_empty_focus (GtkTreeView *tree_view)
4502 {
4503   GdkRectangle area;
4504
4505   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4506     return;
4507
4508   area.x = 0;
4509   area.y = 0;
4510   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4511   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4512   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4513 }
4514
4515 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4516  * is empty.
4517  */
4518 static void
4519 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4520 {
4521   GtkWidget *widget = GTK_WIDGET (tree_view);
4522   gint w, h;
4523
4524   if (!gtk_widget_has_visible_focus (widget))
4525     return;
4526
4527   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4528   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4529
4530   if (w > 0 && h > 0)
4531     {
4532       GtkStyleContext *context;
4533       GtkStateFlags state;
4534
4535       context = gtk_widget_get_style_context (widget);
4536       state = gtk_widget_get_state_flags (widget);
4537
4538       gtk_style_context_save (context);
4539       gtk_style_context_set_state (context, state);
4540
4541       gtk_render_focus (context, cr, 1, 1, w, h);
4542
4543       gtk_style_context_restore (context);
4544     }
4545 }
4546
4547 typedef enum {
4548   GTK_TREE_VIEW_GRID_LINE,
4549   GTK_TREE_VIEW_TREE_LINE,
4550   GTK_TREE_VIEW_FOREGROUND_LINE
4551 } GtkTreeViewLineType;
4552
4553 static void
4554 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4555                          cairo_t             *cr,
4556                          GtkTreeViewLineType  type,
4557                          int                  x1,
4558                          int                  y1,
4559                          int                  x2,
4560                          int                  y2)
4561 {
4562   cairo_save (cr);
4563
4564   switch (type)
4565     {
4566     case GTK_TREE_VIEW_TREE_LINE:
4567       cairo_set_source_rgb (cr, 0, 0, 0);
4568       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4569       if (tree_view->priv->tree_line_dashes[0])
4570         cairo_set_dash (cr, 
4571                         tree_view->priv->tree_line_dashes,
4572                         2, 0.5);
4573       break;
4574     case GTK_TREE_VIEW_GRID_LINE:
4575       cairo_set_source_rgb (cr, 0, 0, 0);
4576       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4577       if (tree_view->priv->grid_line_dashes[0])
4578         cairo_set_dash (cr, 
4579                         tree_view->priv->grid_line_dashes,
4580                         2, 0.5);
4581       break;
4582     default:
4583       g_assert_not_reached ();
4584       /* fall through */
4585     case GTK_TREE_VIEW_FOREGROUND_LINE:
4586       {
4587         GtkStyleContext *context;
4588         GtkStateFlags state;
4589         GdkRGBA color;
4590
4591         context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4592         state = gtk_widget_get_state_flags (GTK_WIDGET (tree_view));
4593
4594         cairo_set_line_width (cr, 1.0);
4595         gtk_style_context_get_color (context, state, &color);
4596         gdk_cairo_set_source_rgba (cr, &color);
4597       }
4598
4599       break;
4600     }
4601
4602   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4603   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4604   cairo_stroke (cr);
4605
4606   cairo_restore (cr);
4607 }
4608                          
4609 static void
4610 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4611                                cairo_t        *cr,
4612                                gint            n_visible_columns)
4613 {
4614   GList *list = tree_view->priv->columns;
4615   gint i = 0;
4616   gint current_x = 0;
4617
4618   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4619       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4620     return;
4621
4622   /* Only draw the lines for visible rows and columns */
4623   for (list = tree_view->priv->columns; list; list = list->next, i++)
4624     {
4625       GtkTreeViewColumn *column = list->data;
4626
4627       /* We don't want a line for the last column */
4628       if (i == n_visible_columns - 1)
4629         break;
4630
4631       if (!gtk_tree_view_column_get_visible (column))
4632         continue;
4633
4634       current_x += gtk_tree_view_column_get_width (column);
4635
4636       gtk_tree_view_draw_line (tree_view, cr,
4637                                GTK_TREE_VIEW_GRID_LINE,
4638                                current_x - 1, 0,
4639                                current_x - 1, tree_view->priv->height);
4640     }
4641 }
4642
4643 /* Warning: Very scary function.
4644  * Modify at your own risk
4645  *
4646  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4647  * FIXME: It's not...
4648  */
4649 static gboolean
4650 gtk_tree_view_bin_draw (GtkWidget      *widget,
4651                         cairo_t        *cr)
4652 {
4653   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4654   GtkTreePath *path;
4655   GtkRBTree *tree;
4656   GList *list;
4657   GtkRBNode *node;
4658   GtkRBNode *cursor = NULL;
4659   GtkRBTree *cursor_tree = NULL;
4660   GtkRBNode *drag_highlight = NULL;
4661   GtkRBTree *drag_highlight_tree = NULL;
4662   GtkTreeIter iter;
4663   gint new_y;
4664   gint y_offset, cell_offset;
4665   gint max_height;
4666   gint depth;
4667   GdkRectangle background_area;
4668   GdkRectangle cell_area;
4669   GdkRectangle clip;
4670   guint flags;
4671   gint highlight_x;
4672   gint expander_cell_width;
4673   gint bin_window_width;
4674   gint bin_window_height;
4675   GtkTreePath *cursor_path;
4676   GtkTreePath *drag_dest_path;
4677   GList *first_column, *last_column;
4678   gint vertical_separator;
4679   gint horizontal_separator;
4680   gint focus_line_width;
4681   gboolean allow_rules;
4682   gboolean has_can_focus_cell;
4683   gboolean rtl;
4684   gint n_visible_columns;
4685   gint pointer_x, pointer_y;
4686   gint grid_line_width;
4687   gboolean got_pointer = FALSE;
4688   gboolean draw_vgrid_lines, draw_hgrid_lines;
4689   GtkStyleContext *context;
4690   GtkStateFlags state;
4691
4692   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4693   context = gtk_widget_get_style_context (widget);
4694   state = gtk_widget_get_state_flags (widget);
4695
4696   gtk_widget_style_get (widget,
4697                         "horizontal-separator", &horizontal_separator,
4698                         "vertical-separator", &vertical_separator,
4699                         "allow-rules", &allow_rules,
4700                         "focus-line-width", &focus_line_width,
4701                         NULL);
4702
4703   if (tree_view->priv->tree == NULL)
4704     {
4705       draw_empty_focus (tree_view, cr);
4706       return TRUE;
4707     }
4708
4709   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4710   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4711   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4712   cairo_clip (cr);
4713   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4714     return TRUE;
4715
4716   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4717
4718   if (new_y < 0)
4719     new_y = 0;
4720   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4721
4722   if (tree_view->priv->height < bin_window_height)
4723     {
4724       gtk_style_context_save (context);
4725       gtk_style_context_set_state (context, state);
4726       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4727
4728       gtk_render_background (context, cr,
4729                              0, tree_view->priv->height,
4730                              bin_window_width,
4731                              bin_window_height - tree_view->priv->height);
4732
4733       gtk_style_context_restore (context);
4734     }
4735
4736   if (node == NULL)
4737     return TRUE;
4738
4739   /* find the path for the node */
4740   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4741                                    tree,
4742                                    node);
4743   gtk_tree_model_get_iter (tree_view->priv->model,
4744                            &iter,
4745                            path);
4746   depth = gtk_tree_path_get_depth (path);
4747   gtk_tree_path_free (path);
4748   
4749   cursor_path = NULL;
4750   drag_dest_path = NULL;
4751
4752   if (tree_view->priv->cursor)
4753     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4754
4755   if (cursor_path)
4756     _gtk_tree_view_find_node (tree_view, cursor_path,
4757                               &cursor_tree, &cursor);
4758
4759   if (tree_view->priv->drag_dest_row)
4760     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4761
4762   if (drag_dest_path)
4763     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4764                               &drag_highlight_tree, &drag_highlight);
4765
4766   draw_vgrid_lines =
4767     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4768     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4769   draw_hgrid_lines =
4770     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4771     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4772
4773   if (draw_vgrid_lines || draw_hgrid_lines)
4774     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4775   
4776   n_visible_columns = 0;
4777   for (list = tree_view->priv->columns; list; list = list->next)
4778     {
4779       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4780         continue;
4781       n_visible_columns ++;
4782     }
4783
4784   /* Find the last column */
4785   for (last_column = g_list_last (tree_view->priv->columns);
4786        last_column &&
4787        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4788        last_column = last_column->prev)
4789     ;
4790
4791   /* and the first */
4792   for (first_column = g_list_first (tree_view->priv->columns);
4793        first_column &&
4794        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4795        first_column = first_column->next)
4796     ;
4797
4798   /* Actually process the expose event.  To do this, we want to
4799    * start at the first node of the event, and walk the tree in
4800    * order, drawing each successive node.
4801    */
4802
4803   do
4804     {
4805       gboolean parity;
4806       gboolean is_separator = FALSE;
4807       gboolean is_first = FALSE;
4808       gboolean is_last = FALSE;
4809       gint n_col = 0;
4810
4811       is_separator = row_is_separator (tree_view, &iter, NULL);
4812
4813       max_height = gtk_tree_view_get_row_height (tree_view, node);
4814
4815       cell_offset = 0;
4816       highlight_x = 0; /* should match x coord of first cell */
4817       expander_cell_width = 0;
4818
4819       background_area.y = y_offset + clip.y;
4820       background_area.height = max_height;
4821
4822       flags = 0;
4823
4824       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4825         flags |= GTK_CELL_RENDERER_PRELIT;
4826
4827       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4828         flags |= GTK_CELL_RENDERER_SELECTED;
4829
4830       parity = _gtk_rbtree_node_find_parity (tree, node);
4831
4832       /* we *need* to set cell data on all cells before the call
4833        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4834        * return a correct value.
4835        */
4836       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4837            list;
4838            list = (rtl ? list->prev : list->next))
4839         {
4840           GtkTreeViewColumn *column = list->data;
4841           gtk_tree_view_column_cell_set_cell_data (column,
4842                                                    tree_view->priv->model,
4843                                                    &iter,
4844                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4845                                                    node->children?TRUE:FALSE);
4846         }
4847
4848       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4849
4850       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4851            list;
4852            list = (rtl ? list->prev : list->next))
4853         {
4854           GtkTreeViewColumn *column = list->data;
4855           GtkRegionFlags row_flags = 0, column_flags = 0;
4856           GtkStateFlags state = 0;
4857           gint width;
4858           gboolean draw_focus;
4859
4860           if (!gtk_tree_view_column_get_visible (column))
4861             continue;
4862
4863           n_col++;
4864           width = gtk_tree_view_column_get_width (column);
4865
4866           if (cell_offset > clip.x + clip.width ||
4867               cell_offset + width < clip.x)
4868             {
4869               cell_offset += width;
4870               continue;
4871             }
4872
4873           if (gtk_tree_view_column_get_sort_indicator (column))
4874             flags |= GTK_CELL_RENDERER_SORTED;
4875           else
4876             flags &= ~GTK_CELL_RENDERER_SORTED;
4877
4878           if (cursor == node)
4879             flags |= GTK_CELL_RENDERER_FOCUSED;
4880           else
4881             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4882
4883           background_area.x = cell_offset;
4884           background_area.width = width;
4885
4886           cell_area = background_area;
4887           cell_area.y += vertical_separator / 2;
4888           cell_area.x += horizontal_separator / 2;
4889           cell_area.height -= vertical_separator;
4890           cell_area.width -= horizontal_separator;
4891
4892           if (draw_vgrid_lines)
4893             {
4894               if (list == first_column)
4895                 {
4896                   cell_area.width -= grid_line_width / 2;
4897                 }
4898               else if (list == last_column)
4899                 {
4900                   cell_area.x += grid_line_width / 2;
4901                   cell_area.width -= grid_line_width / 2;
4902                 }
4903               else
4904                 {
4905                   cell_area.x += grid_line_width / 2;
4906                   cell_area.width -= grid_line_width;
4907                 }
4908             }
4909
4910           if (draw_hgrid_lines)
4911             {
4912               cell_area.y += grid_line_width / 2;
4913               cell_area.height -= grid_line_width;
4914             }
4915
4916           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4917             {
4918               cell_offset += gtk_tree_view_column_get_width (column);
4919               continue;
4920             }
4921
4922           gtk_tree_view_column_cell_set_cell_data (column,
4923                                                    tree_view->priv->model,
4924                                                    &iter,
4925                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4926                                                    node->children?TRUE:FALSE);
4927
4928           /* Select the detail for drawing the cell.  relevant
4929            * factors are parity, sortedness, and whether to
4930            * display rules.
4931            */
4932           if (allow_rules && tree_view->priv->has_rules)
4933             {
4934               if (parity)
4935                 row_flags |= GTK_REGION_ODD;
4936               else
4937                 row_flags |= GTK_REGION_EVEN;
4938             }
4939
4940           if ((flags & GTK_CELL_RENDERER_SORTED) &&
4941               n_visible_columns >= 3)
4942             column_flags |= GTK_REGION_SORTED;
4943
4944           is_first = (rtl ? !list->next : !list->prev);
4945           is_last = (rtl ? !list->prev : !list->next);
4946
4947           if (is_first)
4948             column_flags |= GTK_REGION_FIRST;
4949
4950           if (is_last)
4951             column_flags |= GTK_REGION_LAST;
4952
4953           if ((n_col % 2) == 0)
4954             column_flags |= GTK_REGION_EVEN;
4955           else
4956             column_flags |= GTK_REGION_ODD;
4957
4958           gtk_style_context_save (context);
4959
4960           state = gtk_cell_renderer_get_state (NULL, widget, flags);
4961           gtk_style_context_set_state (context, state);
4962
4963           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4964           gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
4965           gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, column_flags);
4966
4967           if (node == cursor && has_can_focus_cell
4968               && ((column == tree_view->priv->focus_column
4969                    && tree_view->priv->draw_keyfocus &&
4970                    gtk_widget_has_visible_focus (widget))
4971                   || (column == tree_view->priv->edited_column)))
4972             draw_focus = TRUE;
4973           else
4974             draw_focus = FALSE;
4975
4976           /* Draw background */
4977           gtk_render_background (context, cr,
4978                                  background_area.x,
4979                                  background_area.y,
4980                                  background_area.width,
4981                                  background_area.height);
4982
4983           /* Draw frame */
4984           gtk_render_frame (context, cr,
4985                             background_area.x,
4986                             background_area.y,
4987                             background_area.width,
4988                             background_area.height);
4989
4990           if (gtk_tree_view_is_expander_column (tree_view, column))
4991             {
4992               if (!rtl)
4993                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4994               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4995
4996               if (gtk_tree_view_draw_expanders (tree_view))
4997                 {
4998                   if (!rtl)
4999                     cell_area.x += depth * tree_view->priv->expander_size;
5000                   cell_area.width -= depth * tree_view->priv->expander_size;
5001                 }
5002
5003               /* If we have an expander column, the highlight underline
5004                * starts with that column, so that it indicates which
5005                * level of the tree we're dropping at.
5006                */
5007               highlight_x = cell_area.x;
5008               expander_cell_width = cell_area.width;
5009
5010               if (is_separator)
5011                 {
5012                   gtk_style_context_save (context);
5013                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5014
5015                   gtk_render_line (context, cr,
5016                                    cell_area.x,
5017                                    cell_area.y + cell_area.height / 2,
5018                                    cell_area.x + cell_area.width,
5019                                    cell_area.y + cell_area.height / 2);
5020
5021                   gtk_style_context_restore (context);
5022                 }
5023               else
5024                 {
5025                   _gtk_tree_view_column_cell_render (column,
5026                                                      cr,
5027                                                      &background_area,
5028                                                      &cell_area,
5029                                                      flags,
5030                                                      draw_focus);
5031                 }
5032
5033               if (gtk_tree_view_draw_expanders (tree_view)
5034                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5035                 {
5036                   if (!got_pointer)
5037                     {
5038                       gdk_window_get_pointer (tree_view->priv->bin_window, 
5039                                               &pointer_x, &pointer_y, NULL);
5040                       got_pointer = TRUE;
5041                     }
5042
5043                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5044                                             cr,
5045                                             tree,
5046                                             node,
5047                                             pointer_x, pointer_y);
5048                 }
5049             }
5050           else
5051             {
5052               if (is_separator)
5053                 {
5054                   gtk_style_context_save (context);
5055                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5056
5057                   gtk_render_line (context, cr,
5058                                    cell_area.x,
5059                                    cell_area.y + cell_area.height / 2,
5060                                    cell_area.x + cell_area.width,
5061                                    cell_area.y + cell_area.height / 2);
5062
5063                   gtk_style_context_restore (context);
5064                 }
5065               else
5066                 _gtk_tree_view_column_cell_render (column,
5067                                                    cr,
5068                                                    &background_area,
5069                                                    &cell_area,
5070                                                    flags,
5071                                                    draw_focus);
5072             }
5073
5074           if (draw_hgrid_lines)
5075             {
5076               if (background_area.y > 0)
5077                 gtk_tree_view_draw_line (tree_view, cr,
5078                                          GTK_TREE_VIEW_GRID_LINE,
5079                                          background_area.x, background_area.y,
5080                                          background_area.x + background_area.width,
5081                                          background_area.y);
5082
5083               if (y_offset + max_height >= clip.height)
5084                 gtk_tree_view_draw_line (tree_view, cr,
5085                                          GTK_TREE_VIEW_GRID_LINE,
5086                                          background_area.x, background_area.y + max_height,
5087                                          background_area.x + background_area.width,
5088                                          background_area.y + max_height);
5089             }
5090
5091           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5092               tree_view->priv->tree_lines_enabled)
5093             {
5094               gint x = background_area.x;
5095               gint mult = rtl ? -1 : 1;
5096               gint y0 = background_area.y;
5097               gint y1 = background_area.y + background_area.height/2;
5098               gint y2 = background_area.y + background_area.height;
5099
5100               if (rtl)
5101                 x += background_area.width - 1;
5102
5103               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5104                   && depth > 1)
5105                 {
5106                   gtk_tree_view_draw_line (tree_view, cr,
5107                                            GTK_TREE_VIEW_TREE_LINE,
5108                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5109                                            y1,
5110                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
5111                                            y1);
5112                 }
5113               else if (depth > 1)
5114                 {
5115                   gtk_tree_view_draw_line (tree_view, cr,
5116                                            GTK_TREE_VIEW_TREE_LINE,
5117                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5118                                            y1,
5119                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
5120                                            y1);
5121                 }
5122
5123               if (depth > 1)
5124                 {
5125                   gint i;
5126                   GtkRBNode *tmp_node;
5127                   GtkRBTree *tmp_tree;
5128
5129                   if (!_gtk_rbtree_next (tree, node))
5130                     gtk_tree_view_draw_line (tree_view, cr,
5131                                              GTK_TREE_VIEW_TREE_LINE,
5132                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5133                                              y0,
5134                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5135                                              y1);
5136                   else
5137                     gtk_tree_view_draw_line (tree_view, cr,
5138                                              GTK_TREE_VIEW_TREE_LINE,
5139                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5140                                              y0,
5141                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5142                                              y2);
5143
5144                   tmp_node = tree->parent_node;
5145                   tmp_tree = tree->parent_tree;
5146
5147                   for (i = depth - 2; i > 0; i--)
5148                     {
5149                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5150                         gtk_tree_view_draw_line (tree_view, cr,
5151                                                  GTK_TREE_VIEW_TREE_LINE,
5152                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5153                                                  y0,
5154                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5155                                                  y2);
5156
5157                       tmp_node = tmp_tree->parent_node;
5158                       tmp_tree = tmp_tree->parent_tree;
5159                     }
5160                 }
5161             }
5162
5163           gtk_style_context_restore (context);
5164           cell_offset += gtk_tree_view_column_get_width (column);
5165         }
5166
5167       if (node == drag_highlight)
5168         {
5169           /* Draw indicator for the drop
5170            */
5171           gint highlight_y = -1;
5172           GtkRBTree *tree = NULL;
5173           GtkRBNode *node = NULL;
5174
5175           switch (tree_view->priv->drag_dest_pos)
5176             {
5177             case GTK_TREE_VIEW_DROP_BEFORE:
5178               highlight_y = background_area.y - 1;
5179               if (highlight_y < 0)
5180                       highlight_y = 0;
5181               break;
5182
5183             case GTK_TREE_VIEW_DROP_AFTER:
5184               highlight_y = background_area.y + background_area.height - 1;
5185               break;
5186
5187             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5188             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5189               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5190
5191               if (tree == NULL)
5192                 break;
5193
5194               gtk_render_focus (context, cr,
5195                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node)
5196                                    - focus_line_width / 2,
5197                                 gdk_window_get_width (tree_view->priv->bin_window),
5198                                 gtk_tree_view_get_row_height (tree_view, node)
5199                                    - focus_line_width + 1);
5200               break;
5201             }
5202
5203           if (highlight_y >= 0)
5204             {
5205               gtk_tree_view_draw_line (tree_view, cr,
5206                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5207                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5208                                        highlight_y,
5209                                        rtl ? 0 : bin_window_width,
5210                                        highlight_y);
5211             }
5212         }
5213
5214       /* draw the big row-spanning focus rectangle, if needed */
5215       if (!has_can_focus_cell && node == cursor &&
5216           tree_view->priv->draw_keyfocus &&
5217           gtk_widget_has_visible_focus (widget))
5218         {
5219           gint tmp_y, tmp_height;
5220           GtkStateFlags focus_rect_state = 0;
5221
5222           gtk_style_context_save (context);
5223
5224           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5225           gtk_style_context_set_state (context, focus_rect_state);
5226
5227           if (draw_hgrid_lines)
5228             {
5229               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5230               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5231             }
5232           else
5233             {
5234               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5235               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5236             }
5237
5238           gtk_render_focus (context, cr,
5239                             0, tmp_y,
5240                             gdk_window_get_width (tree_view->priv->bin_window),
5241                             tmp_height);
5242
5243           gtk_style_context_restore (context);
5244         }
5245
5246       y_offset += max_height;
5247       if (node->children)
5248         {
5249           GtkTreeIter parent = iter;
5250           gboolean has_child;
5251
5252           tree = node->children;
5253           node = tree->root;
5254
5255           g_assert (node != tree->nil);
5256
5257           while (node->left != tree->nil)
5258             node = node->left;
5259           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5260                                                     &iter,
5261                                                     &parent);
5262           depth++;
5263
5264           /* Sanity Check! */
5265           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5266         }
5267       else
5268         {
5269           gboolean done = FALSE;
5270
5271           do
5272             {
5273               node = _gtk_rbtree_next (tree, node);
5274               if (node != NULL)
5275                 {
5276                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5277                   done = TRUE;
5278
5279                   /* Sanity Check! */
5280                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5281                 }
5282               else
5283                 {
5284                   GtkTreeIter parent_iter = iter;
5285                   gboolean has_parent;
5286
5287                   node = tree->parent_node;
5288                   tree = tree->parent_tree;
5289                   if (tree == NULL)
5290                     /* we should go to done to free some memory */
5291                     goto done;
5292                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5293                                                            &iter,
5294                                                            &parent_iter);
5295                   depth--;
5296
5297                   /* Sanity check */
5298                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5299                 }
5300             }
5301           while (!done);
5302         }
5303     }
5304   while (y_offset < clip.height);
5305
5306 done:
5307   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5308
5309   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5310     gtk_tree_view_paint_rubber_band (tree_view, cr);
5311
5312   if (cursor_path)
5313     gtk_tree_path_free (cursor_path);
5314
5315   if (drag_dest_path)
5316     gtk_tree_path_free (drag_dest_path);
5317
5318   return FALSE;
5319 }
5320
5321 static gboolean
5322 gtk_tree_view_draw (GtkWidget *widget,
5323                     cairo_t   *cr)
5324 {
5325   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5326   GtkWidget   *button;
5327
5328   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5329     {
5330       GtkStyleContext *context;
5331       GList *tmp_list;
5332
5333       context = gtk_widget_get_style_context (widget);
5334
5335       cairo_save (cr);
5336
5337       gtk_style_context_save (context);
5338       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
5339
5340       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5341
5342       gtk_tree_view_bin_draw (widget, cr);
5343
5344       gtk_style_context_restore (context);
5345       cairo_restore (cr);
5346
5347       /* We can't just chain up to Container::draw as it will try to send the
5348        * event to the headers, so we handle propagating it to our children
5349        * (eg. widgets being edited) ourselves.
5350        */
5351       tmp_list = tree_view->priv->children;
5352       while (tmp_list)
5353         {
5354           GtkTreeViewChild *child = tmp_list->data;
5355           tmp_list = tmp_list->next;
5356
5357           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5358         }
5359     }
5360
5361   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5362     {
5363       GList *list;
5364       
5365       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5366         {
5367           GtkTreeViewColumn *column = list->data;
5368
5369           if (column == tree_view->priv->drag_column)
5370             continue;
5371
5372           if (gtk_tree_view_column_get_visible (column))
5373             {
5374               button = gtk_tree_view_column_get_button (column);
5375               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5376                                             button, cr);
5377             }
5378         }
5379     }
5380   
5381   if (tree_view->priv->drag_window &&
5382       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5383     {
5384       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5385       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5386                                     button, cr);
5387     }
5388
5389   return FALSE;
5390 }
5391
5392 enum
5393 {
5394   DROP_HOME,
5395   DROP_RIGHT,
5396   DROP_LEFT,
5397   DROP_END
5398 };
5399
5400 /* returns 0x1 when no column has been found -- yes it's hackish */
5401 static GtkTreeViewColumn *
5402 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5403                                GtkTreeViewColumn *column,
5404                                gint               drop_position)
5405 {
5406   GtkTreeViewColumn *left_column = NULL;
5407   GtkTreeViewColumn *cur_column = NULL;
5408   GList *tmp_list;
5409
5410   if (!gtk_tree_view_column_get_reorderable (column))
5411     return (GtkTreeViewColumn *)0x1;
5412
5413   switch (drop_position)
5414     {
5415       case DROP_HOME:
5416         /* find first column where we can drop */
5417         tmp_list = tree_view->priv->columns;
5418         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5419           return (GtkTreeViewColumn *)0x1;
5420
5421         while (tmp_list)
5422           {
5423             g_assert (tmp_list);
5424
5425             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5426             tmp_list = tmp_list->next;
5427
5428             if (left_column &&
5429                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5430               continue;
5431
5432             if (!tree_view->priv->column_drop_func)
5433               return left_column;
5434
5435             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5436               {
5437                 left_column = cur_column;
5438                 continue;
5439               }
5440
5441             return left_column;
5442           }
5443
5444         if (!tree_view->priv->column_drop_func)
5445           return left_column;
5446
5447         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5448           return left_column;
5449         else
5450           return (GtkTreeViewColumn *)0x1;
5451         break;
5452
5453       case DROP_RIGHT:
5454         /* find first column after column where we can drop */
5455         tmp_list = tree_view->priv->columns;
5456
5457         for (; tmp_list; tmp_list = tmp_list->next)
5458           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5459             break;
5460
5461         if (!tmp_list || !tmp_list->next)
5462           return (GtkTreeViewColumn *)0x1;
5463
5464         tmp_list = tmp_list->next;
5465         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5466         tmp_list = tmp_list->next;
5467
5468         while (tmp_list)
5469           {
5470             g_assert (tmp_list);
5471
5472             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5473             tmp_list = tmp_list->next;
5474
5475             if (left_column &&
5476                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5477               {
5478                 left_column = cur_column;
5479                 if (tmp_list)
5480                   tmp_list = tmp_list->next;
5481                 continue;
5482               }
5483
5484             if (!tree_view->priv->column_drop_func)
5485               return left_column;
5486
5487             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5488               {
5489                 left_column = cur_column;
5490                 continue;
5491               }
5492
5493             return left_column;
5494           }
5495
5496         if (!tree_view->priv->column_drop_func)
5497           return left_column;
5498
5499         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5500           return left_column;
5501         else
5502           return (GtkTreeViewColumn *)0x1;
5503         break;
5504
5505       case DROP_LEFT:
5506         /* find first column before column where we can drop */
5507         tmp_list = tree_view->priv->columns;
5508
5509         for (; tmp_list; tmp_list = tmp_list->next)
5510           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5511             break;
5512
5513         if (!tmp_list || !tmp_list->prev)
5514           return (GtkTreeViewColumn *)0x1;
5515
5516         tmp_list = tmp_list->prev;
5517         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5518         tmp_list = tmp_list->prev;
5519
5520         while (tmp_list)
5521           {
5522             g_assert (tmp_list);
5523
5524             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5525
5526             if (left_column &&
5527                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5528               {
5529                 /*if (!tmp_list->prev)
5530                   return (GtkTreeViewColumn *)0x1;
5531                   */
5532 /*
5533                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5534                 tmp_list = tmp_list->prev->prev;
5535                 continue;*/
5536
5537                 cur_column = left_column;
5538                 if (tmp_list)
5539                   tmp_list = tmp_list->prev;
5540                 continue;
5541               }
5542
5543             if (!tree_view->priv->column_drop_func)
5544               return left_column;
5545
5546             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5547               return left_column;
5548
5549             cur_column = left_column;
5550             tmp_list = tmp_list->prev;
5551           }
5552
5553         if (!tree_view->priv->column_drop_func)
5554           return NULL;
5555
5556         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5557           return NULL;
5558         else
5559           return (GtkTreeViewColumn *)0x1;
5560         break;
5561
5562       case DROP_END:
5563         /* same as DROP_HOME case, but doing it backwards */
5564         tmp_list = g_list_last (tree_view->priv->columns);
5565         cur_column = NULL;
5566
5567         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5568           return (GtkTreeViewColumn *)0x1;
5569
5570         while (tmp_list)
5571           {
5572             g_assert (tmp_list);
5573
5574             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5575
5576             if (left_column &&
5577                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5578               {
5579                 cur_column = left_column;
5580                 tmp_list = tmp_list->prev;
5581               }
5582
5583             if (!tree_view->priv->column_drop_func)
5584               return left_column;
5585
5586             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5587               return left_column;
5588
5589             cur_column = left_column;
5590             tmp_list = tmp_list->prev;
5591           }
5592
5593         if (!tree_view->priv->column_drop_func)
5594           return NULL;
5595
5596         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5597           return NULL;
5598         else
5599           return (GtkTreeViewColumn *)0x1;
5600         break;
5601     }
5602
5603   return (GtkTreeViewColumn *)0x1;
5604 }
5605
5606 static gboolean
5607 gtk_tree_view_key_press (GtkWidget   *widget,
5608                          GdkEventKey *event)
5609 {
5610   GtkTreeView *tree_view = (GtkTreeView *) widget;
5611   GtkWidget   *button;
5612
5613   if (tree_view->priv->rubber_band_status)
5614     {
5615       if (event->keyval == GDK_KEY_Escape)
5616         gtk_tree_view_stop_rubber_band (tree_view);
5617
5618       return TRUE;
5619     }
5620
5621   if (tree_view->priv->in_column_drag)
5622     {
5623       if (event->keyval == GDK_KEY_Escape)
5624         {
5625           tree_view->priv->cur_reorder = NULL;
5626           gtk_tree_view_button_release_drag_column (widget, NULL);
5627         }
5628       return TRUE;
5629     }
5630
5631   if (tree_view->priv->headers_visible)
5632     {
5633       GList *focus_column;
5634       gboolean rtl;
5635
5636       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5637
5638       for (focus_column = tree_view->priv->columns;
5639            focus_column;
5640            focus_column = focus_column->next)
5641         {
5642           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5643           
5644           button = gtk_tree_view_column_get_button (column);
5645           if (gtk_widget_has_focus (button))
5646             break;
5647         }
5648
5649       if (focus_column &&
5650           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5651           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5652            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5653         {
5654           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5655           gint max_width, min_width;
5656
5657           if (!gtk_tree_view_column_get_resizable (column))
5658             {
5659               gtk_widget_error_bell (widget);
5660               return TRUE;
5661             }
5662
5663           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5664               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5665             {
5666               GtkRequisition button_req;
5667               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5668               gint new_width;
5669
5670               button = gtk_tree_view_column_get_button (column);
5671
5672               gtk_widget_get_preferred_size (button, &button_req, NULL);
5673
5674               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5675               new_width -= 2;
5676               if (new_width < 0)
5677                 new_width = 0;
5678
5679               _gtk_tree_view_column_set_resized_width (column, new_width);
5680
5681               min_width = gtk_tree_view_column_get_min_width (column);
5682               if (min_width == -1)
5683                 new_width = MAX (button_req.width, new_width);
5684               else
5685                 {
5686                   new_width = MAX (min_width, new_width);
5687                 }
5688
5689               max_width = gtk_tree_view_column_get_max_width (column);
5690               if (max_width != -1)
5691                 new_width = MIN (new_width, max_width);
5692
5693               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5694
5695               if (new_width != old_width)
5696                 {
5697                   _gtk_tree_view_column_set_resized_width (column, new_width);
5698                   gtk_widget_queue_resize (widget);
5699                 }
5700               else
5701                 gtk_widget_error_bell (widget);
5702             }
5703           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5704                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5705             {
5706               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5707               gint new_width;
5708
5709               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5710               new_width += 2;
5711
5712               max_width = gtk_tree_view_column_get_max_width (column);
5713               if (max_width != -1)
5714                 new_width = MIN (new_width, max_width);
5715
5716               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5717
5718               if (new_width != old_width)
5719                 {
5720                   _gtk_tree_view_column_set_resized_width (column, new_width);
5721                   gtk_widget_queue_resize (widget);
5722                 }
5723               else
5724                 gtk_widget_error_bell (widget);
5725             }
5726
5727           return TRUE;
5728         }
5729
5730       if (focus_column &&
5731           (event->state & GDK_MOD1_MASK) &&
5732           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5733            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5734            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5735            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5736         {
5737           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5738
5739           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5740               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5741             {
5742               GtkTreeViewColumn *col;
5743               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5744               if (col != (GtkTreeViewColumn *)0x1)
5745                 gtk_tree_view_move_column_after (tree_view, column, col);
5746               else
5747                 gtk_widget_error_bell (widget);
5748             }
5749           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5750                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5751             {
5752               GtkTreeViewColumn *col;
5753               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5754               if (col != (GtkTreeViewColumn *)0x1)
5755                 gtk_tree_view_move_column_after (tree_view, column, col);
5756               else
5757                 gtk_widget_error_bell (widget);
5758             }
5759           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5760             {
5761               GtkTreeViewColumn *col;
5762               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5763               if (col != (GtkTreeViewColumn *)0x1)
5764                 gtk_tree_view_move_column_after (tree_view, column, col);
5765               else
5766                 gtk_widget_error_bell (widget);
5767             }
5768           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5769             {
5770               GtkTreeViewColumn *col;
5771               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5772               if (col != (GtkTreeViewColumn *)0x1)
5773                 gtk_tree_view_move_column_after (tree_view, column, col);
5774               else
5775                 gtk_widget_error_bell (widget);
5776             }
5777
5778           return TRUE;
5779         }
5780     }
5781
5782   /* Chain up to the parent class.  It handles the keybindings. */
5783   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5784     return TRUE;
5785
5786   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5787     {
5788       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5789       return FALSE;
5790     }
5791
5792   /* We pass the event to the search_entry.  If its text changes, then we start
5793    * the typeahead find capabilities. */
5794   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5795       && tree_view->priv->enable_search
5796       && !tree_view->priv->search_custom_entry_set)
5797     {
5798       GdkEvent *new_event;
5799       char *old_text;
5800       const char *new_text;
5801       gboolean retval;
5802       GdkScreen *screen;
5803       gboolean text_modified;
5804       gulong popup_menu_id;
5805
5806       gtk_tree_view_ensure_interactive_directory (tree_view);
5807
5808       /* Make a copy of the current text */
5809       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5810       new_event = gdk_event_copy ((GdkEvent *) event);
5811       g_object_unref (((GdkEventKey *) new_event)->window);
5812       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5813       gtk_widget_realize (tree_view->priv->search_window);
5814
5815       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5816                                         "popup-menu", G_CALLBACK (gtk_true),
5817                                         NULL);
5818
5819       /* Move the entry off screen */
5820       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5821       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5822                        gdk_screen_get_width (screen) + 1,
5823                        gdk_screen_get_height (screen) + 1);
5824       gtk_widget_show (tree_view->priv->search_window);
5825
5826       /* Send the event to the window.  If the preedit_changed signal is emitted
5827        * during this event, we will set priv->imcontext_changed  */
5828       tree_view->priv->imcontext_changed = FALSE;
5829       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5830       gdk_event_free (new_event);
5831       gtk_widget_hide (tree_view->priv->search_window);
5832
5833       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5834                                    popup_menu_id);
5835
5836       /* We check to make sure that the entry tried to handle the text, and that
5837        * the text has changed.
5838        */
5839       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5840       text_modified = strcmp (old_text, new_text) != 0;
5841       g_free (old_text);
5842       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5843           (retval && text_modified))               /* ...or the text was modified */
5844         {
5845           if (gtk_tree_view_real_start_interactive_search (tree_view,
5846                                                            gdk_event_get_device ((GdkEvent *) event),
5847                                                            FALSE))
5848             {
5849               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5850               return TRUE;
5851             }
5852           else
5853             {
5854               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5855               return FALSE;
5856             }
5857         }
5858     }
5859
5860   return FALSE;
5861 }
5862
5863 static gboolean
5864 gtk_tree_view_key_release (GtkWidget   *widget,
5865                            GdkEventKey *event)
5866 {
5867   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5868
5869   if (tree_view->priv->rubber_band_status)
5870     return TRUE;
5871
5872   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5873 }
5874
5875 /* FIXME Is this function necessary? Can I get an enter_notify event
5876  * w/o either an expose event or a mouse motion event?
5877  */
5878 static gboolean
5879 gtk_tree_view_enter_notify (GtkWidget        *widget,
5880                             GdkEventCrossing *event)
5881 {
5882   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5883   GtkRBTree *tree;
5884   GtkRBNode *node;
5885   gint new_y;
5886
5887   /* Sanity check it */
5888   if (event->window != tree_view->priv->bin_window)
5889     return FALSE;
5890
5891   if (tree_view->priv->tree == NULL)
5892     return FALSE;
5893
5894   if (event->mode == GDK_CROSSING_GRAB ||
5895       event->mode == GDK_CROSSING_GTK_GRAB ||
5896       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5897       event->mode == GDK_CROSSING_STATE_CHANGED)
5898     return TRUE;
5899
5900   /* find the node internally */
5901   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5902   if (new_y < 0)
5903     new_y = 0;
5904   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5905
5906   tree_view->priv->event_last_x = event->x;
5907   tree_view->priv->event_last_y = event->y;
5908
5909   if ((tree_view->priv->button_pressed_node == NULL) ||
5910       (tree_view->priv->button_pressed_node == node))
5911     prelight_or_select (tree_view, tree, node, event->x, event->y);
5912
5913   return TRUE;
5914 }
5915
5916 static gboolean
5917 gtk_tree_view_leave_notify (GtkWidget        *widget,
5918                             GdkEventCrossing *event)
5919 {
5920   GtkTreeView *tree_view;
5921
5922   if (event->mode == GDK_CROSSING_GRAB)
5923     return TRUE;
5924
5925   tree_view = GTK_TREE_VIEW (widget);
5926
5927   if (tree_view->priv->prelight_node)
5928     _gtk_tree_view_queue_draw_node (tree_view,
5929                                    tree_view->priv->prelight_tree,
5930                                    tree_view->priv->prelight_node,
5931                                    NULL);
5932
5933   tree_view->priv->event_last_x = -10000;
5934   tree_view->priv->event_last_y = -10000;
5935
5936   prelight_or_select (tree_view,
5937                       NULL, NULL,
5938                       -1000, -1000); /* coords not possibly over an arrow */
5939
5940   return TRUE;
5941 }
5942
5943
5944 static gint
5945 gtk_tree_view_focus_out (GtkWidget     *widget,
5946                          GdkEventFocus *event)
5947 {
5948   GtkTreeView *tree_view;
5949
5950   tree_view = GTK_TREE_VIEW (widget);
5951
5952   gtk_widget_queue_draw (widget);
5953
5954   /* destroy interactive search dialog */
5955   if (tree_view->priv->search_window)
5956     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5957                                       gdk_event_get_device ((GdkEvent *) event));
5958
5959   return FALSE;
5960 }
5961
5962
5963 /* Incremental Reflow
5964  */
5965
5966 static void
5967 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5968                                  GtkRBTree   *tree,
5969                                  GtkRBNode   *node)
5970 {
5971   GtkAllocation allocation;
5972   gint y;
5973
5974   y = _gtk_rbtree_node_find_offset (tree, node)
5975     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
5976     + gtk_tree_view_get_effective_header_height (tree_view);
5977
5978   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5979   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5980                               0, y,
5981                               allocation.width,
5982                               GTK_RBNODE_GET_HEIGHT (node));
5983 }
5984
5985 static gboolean
5986 node_is_visible (GtkTreeView *tree_view,
5987                  GtkRBTree   *tree,
5988                  GtkRBNode   *node)
5989 {
5990   int y;
5991   int height;
5992
5993   y = _gtk_rbtree_node_find_offset (tree, node);
5994   height = gtk_tree_view_get_row_height (tree_view, node);
5995
5996   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
5997       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
5998                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
5999     return TRUE;
6000
6001   return FALSE;
6002 }
6003
6004 /* Returns TRUE if it updated the size
6005  */
6006 static gboolean
6007 validate_row (GtkTreeView *tree_view,
6008               GtkRBTree   *tree,
6009               GtkRBNode   *node,
6010               GtkTreeIter *iter,
6011               GtkTreePath *path)
6012 {
6013   GtkTreeViewColumn *column;
6014   GList *list, *first_column, *last_column;
6015   gint height = 0;
6016   gint horizontal_separator;
6017   gint vertical_separator;
6018   gint depth = gtk_tree_path_get_depth (path);
6019   gboolean retval = FALSE;
6020   gboolean is_separator = FALSE;
6021   gboolean draw_vgrid_lines, draw_hgrid_lines;
6022   gint focus_pad;
6023   gint grid_line_width;
6024   gboolean wide_separators;
6025   gint separator_height;
6026
6027   /* double check the row needs validating */
6028   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6029       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6030     return FALSE;
6031
6032   is_separator = row_is_separator (tree_view, iter, NULL);
6033
6034   gtk_widget_style_get (GTK_WIDGET (tree_view),
6035                         "focus-padding", &focus_pad,
6036                         "horizontal-separator", &horizontal_separator,
6037                         "vertical-separator", &vertical_separator,
6038                         "grid-line-width", &grid_line_width,
6039                         "wide-separators",  &wide_separators,
6040                         "separator-height", &separator_height,
6041                         NULL);
6042   
6043   draw_vgrid_lines =
6044     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6045     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6046   draw_hgrid_lines =
6047     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6048     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6049
6050   for (last_column = g_list_last (tree_view->priv->columns);
6051        last_column &&
6052        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6053        last_column = last_column->prev)
6054     ;
6055
6056   for (first_column = g_list_first (tree_view->priv->columns);
6057        first_column &&
6058        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6059        first_column = first_column->next)
6060     ;
6061
6062   for (list = tree_view->priv->columns; list; list = list->next)
6063     {
6064       gint padding = 0;
6065       gint original_width;
6066       gint new_width;
6067       gint row_height;
6068
6069       column = list->data;
6070
6071       if (!gtk_tree_view_column_get_visible (column))
6072         continue;
6073
6074       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6075           !_gtk_tree_view_column_cell_get_dirty (column))
6076         continue;
6077
6078       original_width = _gtk_tree_view_column_get_requested_width (column);
6079
6080       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6081                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6082                                                node->children?TRUE:FALSE);
6083       gtk_tree_view_column_cell_get_size (column,
6084                                           NULL, NULL, NULL,
6085                                           NULL, &row_height);
6086
6087       if (!is_separator)
6088         {
6089           row_height += vertical_separator;
6090           height = MAX (height, row_height);
6091           height = MAX (height, tree_view->priv->expander_size);
6092         }
6093       else
6094         {
6095           if (wide_separators)
6096             height = separator_height + 2 * focus_pad;
6097           else
6098             height = 2 + 2 * focus_pad;
6099         }
6100
6101       if (gtk_tree_view_is_expander_column (tree_view, column))
6102         {
6103           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6104
6105           if (gtk_tree_view_draw_expanders (tree_view))
6106             padding += depth * tree_view->priv->expander_size;
6107         }
6108       else
6109         padding += horizontal_separator;
6110
6111       if (draw_vgrid_lines)
6112         {
6113           if (list->data == first_column || list->data == last_column)
6114             padding += grid_line_width / 2.0;
6115           else
6116             padding += grid_line_width;
6117         }
6118
6119       /* Update the padding for the column */
6120       _gtk_tree_view_column_push_padding (column, padding);
6121       new_width = _gtk_tree_view_column_get_requested_width (column);
6122
6123       if (new_width > original_width)
6124         retval = TRUE;
6125     }
6126
6127   if (draw_hgrid_lines)
6128     height += grid_line_width;
6129
6130   if (height != GTK_RBNODE_GET_HEIGHT (node))
6131     {
6132       retval = TRUE;
6133       _gtk_rbtree_node_set_height (tree, node, height);
6134     }
6135   _gtk_rbtree_node_mark_valid (tree, node);
6136   tree_view->priv->post_validation_flag = TRUE;
6137
6138   return retval;
6139 }
6140
6141
6142 static void
6143 validate_visible_area (GtkTreeView *tree_view)
6144 {
6145   GtkAllocation allocation;
6146   GtkTreePath *path = NULL;
6147   GtkTreePath *above_path = NULL;
6148   GtkTreeIter iter;
6149   GtkRBTree *tree = NULL;
6150   GtkRBNode *node = NULL;
6151   gboolean need_redraw = FALSE;
6152   gboolean size_changed = FALSE;
6153   gint total_height;
6154   gint area_above = 0;
6155   gint area_below = 0;
6156
6157   if (tree_view->priv->tree == NULL)
6158     return;
6159
6160   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6161       tree_view->priv->scroll_to_path == NULL)
6162     return;
6163
6164   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6165   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6166
6167   if (total_height == 0)
6168     return;
6169
6170   /* First, we check to see if we need to scroll anywhere
6171    */
6172   if (tree_view->priv->scroll_to_path)
6173     {
6174       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6175       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6176         {
6177           /* we are going to scroll, and will update dy */
6178           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6179           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6180               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6181             {
6182               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6183               if (validate_row (tree_view, tree, node, &iter, path))
6184                 size_changed = TRUE;
6185             }
6186
6187           if (tree_view->priv->scroll_to_use_align)
6188             {
6189               gint height = gtk_tree_view_get_row_height (tree_view, node);
6190               area_above = (total_height - height) *
6191                 tree_view->priv->scroll_to_row_align;
6192               area_below = total_height - area_above - height;
6193               area_above = MAX (area_above, 0);
6194               area_below = MAX (area_below, 0);
6195             }
6196           else
6197             {
6198               /* two cases:
6199                * 1) row not visible
6200                * 2) row visible
6201                */
6202               gint dy;
6203               gint height = gtk_tree_view_get_row_height (tree_view, node);
6204
6205               dy = _gtk_rbtree_node_find_offset (tree, node);
6206
6207               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6208                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6209                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6210                 {
6211                   /* row visible: keep the row at the same position */
6212                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6213                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6214                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6215                                - dy - height;
6216                 }
6217               else
6218                 {
6219                   /* row not visible */
6220                   if (dy >= 0
6221                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6222                     {
6223                       /* row at the beginning -- fixed */
6224                       area_above = dy;
6225                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6226                                    - area_above - height;
6227                     }
6228                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6229                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6230                     {
6231                       /* row at the end -- fixed */
6232                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6233                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6234                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6235                                    area_above - height;
6236
6237                       if (area_below < 0)
6238                         {
6239                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6240                           area_below = 0;
6241                         }
6242                     }
6243                   else
6244                     {
6245                       /* row somewhere in the middle, bring it to the top
6246                        * of the view
6247                        */
6248                       area_above = 0;
6249                       area_below = total_height - height;
6250                     }
6251                 }
6252             }
6253         }
6254       else
6255         /* the scroll to isn't valid; ignore it.
6256          */
6257         {
6258           if (tree_view->priv->scroll_to_path && !path)
6259             {
6260               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6261               tree_view->priv->scroll_to_path = NULL;
6262             }
6263           if (path)
6264             gtk_tree_path_free (path);
6265           path = NULL;
6266         }      
6267     }
6268
6269   /* We didn't have a scroll_to set, so we just handle things normally
6270    */
6271   if (path == NULL)
6272     {
6273       gint offset;
6274
6275       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6276                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6277                                         &tree, &node);
6278       if (node == NULL)
6279         {
6280           /* In this case, nothing has been validated */
6281           path = gtk_tree_path_new_first ();
6282           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6283         }
6284       else
6285         {
6286           path = _gtk_tree_view_find_path (tree_view, tree, node);
6287           total_height += offset;
6288         }
6289
6290       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6291
6292       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6293           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6294         {
6295           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6296           if (validate_row (tree_view, tree, node, &iter, path))
6297             size_changed = TRUE;
6298         }
6299       area_above = 0;
6300       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6301     }
6302
6303   above_path = gtk_tree_path_copy (path);
6304
6305   /* if we do not validate any row above the new top_row, we will make sure
6306    * that the row immediately above top_row has been validated. (if we do not
6307    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6308    * when invalidated that row's height will be zero. and this will mess up
6309    * scrolling).
6310    */
6311   if (area_above == 0)
6312     {
6313       GtkRBTree *tmptree;
6314       GtkRBNode *tmpnode;
6315
6316       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6317       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6318
6319       if (tmpnode)
6320         {
6321           GtkTreePath *tmppath;
6322           GtkTreeIter tmpiter;
6323
6324           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6325           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6326
6327           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6328               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6329             {
6330               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6331               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6332                 size_changed = TRUE;
6333             }
6334
6335           gtk_tree_path_free (tmppath);
6336         }
6337     }
6338
6339   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6340    * backwards is much slower then forward, as there is no iter_prev function.
6341    * We go forwards first in case we run out of tree.  Then we go backwards to
6342    * fill out the top.
6343    */
6344   while (node && area_below > 0)
6345     {
6346       if (node->children)
6347         {
6348           GtkTreeIter parent = iter;
6349           gboolean has_child;
6350
6351           tree = node->children;
6352           node = tree->root;
6353
6354           g_assert (node != tree->nil);
6355
6356           while (node->left != tree->nil)
6357             node = node->left;
6358           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6359                                                     &iter,
6360                                                     &parent);
6361           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6362           gtk_tree_path_down (path);
6363         }
6364       else
6365         {
6366           gboolean done = FALSE;
6367           do
6368             {
6369               node = _gtk_rbtree_next (tree, node);
6370               if (node != NULL)
6371                 {
6372                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6373                   done = TRUE;
6374                   gtk_tree_path_next (path);
6375
6376                   /* Sanity Check! */
6377                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6378                 }
6379               else
6380                 {
6381                   GtkTreeIter parent_iter = iter;
6382                   gboolean has_parent;
6383
6384                   node = tree->parent_node;
6385                   tree = tree->parent_tree;
6386                   if (tree == NULL)
6387                     break;
6388                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6389                                                            &iter,
6390                                                            &parent_iter);
6391                   gtk_tree_path_up (path);
6392
6393                   /* Sanity check */
6394                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6395                 }
6396             }
6397           while (!done);
6398         }
6399
6400       if (!node)
6401         break;
6402
6403       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6404           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6405         {
6406           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6407           if (validate_row (tree_view, tree, node, &iter, path))
6408               size_changed = TRUE;
6409         }
6410
6411       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6412     }
6413   gtk_tree_path_free (path);
6414
6415   /* If we ran out of tree, and have extra area_below left, we need to add it
6416    * to area_above */
6417   if (area_below > 0)
6418     area_above += area_below;
6419
6420   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6421
6422   /* We walk backwards */
6423   while (area_above > 0)
6424     {
6425       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6426
6427       /* Always find the new path in the tree.  We cannot just assume
6428        * a gtk_tree_path_prev() is enough here, as there might be children
6429        * in between this node and the previous sibling node.  If this
6430        * appears to be a performance hotspot in profiles, we can look into
6431        * intrigate logic for keeping path, node and iter in sync like
6432        * we do for forward walks.  (Which will be hard because of the lacking
6433        * iter_prev).
6434        */
6435
6436       if (node == NULL)
6437         break;
6438
6439       gtk_tree_path_free (above_path);
6440       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6441
6442       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6443
6444       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6445           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6446         {
6447           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6448           if (validate_row (tree_view, tree, node, &iter, above_path))
6449             size_changed = TRUE;
6450         }
6451       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6452     }
6453
6454   /* if we scrolled to a path, we need to set the dy here,
6455    * and sync the top row accordingly
6456    */
6457   if (tree_view->priv->scroll_to_path)
6458     {
6459       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6460       gtk_tree_view_top_row_to_dy (tree_view);
6461
6462       need_redraw = TRUE;
6463     }
6464   else if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6465     {
6466       /* when we are not scrolling, we should never set dy to something
6467        * else than zero. we update top_row to be in sync with dy = 0.
6468        */
6469       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6470       gtk_tree_view_dy_to_top_row (tree_view);
6471     }
6472   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6473     {
6474       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6475       gtk_tree_view_dy_to_top_row (tree_view);
6476     }
6477   else
6478     gtk_tree_view_top_row_to_dy (tree_view);
6479
6480   /* update width/height and queue a resize */
6481   if (size_changed)
6482     {
6483       GtkRequisition requisition;
6484
6485       /* We temporarily guess a size, under the assumption that it will be the
6486        * same when we get our next size_allocate.  If we don't do this, we'll be
6487        * in an inconsistent state if we call top_row_to_dy. */
6488
6489       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6490                                      &requisition, NULL);
6491       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6492                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6493       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6494                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6495       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6496     }
6497
6498   if (tree_view->priv->scroll_to_path)
6499     {
6500       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6501       tree_view->priv->scroll_to_path = NULL;
6502     }
6503
6504   if (above_path)
6505     gtk_tree_path_free (above_path);
6506
6507   if (tree_view->priv->scroll_to_column)
6508     {
6509       tree_view->priv->scroll_to_column = NULL;
6510     }
6511   if (need_redraw)
6512     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6513 }
6514
6515 static void
6516 initialize_fixed_height_mode (GtkTreeView *tree_view)
6517 {
6518   if (!tree_view->priv->tree)
6519     return;
6520
6521   if (tree_view->priv->fixed_height < 0)
6522     {
6523       GtkTreeIter iter;
6524       GtkTreePath *path;
6525
6526       GtkRBTree *tree = NULL;
6527       GtkRBNode *node = NULL;
6528
6529       tree = tree_view->priv->tree;
6530       node = tree->root;
6531
6532       path = _gtk_tree_view_find_path (tree_view, tree, node);
6533       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6534
6535       validate_row (tree_view, tree, node, &iter, path);
6536
6537       gtk_tree_path_free (path);
6538
6539       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6540     }
6541
6542    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6543                                  tree_view->priv->fixed_height, TRUE);
6544 }
6545
6546 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6547  * the left-most uninvalidated node.  We then try walking right, validating
6548  * nodes.  Once we find a valid node, we repeat the previous process of finding
6549  * the first invalid node.
6550  */
6551
6552 static gboolean
6553 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6554 {
6555   GtkRBTree *tree = NULL;
6556   GtkRBNode *node = NULL;
6557   gboolean validated_area = FALSE;
6558   gint retval = TRUE;
6559   GtkTreePath *path = NULL;
6560   GtkTreeIter iter;
6561   GTimer *timer;
6562   gint i = 0;
6563
6564   gint y = -1;
6565   gint prev_height = -1;
6566   gboolean fixed_height = TRUE;
6567
6568   g_assert (tree_view);
6569
6570   if (tree_view->priv->tree == NULL)
6571       return FALSE;
6572
6573   if (tree_view->priv->fixed_height_mode)
6574     {
6575       if (tree_view->priv->fixed_height < 0)
6576         initialize_fixed_height_mode (tree_view);
6577
6578       return FALSE;
6579     }
6580
6581   timer = g_timer_new ();
6582   g_timer_start (timer);
6583
6584   do
6585     {
6586       gboolean changed = FALSE;
6587
6588       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6589         {
6590           retval = FALSE;
6591           goto done;
6592         }
6593
6594       if (path != NULL)
6595         {
6596           node = _gtk_rbtree_next (tree, node);
6597           if (node != NULL)
6598             {
6599               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6600               gtk_tree_path_next (path);
6601             }
6602           else
6603             {
6604               gtk_tree_path_free (path);
6605               path = NULL;
6606             }
6607         }
6608
6609       if (path == NULL)
6610         {
6611           tree = tree_view->priv->tree;
6612           node = tree_view->priv->tree->root;
6613
6614           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6615
6616           do
6617             {
6618               if (node->left != tree->nil &&
6619                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6620                 {
6621                   node = node->left;
6622                 }
6623               else if (node->right != tree->nil &&
6624                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6625                 {
6626                   node = node->right;
6627                 }
6628               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6629                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6630                 {
6631                   break;
6632                 }
6633               else if (node->children != NULL)
6634                 {
6635                   tree = node->children;
6636                   node = tree->root;
6637                 }
6638               else
6639                 /* RBTree corruption!  All bad */
6640                 g_assert_not_reached ();
6641             }
6642           while (TRUE);
6643           path = _gtk_tree_view_find_path (tree_view, tree, node);
6644           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6645         }
6646
6647       changed = validate_row (tree_view, tree, node, &iter, path);
6648       validated_area = changed || validated_area;
6649
6650       if (changed)
6651         {
6652           gint offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
6653
6654           if (y == -1 || y > offset)
6655             y = offset;
6656         }
6657
6658       if (!tree_view->priv->fixed_height_check)
6659         {
6660           gint height;
6661
6662           height = gtk_tree_view_get_row_height (tree_view, node);
6663           if (prev_height < 0)
6664             prev_height = height;
6665           else if (prev_height != height)
6666             fixed_height = FALSE;
6667         }
6668
6669       i++;
6670     }
6671   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6672
6673   if (!tree_view->priv->fixed_height_check)
6674    {
6675      if (fixed_height)
6676        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6677
6678      tree_view->priv->fixed_height_check = 1;
6679    }
6680   
6681  done:
6682   if (validated_area)
6683     {
6684       GtkRequisition requisition;
6685
6686       /* We temporarily guess a size, under the assumption that it will be the
6687        * same when we get our next size_allocate.  If we don't do this, we'll be
6688        * in an inconsistent state when we call top_row_to_dy. */
6689
6690       /* FIXME: This is called from size_request, for some reason it is not infinitely
6691        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6692        * not allowed (from inside ->get_preferred_width/height() implementations, one
6693        * should call the vfuncs directly). However what is desired here is the full
6694        * size including any margins and limited by any alignment (i.e. after 
6695        * GtkWidget:adjust_size_request() is called).
6696        *
6697        * Currently bypassing this but the real solution is to not update the scroll adjustments
6698        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6699        */
6700       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition, FALSE);
6701
6702       /* If rows above the current position have changed height, this has
6703        * affected the current view and thus needs a redraw.
6704        */
6705       if (y != -1 && y < gtk_adjustment_get_value (tree_view->priv->vadjustment))
6706         gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6707
6708       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6709                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6710       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6711                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6712
6713       if (queue_resize)
6714         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6715     }
6716
6717   if (path) gtk_tree_path_free (path);
6718   g_timer_destroy (timer);
6719
6720   return retval;
6721 }
6722
6723 static gboolean
6724 validate_rows (GtkTreeView *tree_view)
6725 {
6726   gboolean retval;
6727   
6728   retval = do_validate_rows (tree_view, TRUE);
6729   
6730   if (! retval && tree_view->priv->validate_rows_timer)
6731     {
6732       g_source_remove (tree_view->priv->validate_rows_timer);
6733       tree_view->priv->validate_rows_timer = 0;
6734     }
6735
6736   return retval;
6737 }
6738
6739 static gboolean
6740 validate_rows_handler (GtkTreeView *tree_view)
6741 {
6742   gboolean retval;
6743
6744   retval = do_validate_rows (tree_view, TRUE);
6745   if (! retval && tree_view->priv->validate_rows_timer)
6746     {
6747       g_source_remove (tree_view->priv->validate_rows_timer);
6748       tree_view->priv->validate_rows_timer = 0;
6749     }
6750
6751   return retval;
6752 }
6753
6754 static gboolean
6755 do_presize_handler (GtkTreeView *tree_view)
6756 {
6757   if (tree_view->priv->mark_rows_col_dirty)
6758     {
6759       if (tree_view->priv->tree)
6760         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6761       tree_view->priv->mark_rows_col_dirty = FALSE;
6762     }
6763   validate_visible_area (tree_view);
6764   tree_view->priv->presize_handler_timer = 0;
6765
6766   if (tree_view->priv->fixed_height_mode)
6767     {
6768       GtkRequisition requisition;
6769
6770       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6771                                      &requisition, NULL);
6772
6773       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6774                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6775       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6776                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6777       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6778     }
6779                    
6780   return FALSE;
6781 }
6782
6783 static gboolean
6784 presize_handler_callback (gpointer data)
6785 {
6786   do_presize_handler (GTK_TREE_VIEW (data));
6787                    
6788   return FALSE;
6789 }
6790
6791 static void
6792 install_presize_handler (GtkTreeView *tree_view)
6793 {
6794   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6795     return;
6796
6797   if (! tree_view->priv->presize_handler_timer)
6798     {
6799       tree_view->priv->presize_handler_timer =
6800         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6801     }
6802   if (! tree_view->priv->validate_rows_timer)
6803     {
6804       tree_view->priv->validate_rows_timer =
6805         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6806     }
6807 }
6808
6809 static void
6810 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6811 {
6812   /* Prior to drawing, we make sure the visible area is validated. */
6813   if (tree_view->priv->presize_handler_timer)
6814     {
6815       g_source_remove (tree_view->priv->presize_handler_timer);
6816       tree_view->priv->presize_handler_timer = 0;
6817
6818       do_presize_handler (tree_view);
6819     }
6820
6821   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6822 }
6823
6824 static gboolean
6825 scroll_sync_handler (GtkTreeView *tree_view)
6826 {
6827   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6828     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6829   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6830     gtk_tree_view_top_row_to_dy (tree_view);
6831   else
6832     gtk_tree_view_dy_to_top_row (tree_view);
6833
6834   tree_view->priv->scroll_sync_timer = 0;
6835
6836   return FALSE;
6837 }
6838
6839 static void
6840 install_scroll_sync_handler (GtkTreeView *tree_view)
6841 {
6842   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6843     return;
6844
6845   if (!tree_view->priv->scroll_sync_timer)
6846     {
6847       tree_view->priv->scroll_sync_timer =
6848         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6849     }
6850 }
6851
6852 static void
6853 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6854                            GtkTreePath *path,
6855                            gint         offset)
6856 {
6857   gtk_tree_row_reference_free (tree_view->priv->top_row);
6858
6859   if (!path)
6860     {
6861       tree_view->priv->top_row = NULL;
6862       tree_view->priv->top_row_dy = 0;
6863     }
6864   else
6865     {
6866       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6867       tree_view->priv->top_row_dy = offset;
6868     }
6869 }
6870
6871 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6872  * it's set to be NULL, and top_row_dy is 0;
6873  */
6874 static void
6875 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6876 {
6877   gint offset;
6878   GtkTreePath *path;
6879   GtkRBTree *tree;
6880   GtkRBNode *node;
6881
6882   if (tree_view->priv->tree == NULL)
6883     {
6884       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6885     }
6886   else
6887     {
6888       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6889                                         tree_view->priv->dy,
6890                                         &tree, &node);
6891
6892       if (tree == NULL)
6893         {
6894           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6895         }
6896       else
6897         {
6898           path = _gtk_tree_view_find_path (tree_view, tree, node);
6899           gtk_tree_view_set_top_row (tree_view, path, offset);
6900           gtk_tree_path_free (path);
6901         }
6902     }
6903 }
6904
6905 static void
6906 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6907 {
6908   GtkTreePath *path;
6909   GtkRBTree *tree;
6910   GtkRBNode *node;
6911   int new_dy;
6912
6913   /* Avoid recursive calls */
6914   if (tree_view->priv->in_top_row_to_dy)
6915     return;
6916
6917   if (tree_view->priv->top_row)
6918     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6919   else
6920     path = NULL;
6921
6922   if (!path)
6923     tree = NULL;
6924   else
6925     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6926
6927   if (path)
6928     gtk_tree_path_free (path);
6929
6930   if (tree == NULL)
6931     {
6932       /* keep dy and set new toprow */
6933       gtk_tree_row_reference_free (tree_view->priv->top_row);
6934       tree_view->priv->top_row = NULL;
6935       tree_view->priv->top_row_dy = 0;
6936       /* DO NOT install the idle handler */
6937       gtk_tree_view_dy_to_top_row (tree_view);
6938       return;
6939     }
6940
6941   if (gtk_tree_view_get_row_height (tree_view, node)
6942       < tree_view->priv->top_row_dy)
6943     {
6944       /* new top row -- do NOT install the idle handler */
6945       gtk_tree_view_dy_to_top_row (tree_view);
6946       return;
6947     }
6948
6949   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6950   new_dy += tree_view->priv->top_row_dy;
6951
6952   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6953     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
6954
6955   new_dy = MAX (0, new_dy);
6956
6957   tree_view->priv->in_top_row_to_dy = TRUE;
6958   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6959   tree_view->priv->in_top_row_to_dy = FALSE;
6960 }
6961
6962
6963 void
6964 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
6965                                             gboolean     install_handler)
6966 {
6967   tree_view->priv->mark_rows_col_dirty = TRUE;
6968
6969   if (install_handler)
6970     install_presize_handler (tree_view);
6971 }
6972
6973 /*
6974  * This function works synchronously (due to the while (validate_rows...)
6975  * loop).
6976  *
6977  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6978  * here. You now need to check that yourself.
6979  */
6980 void
6981 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6982                                 GtkTreeViewColumn *column)
6983 {
6984   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6985   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6986
6987   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6988
6989   do_presize_handler (tree_view);
6990   while (validate_rows (tree_view));
6991
6992   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6993 }
6994
6995 /* Drag-and-drop */
6996
6997 static void
6998 set_source_row (GdkDragContext *context,
6999                 GtkTreeModel   *model,
7000                 GtkTreePath    *source_row)
7001 {
7002   g_object_set_data_full (G_OBJECT (context),
7003                           I_("gtk-tree-view-source-row"),
7004                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7005                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7006 }
7007
7008 static GtkTreePath*
7009 get_source_row (GdkDragContext *context)
7010 {
7011   GtkTreeRowReference *ref =
7012     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7013
7014   if (ref)
7015     return gtk_tree_row_reference_get_path (ref);
7016   else
7017     return NULL;
7018 }
7019
7020 typedef struct
7021 {
7022   GtkTreeRowReference *dest_row;
7023   guint                path_down_mode   : 1;
7024   guint                empty_view_drop  : 1;
7025   guint                drop_append_mode : 1;
7026 }
7027 DestRow;
7028
7029 static void
7030 dest_row_free (gpointer data)
7031 {
7032   DestRow *dr = (DestRow *)data;
7033
7034   gtk_tree_row_reference_free (dr->dest_row);
7035   g_slice_free (DestRow, dr);
7036 }
7037
7038 static void
7039 set_dest_row (GdkDragContext *context,
7040               GtkTreeModel   *model,
7041               GtkTreePath    *dest_row,
7042               gboolean        path_down_mode,
7043               gboolean        empty_view_drop,
7044               gboolean        drop_append_mode)
7045 {
7046   DestRow *dr;
7047
7048   if (!dest_row)
7049     {
7050       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7051                               NULL, NULL);
7052       return;
7053     }
7054
7055   dr = g_slice_new (DestRow);
7056
7057   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7058   dr->path_down_mode = path_down_mode != FALSE;
7059   dr->empty_view_drop = empty_view_drop != FALSE;
7060   dr->drop_append_mode = drop_append_mode != FALSE;
7061
7062   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7063                           dr, (GDestroyNotify) dest_row_free);
7064 }
7065
7066 static GtkTreePath*
7067 get_dest_row (GdkDragContext *context,
7068               gboolean       *path_down_mode)
7069 {
7070   DestRow *dr =
7071     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7072
7073   if (dr)
7074     {
7075       GtkTreePath *path = NULL;
7076
7077       if (path_down_mode)
7078         *path_down_mode = dr->path_down_mode;
7079
7080       if (dr->dest_row)
7081         path = gtk_tree_row_reference_get_path (dr->dest_row);
7082       else if (dr->empty_view_drop)
7083         path = gtk_tree_path_new_from_indices (0, -1);
7084       else
7085         path = NULL;
7086
7087       if (path && dr->drop_append_mode)
7088         gtk_tree_path_next (path);
7089
7090       return path;
7091     }
7092   else
7093     return NULL;
7094 }
7095
7096 /* Get/set whether drag_motion requested the drag data and
7097  * drag_data_received should thus not actually insert the data,
7098  * since the data doesn't result from a drop.
7099  */
7100 static void
7101 set_status_pending (GdkDragContext *context,
7102                     GdkDragAction   suggested_action)
7103 {
7104   g_object_set_data (G_OBJECT (context),
7105                      I_("gtk-tree-view-status-pending"),
7106                      GINT_TO_POINTER (suggested_action));
7107 }
7108
7109 static GdkDragAction
7110 get_status_pending (GdkDragContext *context)
7111 {
7112   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7113                                              "gtk-tree-view-status-pending"));
7114 }
7115
7116 static TreeViewDragInfo*
7117 get_info (GtkTreeView *tree_view)
7118 {
7119   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7120 }
7121
7122 static void
7123 destroy_info (TreeViewDragInfo *di)
7124 {
7125   g_slice_free (TreeViewDragInfo, di);
7126 }
7127
7128 static TreeViewDragInfo*
7129 ensure_info (GtkTreeView *tree_view)
7130 {
7131   TreeViewDragInfo *di;
7132
7133   di = get_info (tree_view);
7134
7135   if (di == NULL)
7136     {
7137       di = g_slice_new0 (TreeViewDragInfo);
7138
7139       g_object_set_data_full (G_OBJECT (tree_view),
7140                               I_("gtk-tree-view-drag-info"),
7141                               di,
7142                               (GDestroyNotify) destroy_info);
7143     }
7144
7145   return di;
7146 }
7147
7148 static void
7149 remove_info (GtkTreeView *tree_view)
7150 {
7151   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7152 }
7153
7154 #if 0
7155 static gint
7156 drag_scan_timeout (gpointer data)
7157 {
7158   GtkTreeView *tree_view;
7159   gint x, y;
7160   GdkModifierType state;
7161   GtkTreePath *path = NULL;
7162   GtkTreeViewColumn *column = NULL;
7163   GdkRectangle visible_rect;
7164
7165   GDK_THREADS_ENTER ();
7166
7167   tree_view = GTK_TREE_VIEW (data);
7168
7169   gdk_window_get_pointer (tree_view->priv->bin_window,
7170                           &x, &y, &state);
7171
7172   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7173
7174   /* See if we are near the edge. */
7175   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7176       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7177       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7178       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7179     {
7180       gtk_tree_view_get_path_at_pos (tree_view,
7181                                      tree_view->priv->bin_window,
7182                                      x, y,
7183                                      &path,
7184                                      &column,
7185                                      NULL,
7186                                      NULL);
7187
7188       if (path != NULL)
7189         {
7190           gtk_tree_view_scroll_to_cell (tree_view,
7191                                         path,
7192                                         column,
7193                                         TRUE,
7194                                         0.5, 0.5);
7195
7196           gtk_tree_path_free (path);
7197         }
7198     }
7199
7200   GDK_THREADS_LEAVE ();
7201
7202   return TRUE;
7203 }
7204 #endif /* 0 */
7205
7206 static void
7207 add_scroll_timeout (GtkTreeView *tree_view)
7208 {
7209   if (tree_view->priv->scroll_timeout == 0)
7210     {
7211       tree_view->priv->scroll_timeout =
7212         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7213     }
7214 }
7215
7216 static void
7217 remove_scroll_timeout (GtkTreeView *tree_view)
7218 {
7219   if (tree_view->priv->scroll_timeout != 0)
7220     {
7221       g_source_remove (tree_view->priv->scroll_timeout);
7222       tree_view->priv->scroll_timeout = 0;
7223     }
7224 }
7225
7226 static gboolean
7227 check_model_dnd (GtkTreeModel *model,
7228                  GType         required_iface,
7229                  const gchar  *signal)
7230 {
7231   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7232     {
7233       g_warning ("You must override the default '%s' handler "
7234                  "on GtkTreeView when using models that don't support "
7235                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7236                  "is to connect to '%s' and call "
7237                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7238                  "the default handler from running. Look at the source code "
7239                  "for the default handler in gtktreeview.c to get an idea what "
7240                  "your handler should do. (gtktreeview.c is in the GTK source "
7241                  "code.) If you're using GTK from a language other than C, "
7242                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7243                  signal, g_type_name (required_iface), signal);
7244       return FALSE;
7245     }
7246   else
7247     return TRUE;
7248 }
7249
7250 static void
7251 remove_open_timeout (GtkTreeView *tree_view)
7252 {
7253   if (tree_view->priv->open_dest_timeout != 0)
7254     {
7255       g_source_remove (tree_view->priv->open_dest_timeout);
7256       tree_view->priv->open_dest_timeout = 0;
7257     }
7258 }
7259
7260
7261 static gint
7262 open_row_timeout (gpointer data)
7263 {
7264   GtkTreeView *tree_view = data;
7265   GtkTreePath *dest_path = NULL;
7266   GtkTreeViewDropPosition pos;
7267   gboolean result = FALSE;
7268
7269   gtk_tree_view_get_drag_dest_row (tree_view,
7270                                    &dest_path,
7271                                    &pos);
7272
7273   if (dest_path &&
7274       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7275        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7276     {
7277       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7278       tree_view->priv->open_dest_timeout = 0;
7279
7280       gtk_tree_path_free (dest_path);
7281     }
7282   else
7283     {
7284       if (dest_path)
7285         gtk_tree_path_free (dest_path);
7286
7287       result = TRUE;
7288     }
7289
7290   return result;
7291 }
7292
7293 static gboolean
7294 scroll_row_timeout (gpointer data)
7295 {
7296   GtkTreeView *tree_view = data;
7297
7298   gtk_tree_view_vertical_autoscroll (tree_view);
7299
7300   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7301     gtk_tree_view_update_rubber_band (tree_view);
7302
7303   return TRUE;
7304 }
7305
7306 /* Returns TRUE if event should not be propagated to parent widgets */
7307 static gboolean
7308 set_destination_row (GtkTreeView    *tree_view,
7309                      GdkDragContext *context,
7310                      /* coordinates relative to the widget */
7311                      gint            x,
7312                      gint            y,
7313                      GdkDragAction  *suggested_action,
7314                      GdkAtom        *target)
7315 {
7316   GtkTreePath *path = NULL;
7317   GtkTreeViewDropPosition pos;
7318   GtkTreeViewDropPosition old_pos;
7319   TreeViewDragInfo *di;
7320   GtkWidget *widget;
7321   GtkTreePath *old_dest_path = NULL;
7322   gboolean can_drop = FALSE;
7323
7324   *suggested_action = 0;
7325   *target = GDK_NONE;
7326
7327   widget = GTK_WIDGET (tree_view);
7328
7329   di = get_info (tree_view);
7330
7331   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7332     {
7333       /* someone unset us as a drag dest, note that if
7334        * we return FALSE drag_leave isn't called
7335        */
7336
7337       gtk_tree_view_set_drag_dest_row (tree_view,
7338                                        NULL,
7339                                        GTK_TREE_VIEW_DROP_BEFORE);
7340
7341       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7342       remove_open_timeout (GTK_TREE_VIEW (widget));
7343
7344       return FALSE; /* no longer a drop site */
7345     }
7346
7347   *target = gtk_drag_dest_find_target (widget, context,
7348                                        gtk_drag_dest_get_target_list (widget));
7349   if (*target == GDK_NONE)
7350     {
7351       return FALSE;
7352     }
7353
7354   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7355                                           x, y,
7356                                           &path,
7357                                           &pos))
7358     {
7359       gint n_children;
7360       GtkTreeModel *model;
7361
7362       remove_open_timeout (tree_view);
7363
7364       /* the row got dropped on empty space, let's setup a special case
7365        */
7366
7367       if (path)
7368         gtk_tree_path_free (path);
7369
7370       model = gtk_tree_view_get_model (tree_view);
7371
7372       n_children = gtk_tree_model_iter_n_children (model, NULL);
7373       if (n_children)
7374         {
7375           pos = GTK_TREE_VIEW_DROP_AFTER;
7376           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7377         }
7378       else
7379         {
7380           pos = GTK_TREE_VIEW_DROP_BEFORE;
7381           path = gtk_tree_path_new_from_indices (0, -1);
7382         }
7383
7384       can_drop = TRUE;
7385
7386       goto out;
7387     }
7388
7389   g_assert (path);
7390
7391   /* If we left the current row's "open" zone, unset the timeout for
7392    * opening the row
7393    */
7394   gtk_tree_view_get_drag_dest_row (tree_view,
7395                                    &old_dest_path,
7396                                    &old_pos);
7397
7398   if (old_dest_path &&
7399       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7400        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7401          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7402     remove_open_timeout (tree_view);
7403
7404   if (old_dest_path)
7405     gtk_tree_path_free (old_dest_path);
7406
7407   if (TRUE /* FIXME if the location droppable predicate */)
7408     {
7409       can_drop = TRUE;
7410     }
7411
7412 out:
7413   if (can_drop)
7414     {
7415       GtkWidget *source_widget;
7416
7417       *suggested_action = gdk_drag_context_get_suggested_action (context);
7418       source_widget = gtk_drag_get_source_widget (context);
7419
7420       if (source_widget == widget)
7421         {
7422           /* Default to MOVE, unless the user has
7423            * pressed ctrl or shift to affect available actions
7424            */
7425           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7426             *suggested_action = GDK_ACTION_MOVE;
7427         }
7428
7429       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7430                                        path, pos);
7431     }
7432   else
7433     {
7434       /* can't drop here */
7435       remove_open_timeout (tree_view);
7436
7437       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7438                                        NULL,
7439                                        GTK_TREE_VIEW_DROP_BEFORE);
7440     }
7441
7442   if (path)
7443     gtk_tree_path_free (path);
7444
7445   return TRUE;
7446 }
7447
7448 static GtkTreePath*
7449 get_logical_dest_row (GtkTreeView *tree_view,
7450                       gboolean    *path_down_mode,
7451                       gboolean    *drop_append_mode)
7452 {
7453   /* adjust path to point to the row the drop goes in front of */
7454   GtkTreePath *path = NULL;
7455   GtkTreeViewDropPosition pos;
7456
7457   g_return_val_if_fail (path_down_mode != NULL, NULL);
7458   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7459
7460   *path_down_mode = FALSE;
7461   *drop_append_mode = 0;
7462
7463   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7464
7465   if (path == NULL)
7466     return NULL;
7467
7468   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7469     ; /* do nothing */
7470   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7471            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7472     *path_down_mode = TRUE;
7473   else
7474     {
7475       GtkTreeIter iter;
7476       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7477
7478       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7479
7480       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7481           !gtk_tree_model_iter_next (model, &iter))
7482         *drop_append_mode = 1;
7483       else
7484         {
7485           *drop_append_mode = 0;
7486           gtk_tree_path_next (path);
7487         }
7488     }
7489
7490   return path;
7491 }
7492
7493 static gboolean
7494 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7495                                         GdkEventMotion   *event)
7496 {
7497   GtkWidget *widget = GTK_WIDGET (tree_view);
7498   GdkDragContext *context;
7499   TreeViewDragInfo *di;
7500   GtkTreePath *path = NULL;
7501   gint button;
7502   gint cell_x, cell_y;
7503   GtkTreeModel *model;
7504   gboolean retval = FALSE;
7505
7506   di = get_info (tree_view);
7507
7508   if (di == NULL || !di->source_set)
7509     goto out;
7510
7511   if (tree_view->priv->pressed_button < 0)
7512     goto out;
7513
7514   if (!gtk_drag_check_threshold (widget,
7515                                  tree_view->priv->press_start_x,
7516                                  tree_view->priv->press_start_y,
7517                                  event->x, event->y))
7518     goto out;
7519
7520   model = gtk_tree_view_get_model (tree_view);
7521
7522   if (model == NULL)
7523     goto out;
7524
7525   button = tree_view->priv->pressed_button;
7526   tree_view->priv->pressed_button = -1;
7527
7528   gtk_tree_view_get_path_at_pos (tree_view,
7529                                  tree_view->priv->press_start_x,
7530                                  tree_view->priv->press_start_y,
7531                                  &path,
7532                                  NULL,
7533                                  &cell_x,
7534                                  &cell_y);
7535
7536   if (path == NULL)
7537     goto out;
7538
7539   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7540       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7541                                            path))
7542     goto out;
7543
7544   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7545     goto out;
7546
7547   /* Now we can begin the drag */
7548
7549   retval = TRUE;
7550
7551   context = gtk_drag_begin (widget,
7552                             gtk_drag_source_get_target_list (widget),
7553                             di->source_actions,
7554                             button,
7555                             (GdkEvent*)event);
7556
7557   set_source_row (context, model, path);
7558
7559  out:
7560   if (path)
7561     gtk_tree_path_free (path);
7562
7563   return retval;
7564 }
7565
7566
7567 static void
7568 gtk_tree_view_drag_begin (GtkWidget      *widget,
7569                           GdkDragContext *context)
7570 {
7571   GtkTreeView *tree_view;
7572   GtkTreePath *path = NULL;
7573   gint cell_x, cell_y;
7574   cairo_surface_t *row_pix;
7575   TreeViewDragInfo *di;
7576
7577   tree_view = GTK_TREE_VIEW (widget);
7578
7579   /* if the user uses a custom DND source impl, we don't set the icon here */
7580   di = get_info (tree_view);
7581
7582   if (di == NULL || !di->source_set)
7583     return;
7584
7585   gtk_tree_view_get_path_at_pos (tree_view,
7586                                  tree_view->priv->press_start_x,
7587                                  tree_view->priv->press_start_y,
7588                                  &path,
7589                                  NULL,
7590                                  &cell_x,
7591                                  &cell_y);
7592
7593   g_return_if_fail (path != NULL);
7594
7595   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7596                                                 path);
7597   cairo_surface_set_device_offset (row_pix,
7598                                    /* the + 1 is for the black border in the icon */
7599                                    - (tree_view->priv->press_start_x + 1),
7600                                    - (cell_y + 1));
7601
7602   gtk_drag_set_icon_surface (context, row_pix);
7603
7604   cairo_surface_destroy (row_pix);
7605   gtk_tree_path_free (path);
7606 }
7607
7608 static void
7609 gtk_tree_view_drag_end (GtkWidget      *widget,
7610                         GdkDragContext *context)
7611 {
7612   /* do nothing */
7613 }
7614
7615 /* Default signal implementations for the drag signals */
7616 static void
7617 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7618                              GdkDragContext   *context,
7619                              GtkSelectionData *selection_data,
7620                              guint             info,
7621                              guint             time)
7622 {
7623   GtkTreeView *tree_view;
7624   GtkTreeModel *model;
7625   TreeViewDragInfo *di;
7626   GtkTreePath *source_row;
7627
7628   tree_view = GTK_TREE_VIEW (widget);
7629
7630   model = gtk_tree_view_get_model (tree_view);
7631
7632   if (model == NULL)
7633     return;
7634
7635   di = get_info (GTK_TREE_VIEW (widget));
7636
7637   if (di == NULL)
7638     return;
7639
7640   source_row = get_source_row (context);
7641
7642   if (source_row == NULL)
7643     return;
7644
7645   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7646    * any model; for DragSource models there are some other targets
7647    * we also support.
7648    */
7649
7650   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7651       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7652                                           source_row,
7653                                           selection_data))
7654     goto done;
7655
7656   /* If drag_data_get does nothing, try providing row data. */
7657   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7658     {
7659       gtk_tree_set_row_drag_data (selection_data,
7660                                   model,
7661                                   source_row);
7662     }
7663
7664  done:
7665   gtk_tree_path_free (source_row);
7666 }
7667
7668
7669 static void
7670 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7671                                 GdkDragContext *context)
7672 {
7673   TreeViewDragInfo *di;
7674   GtkTreeModel *model;
7675   GtkTreeView *tree_view;
7676   GtkTreePath *source_row;
7677
7678   tree_view = GTK_TREE_VIEW (widget);
7679   model = gtk_tree_view_get_model (tree_view);
7680
7681   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7682     return;
7683
7684   di = get_info (tree_view);
7685
7686   if (di == NULL)
7687     return;
7688
7689   source_row = get_source_row (context);
7690
7691   if (source_row == NULL)
7692     return;
7693
7694   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7695                                          source_row);
7696
7697   gtk_tree_path_free (source_row);
7698
7699   set_source_row (context, NULL, NULL);
7700 }
7701
7702 static void
7703 gtk_tree_view_drag_leave (GtkWidget      *widget,
7704                           GdkDragContext *context,
7705                           guint             time)
7706 {
7707   /* unset any highlight row */
7708   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7709                                    NULL,
7710                                    GTK_TREE_VIEW_DROP_BEFORE);
7711
7712   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7713   remove_open_timeout (GTK_TREE_VIEW (widget));
7714 }
7715
7716
7717 static gboolean
7718 gtk_tree_view_drag_motion (GtkWidget        *widget,
7719                            GdkDragContext   *context,
7720                            /* coordinates relative to the widget */
7721                            gint              x,
7722                            gint              y,
7723                            guint             time)
7724 {
7725   gboolean empty;
7726   GtkTreePath *path = NULL;
7727   GtkTreeViewDropPosition pos;
7728   GtkTreeView *tree_view;
7729   GdkDragAction suggested_action = 0;
7730   GdkAtom target;
7731
7732   tree_view = GTK_TREE_VIEW (widget);
7733
7734   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7735     return FALSE;
7736
7737   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7738
7739   /* we only know this *after* set_desination_row */
7740   empty = tree_view->priv->empty_view_drop;
7741
7742   if (path == NULL && !empty)
7743     {
7744       /* Can't drop here. */
7745       gdk_drag_status (context, 0, time);
7746     }
7747   else
7748     {
7749       if (tree_view->priv->open_dest_timeout == 0 &&
7750           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7751            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7752         {
7753           tree_view->priv->open_dest_timeout =
7754             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7755         }
7756       else
7757         {
7758           add_scroll_timeout (tree_view);
7759         }
7760
7761       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7762         {
7763           /* Request data so we can use the source row when
7764            * determining whether to accept the drop
7765            */
7766           set_status_pending (context, suggested_action);
7767           gtk_drag_get_data (widget, context, target, time);
7768         }
7769       else
7770         {
7771           set_status_pending (context, 0);
7772           gdk_drag_status (context, suggested_action, time);
7773         }
7774     }
7775
7776   if (path)
7777     gtk_tree_path_free (path);
7778
7779   return TRUE;
7780 }
7781
7782
7783 static gboolean
7784 gtk_tree_view_drag_drop (GtkWidget        *widget,
7785                          GdkDragContext   *context,
7786                          /* coordinates relative to the widget */
7787                          gint              x,
7788                          gint              y,
7789                          guint             time)
7790 {
7791   GtkTreeView *tree_view;
7792   GtkTreePath *path;
7793   GdkDragAction suggested_action = 0;
7794   GdkAtom target = GDK_NONE;
7795   TreeViewDragInfo *di;
7796   GtkTreeModel *model;
7797   gboolean path_down_mode;
7798   gboolean drop_append_mode;
7799
7800   tree_view = GTK_TREE_VIEW (widget);
7801
7802   model = gtk_tree_view_get_model (tree_view);
7803
7804   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7805   remove_open_timeout (GTK_TREE_VIEW (widget));
7806
7807   di = get_info (tree_view);
7808
7809   if (di == NULL)
7810     return FALSE;
7811
7812   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7813     return FALSE;
7814
7815   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7816     return FALSE;
7817
7818   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7819
7820   if (target != GDK_NONE && path != NULL)
7821     {
7822       /* in case a motion had requested drag data, change things so we
7823        * treat drag data receives as a drop.
7824        */
7825       set_status_pending (context, 0);
7826       set_dest_row (context, model, path,
7827                     path_down_mode, tree_view->priv->empty_view_drop,
7828                     drop_append_mode);
7829     }
7830
7831   if (path)
7832     gtk_tree_path_free (path);
7833
7834   /* Unset this thing */
7835   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7836                                    NULL,
7837                                    GTK_TREE_VIEW_DROP_BEFORE);
7838
7839   if (target != GDK_NONE)
7840     {
7841       gtk_drag_get_data (widget, context, target, time);
7842       return TRUE;
7843     }
7844   else
7845     return FALSE;
7846 }
7847
7848 static void
7849 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7850                                   GdkDragContext   *context,
7851                                   /* coordinates relative to the widget */
7852                                   gint              x,
7853                                   gint              y,
7854                                   GtkSelectionData *selection_data,
7855                                   guint             info,
7856                                   guint             time)
7857 {
7858   GtkTreePath *path;
7859   TreeViewDragInfo *di;
7860   gboolean accepted = FALSE;
7861   GtkTreeModel *model;
7862   GtkTreeView *tree_view;
7863   GtkTreePath *dest_row;
7864   GdkDragAction suggested_action;
7865   gboolean path_down_mode;
7866   gboolean drop_append_mode;
7867
7868   tree_view = GTK_TREE_VIEW (widget);
7869
7870   model = gtk_tree_view_get_model (tree_view);
7871
7872   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7873     return;
7874
7875   di = get_info (tree_view);
7876
7877   if (di == NULL)
7878     return;
7879
7880   suggested_action = get_status_pending (context);
7881
7882   if (suggested_action)
7883     {
7884       /* We are getting this data due to a request in drag_motion,
7885        * rather than due to a request in drag_drop, so we are just
7886        * supposed to call drag_status, not actually paste in the
7887        * data.
7888        */
7889       path = get_logical_dest_row (tree_view, &path_down_mode,
7890                                    &drop_append_mode);
7891
7892       if (path == NULL)
7893         suggested_action = 0;
7894       else if (path_down_mode)
7895         gtk_tree_path_down (path);
7896
7897       if (suggested_action)
7898         {
7899           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7900                                                      path,
7901                                                      selection_data))
7902             {
7903               if (path_down_mode)
7904                 {
7905                   path_down_mode = FALSE;
7906                   gtk_tree_path_up (path);
7907
7908                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7909                                                              path,
7910                                                              selection_data))
7911                     suggested_action = 0;
7912                 }
7913               else
7914                 suggested_action = 0;
7915             }
7916         }
7917
7918       gdk_drag_status (context, suggested_action, time);
7919
7920       if (path)
7921         gtk_tree_path_free (path);
7922
7923       /* If you can't drop, remove user drop indicator until the next motion */
7924       if (suggested_action == 0)
7925         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7926                                          NULL,
7927                                          GTK_TREE_VIEW_DROP_BEFORE);
7928
7929       return;
7930     }
7931
7932   dest_row = get_dest_row (context, &path_down_mode);
7933
7934   if (dest_row == NULL)
7935     return;
7936
7937   if (gtk_selection_data_get_length (selection_data) >= 0)
7938     {
7939       if (path_down_mode)
7940         {
7941           gtk_tree_path_down (dest_row);
7942           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7943                                                      dest_row, selection_data))
7944             gtk_tree_path_up (dest_row);
7945         }
7946     }
7947
7948   if (gtk_selection_data_get_length (selection_data) >= 0)
7949     {
7950       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7951                                                  dest_row,
7952                                                  selection_data))
7953         accepted = TRUE;
7954     }
7955
7956   gtk_drag_finish (context,
7957                    accepted,
7958                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
7959                    time);
7960
7961   if (gtk_tree_path_get_depth (dest_row) == 1
7962       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7963     {
7964       /* special special case drag to "0", scroll to first item */
7965       if (!tree_view->priv->scroll_to_path)
7966         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7967     }
7968
7969   gtk_tree_path_free (dest_row);
7970
7971   /* drop dest_row */
7972   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7973 }
7974
7975
7976
7977 /* GtkContainer Methods
7978  */
7979
7980
7981 static void
7982 gtk_tree_view_remove (GtkContainer *container,
7983                       GtkWidget    *widget)
7984 {
7985   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7986   GtkTreeViewChild *child = NULL;
7987   GList *tmp_list;
7988
7989   tmp_list = tree_view->priv->children;
7990   while (tmp_list)
7991     {
7992       child = tmp_list->data;
7993       if (child->widget == widget)
7994         {
7995           gtk_widget_unparent (widget);
7996
7997           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7998           g_list_free_1 (tmp_list);
7999           g_slice_free (GtkTreeViewChild, child);
8000           return;
8001         }
8002
8003       tmp_list = tmp_list->next;
8004     }
8005
8006   tmp_list = tree_view->priv->columns;
8007
8008   while (tmp_list)
8009     {
8010       GtkTreeViewColumn *column;
8011       GtkWidget         *button;
8012
8013       column = tmp_list->data;
8014       button = gtk_tree_view_column_get_button (column);
8015
8016       if (button == widget)
8017         {
8018           gtk_widget_unparent (widget);
8019           return;
8020         }
8021       tmp_list = tmp_list->next;
8022     }
8023 }
8024
8025 static void
8026 gtk_tree_view_forall (GtkContainer *container,
8027                       gboolean      include_internals,
8028                       GtkCallback   callback,
8029                       gpointer      callback_data)
8030 {
8031   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8032   GtkTreeViewChild *child = NULL;
8033   GtkTreeViewColumn *column;
8034   GtkWidget *button;
8035   GList *tmp_list;
8036
8037   tmp_list = tree_view->priv->children;
8038   while (tmp_list)
8039     {
8040       child = tmp_list->data;
8041       tmp_list = tmp_list->next;
8042
8043       (* callback) (child->widget, callback_data);
8044     }
8045   if (include_internals == FALSE)
8046     return;
8047
8048   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8049     {
8050       column = tmp_list->data;
8051       button = gtk_tree_view_column_get_button (column);
8052
8053       if (button)
8054         (* callback) (button, callback_data);
8055     }
8056 }
8057
8058 /* Returns TRUE is any of the columns contains a cell that can-focus.
8059  * If this is not the case, a column-spanning focus rectangle will be
8060  * drawn.
8061  */
8062 static gboolean
8063 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8064 {
8065   GList *list;
8066
8067   for (list = tree_view->priv->columns; list; list = list->next)
8068     {
8069       GtkTreeViewColumn *column = list->data;
8070
8071       if (!gtk_tree_view_column_get_visible (column))
8072         continue;
8073       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8074         return TRUE;
8075     }
8076
8077   return FALSE;
8078 }
8079
8080 static void
8081 column_sizing_notify (GObject    *object,
8082                       GParamSpec *pspec,
8083                       gpointer    data)
8084 {
8085   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8086
8087   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8088     /* disable fixed height mode */
8089     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8090 }
8091
8092 /**
8093  * gtk_tree_view_set_fixed_height_mode:
8094  * @tree_view: a #GtkTreeView 
8095  * @enable: %TRUE to enable fixed height mode
8096  * 
8097  * Enables or disables the fixed height mode of @tree_view. 
8098  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8099  * rows have the same height. 
8100  * Only enable this option if all rows are the same height and all
8101  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8102  *
8103  * Since: 2.6 
8104  **/
8105 void
8106 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8107                                      gboolean     enable)
8108 {
8109   GList *l;
8110   
8111   enable = enable != FALSE;
8112
8113   if (enable == tree_view->priv->fixed_height_mode)
8114     return;
8115
8116   if (!enable)
8117     {
8118       tree_view->priv->fixed_height_mode = 0;
8119       tree_view->priv->fixed_height = -1;
8120
8121       /* force a revalidation */
8122       install_presize_handler (tree_view);
8123     }
8124   else 
8125     {
8126       /* make sure all columns are of type FIXED */
8127       for (l = tree_view->priv->columns; l; l = l->next)
8128         {
8129           GtkTreeViewColumn *c = l->data;
8130           
8131           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8132         }
8133       
8134       /* yes, we really have to do this is in a separate loop */
8135       for (l = tree_view->priv->columns; l; l = l->next)
8136         g_signal_connect (l->data, "notify::sizing",
8137                           G_CALLBACK (column_sizing_notify), tree_view);
8138       
8139       tree_view->priv->fixed_height_mode = 1;
8140       tree_view->priv->fixed_height = -1;
8141       
8142       if (tree_view->priv->tree)
8143         initialize_fixed_height_mode (tree_view);
8144     }
8145
8146   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8147 }
8148
8149 /**
8150  * gtk_tree_view_get_fixed_height_mode:
8151  * @tree_view: a #GtkTreeView
8152  * 
8153  * Returns whether fixed height mode is turned on for @tree_view.
8154  * 
8155  * Return value: %TRUE if @tree_view is in fixed height mode
8156  * 
8157  * Since: 2.6
8158  **/
8159 gboolean
8160 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8161 {
8162   return tree_view->priv->fixed_height_mode;
8163 }
8164
8165 /* Returns TRUE if the focus is within the headers, after the focus operation is
8166  * done
8167  */
8168 static gboolean
8169 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8170                             GtkDirectionType  dir,
8171                             gboolean          clamp_column_visible)
8172 {
8173   GtkTreeViewColumn *column;
8174   GtkWidget *focus_child;
8175   GtkWidget *button;
8176   GList *last_column, *first_column;
8177   GList *tmp_list;
8178   gboolean rtl;
8179
8180   if (! tree_view->priv->headers_visible)
8181     return FALSE;
8182
8183   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8184
8185   first_column = tree_view->priv->columns;
8186   while (first_column)
8187     {
8188       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8189       button = gtk_tree_view_column_get_button (column);
8190
8191       if (gtk_widget_get_can_focus (button) &&
8192           gtk_tree_view_column_get_visible (column) &&
8193           (gtk_tree_view_column_get_clickable (column) ||
8194            gtk_tree_view_column_get_reorderable (column)))
8195         break;
8196       first_column = first_column->next;
8197     }
8198
8199   /* No headers are visible, or are focusable.  We can't focus in or out.
8200    */
8201   if (first_column == NULL)
8202     return FALSE;
8203
8204   last_column = g_list_last (tree_view->priv->columns);
8205   while (last_column)
8206     {
8207       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8208       button = gtk_tree_view_column_get_button (column);
8209
8210       if (gtk_widget_get_can_focus (button) &&
8211           gtk_tree_view_column_get_visible (column) &&
8212           (gtk_tree_view_column_get_clickable (column) ||
8213            gtk_tree_view_column_get_reorderable (column)))
8214         break;
8215       last_column = last_column->prev;
8216     }
8217
8218
8219   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8220
8221   switch (dir)
8222     {
8223     case GTK_DIR_TAB_BACKWARD:
8224     case GTK_DIR_TAB_FORWARD:
8225     case GTK_DIR_UP:
8226     case GTK_DIR_DOWN:
8227       if (focus_child == NULL)
8228         {
8229           if (tree_view->priv->focus_column != NULL)
8230             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8231           else 
8232             button = NULL;
8233
8234           if (button && gtk_widget_get_can_focus (button))
8235             focus_child = button;
8236           else
8237             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8238
8239           gtk_widget_grab_focus (focus_child);
8240           break;
8241         }
8242       return FALSE;
8243
8244     case GTK_DIR_LEFT:
8245     case GTK_DIR_RIGHT:
8246       if (focus_child == NULL)
8247         {
8248           if (tree_view->priv->focus_column != NULL)
8249             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8250           else if (dir == GTK_DIR_LEFT)
8251             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8252           else
8253             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8254
8255           gtk_widget_grab_focus (focus_child);
8256           break;
8257         }
8258
8259       if (gtk_widget_child_focus (focus_child, dir))
8260         {
8261           /* The focus moves inside the button. */
8262           /* This is probably a great example of bad UI */
8263           break;
8264         }
8265
8266       /* We need to move the focus among the row of buttons. */
8267       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8268         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8269           break;
8270
8271       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8272           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8273         {
8274           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8275           break;
8276         }
8277
8278       while (tmp_list)
8279         {
8280           GtkTreeViewColumn *column;
8281           GtkWidget         *button;
8282
8283           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8284             tmp_list = tmp_list->next;
8285           else
8286             tmp_list = tmp_list->prev;
8287
8288           if (tmp_list == NULL)
8289             {
8290               g_warning ("Internal button not found");
8291               break;
8292             }
8293           column = tmp_list->data;
8294           button = gtk_tree_view_column_get_button (column);
8295           if (button &&
8296               gtk_tree_view_column_get_visible (column) &&
8297               gtk_widget_get_can_focus (button))
8298             {
8299               focus_child = button;
8300               gtk_widget_grab_focus (button);
8301               break;
8302             }
8303         }
8304       break;
8305     default:
8306       g_assert_not_reached ();
8307       break;
8308     }
8309
8310   /* if focus child is non-null, we assume it's been set to the current focus child
8311    */
8312   if (focus_child)
8313     {
8314       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8315         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8316           {
8317             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8318             break;
8319           }
8320
8321       if (clamp_column_visible)
8322         {
8323           gtk_tree_view_clamp_column_visible (tree_view,
8324                                               tree_view->priv->focus_column,
8325                                               FALSE);
8326         }
8327     }
8328
8329   return (focus_child != NULL);
8330 }
8331
8332 /* This function returns in 'path' the first focusable path, if the given path
8333  * is already focusable, it's the returned one.
8334  */
8335 static gboolean
8336 search_first_focusable_path (GtkTreeView  *tree_view,
8337                              GtkTreePath **path,
8338                              gboolean      search_forward,
8339                              GtkRBTree   **new_tree,
8340                              GtkRBNode   **new_node)
8341 {
8342   GtkRBTree *tree = NULL;
8343   GtkRBNode *node = NULL;
8344
8345   if (!path || !*path)
8346     return FALSE;
8347
8348   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8349
8350   if (!tree || !node)
8351     return FALSE;
8352
8353   while (node && row_is_separator (tree_view, NULL, *path))
8354     {
8355       if (search_forward)
8356         _gtk_rbtree_next_full (tree, node, &tree, &node);
8357       else
8358         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8359
8360       if (*path)
8361         gtk_tree_path_free (*path);
8362
8363       if (node)
8364         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8365       else
8366         *path = NULL;
8367     }
8368
8369   if (new_tree)
8370     *new_tree = tree;
8371
8372   if (new_node)
8373     *new_node = node;
8374
8375   return (*path != NULL);
8376 }
8377
8378 static gint
8379 gtk_tree_view_focus (GtkWidget        *widget,
8380                      GtkDirectionType  direction)
8381 {
8382   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8383   GtkContainer *container = GTK_CONTAINER (widget);
8384   GtkWidget *focus_child;
8385
8386   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8387     return FALSE;
8388
8389   focus_child = gtk_container_get_focus_child (container);
8390
8391   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8392   /* Case 1.  Headers currently have focus. */
8393   if (focus_child)
8394     {
8395       switch (direction)
8396         {
8397         case GTK_DIR_LEFT:
8398         case GTK_DIR_RIGHT:
8399           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8400           return TRUE;
8401         case GTK_DIR_TAB_BACKWARD:
8402         case GTK_DIR_UP:
8403           return FALSE;
8404         case GTK_DIR_TAB_FORWARD:
8405         case GTK_DIR_DOWN:
8406           gtk_widget_grab_focus (widget);
8407           return TRUE;
8408         default:
8409           g_assert_not_reached ();
8410           return FALSE;
8411         }
8412     }
8413
8414   /* Case 2. We don't have focus at all. */
8415   if (!gtk_widget_has_focus (widget))
8416     {
8417       gtk_widget_grab_focus (widget);
8418       return TRUE;
8419     }
8420
8421   /* Case 3. We have focus already. */
8422   if (direction == GTK_DIR_TAB_BACKWARD)
8423     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8424   else if (direction == GTK_DIR_TAB_FORWARD)
8425     return FALSE;
8426
8427   /* Other directions caught by the keybindings */
8428   gtk_widget_grab_focus (widget);
8429   return TRUE;
8430 }
8431
8432 static void
8433 gtk_tree_view_grab_focus (GtkWidget *widget)
8434 {
8435   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8436
8437   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8438 }
8439
8440 static void
8441 gtk_tree_view_style_updated (GtkWidget *widget)
8442 {
8443   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8444   GList *list;
8445   GtkTreeViewColumn *column;
8446
8447   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8448
8449   if (gtk_widget_get_realized (widget))
8450     {
8451       GtkStyleContext *context;
8452
8453       context = gtk_widget_get_style_context (widget);
8454
8455       gtk_style_context_save (context);
8456       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
8457       gtk_style_context_set_background (context, tree_view->priv->bin_window);
8458       gtk_style_context_restore (context);
8459
8460       gtk_style_context_set_background (context, tree_view->priv->header_window);
8461
8462       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8463       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8464     }
8465
8466   gtk_widget_style_get (widget,
8467                         "expander-size", &tree_view->priv->expander_size,
8468                         NULL);
8469   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8470
8471   for (list = tree_view->priv->columns; list; list = list->next)
8472     {
8473       column = list->data;
8474       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8475     }
8476
8477   tree_view->priv->fixed_height = -1;
8478   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8479
8480   gtk_widget_queue_resize (widget);
8481 }
8482
8483
8484 static void
8485 gtk_tree_view_set_focus_child (GtkContainer *container,
8486                                GtkWidget    *child)
8487 {
8488   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8489   GList *list;
8490
8491   for (list = tree_view->priv->columns; list; list = list->next)
8492     {
8493       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8494         {
8495           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8496           break;
8497         }
8498     }
8499
8500   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8501 }
8502
8503 static GtkWidgetPath *
8504 gtk_tree_view_get_path_for_child (GtkContainer *container,
8505                                   GtkWidget    *child)
8506 {
8507   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8508   GtkWidgetPath *path;
8509   gboolean rtl;
8510   GList *list;
8511   gint n_col = 0;
8512
8513   path = GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->get_path_for_child (container, child);
8514   rtl = (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL);
8515
8516   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8517        list;
8518        list = (rtl ? list->prev : list->next))
8519     {
8520       GtkTreeViewColumn *column = list->data;
8521       GtkRegionFlags flags = 0;
8522
8523       if (!gtk_tree_view_column_get_visible (column))
8524         continue;
8525
8526       n_col++;
8527
8528       if (gtk_tree_view_column_get_widget (column) != child &&
8529           gtk_tree_view_column_get_button (column) != child)
8530         continue;
8531
8532       if ((n_col % 2) == 0)
8533         flags |= GTK_REGION_EVEN;
8534       else
8535         flags |= GTK_REGION_ODD;
8536
8537       if (n_col == 1)
8538         flags |= GTK_REGION_FIRST;
8539
8540       if ((rtl && !list->prev) ||
8541           (!rtl && !list->next))
8542         flags |= GTK_REGION_LAST;
8543
8544       gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_COLUMN_HEADER, flags);
8545       break;
8546     }
8547
8548   gtk_widget_path_append_for_widget (path, child);
8549
8550   return path;
8551 }
8552
8553 static gboolean
8554 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8555                                 GtkMovementStep    step,
8556                                 gint               count)
8557 {
8558   GdkModifierType state;
8559
8560   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8561   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8562                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8563                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8564                         step == GTK_MOVEMENT_PAGES ||
8565                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8566
8567   if (tree_view->priv->tree == NULL)
8568     return FALSE;
8569   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8570     return FALSE;
8571
8572   gtk_tree_view_stop_editing (tree_view, FALSE);
8573   tree_view->priv->draw_keyfocus = TRUE;
8574   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8575
8576   if (gtk_get_current_event_state (&state))
8577     {
8578       GdkModifierType extend_mod_mask;
8579       GdkModifierType modify_mod_mask;
8580
8581       extend_mod_mask =
8582         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8583                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION);
8584
8585       modify_mod_mask =
8586         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8587                                       GDK_MODIFIER_INTENT_MODIFY_SELECTION);
8588
8589       if ((state & modify_mod_mask) == modify_mod_mask)
8590         tree_view->priv->modify_selection_pressed = TRUE;
8591       if ((state & extend_mod_mask) == extend_mod_mask)
8592         tree_view->priv->extend_selection_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->modify_selection_pressed = FALSE;
8617   tree_view->priv->extend_selection_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   GtkStyleContext *context;
8992
8993   g_return_if_fail (path != NULL);
8994
8995   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8996
8997   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8998     return;
8999
9000   if (tree == NULL)
9001     return;
9002
9003   /* check if the selection has been changed */
9004   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
9005                         check_selection_helper, &selection_changed);
9006
9007   for (list = tree_view->priv->columns; list; list = list->next)
9008     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
9009         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9010       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
9011
9012   /* Ensure we don't have a dangling pointer to a dead node */
9013   ensure_unprelighted (tree_view);
9014
9015   /* Cancel editting if we've started */
9016   gtk_tree_view_stop_editing (tree_view, TRUE);
9017
9018   if (tree_view->priv->destroy_count_func)
9019     {
9020       gint child_count = 0;
9021       if (node->children)
9022         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9023       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9024     }
9025
9026   if (tree->root->count == 1)
9027     {
9028       if (tree_view->priv->tree == tree)
9029         tree_view->priv->tree = NULL;
9030
9031       _gtk_rbtree_remove (tree);
9032     }
9033   else
9034     {
9035       _gtk_rbtree_remove_node (tree, node);
9036     }
9037
9038   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9039     {
9040       gtk_tree_row_reference_free (tree_view->priv->top_row);
9041       tree_view->priv->top_row = NULL;
9042     }
9043
9044   /* Cancel any ongoing animation happening within the row */
9045   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
9046   gtk_style_context_cancel_animations (context, node);
9047
9048   install_scroll_sync_handler (tree_view);
9049
9050   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9051
9052   if (selection_changed)
9053     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9054 }
9055
9056 static void
9057 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9058                               GtkTreePath  *parent,
9059                               GtkTreeIter  *iter,
9060                               gint         *new_order,
9061                               gpointer      data)
9062 {
9063   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9064   GtkRBTree *tree;
9065   GtkRBNode *node;
9066   gint len;
9067
9068   len = gtk_tree_model_iter_n_children (model, iter);
9069
9070   if (len < 2)
9071     return;
9072
9073   gtk_tree_row_reference_reordered (G_OBJECT (data),
9074                                     parent,
9075                                     iter,
9076                                     new_order);
9077
9078   if (_gtk_tree_view_find_node (tree_view,
9079                                 parent,
9080                                 &tree,
9081                                 &node))
9082     return;
9083
9084   /* We need to special case the parent path */
9085   if (tree == NULL)
9086     tree = tree_view->priv->tree;
9087   else
9088     tree = node->children;
9089
9090   if (tree == NULL)
9091     return;
9092
9093   if (tree_view->priv->edited_column)
9094     gtk_tree_view_stop_editing (tree_view, TRUE);
9095
9096   /* we need to be unprelighted */
9097   ensure_unprelighted (tree_view);
9098
9099   _gtk_rbtree_reorder (tree, new_order, len);
9100
9101   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9102
9103   gtk_tree_view_dy_to_top_row (tree_view);
9104 }
9105
9106
9107 /* Internal tree functions
9108  */
9109
9110
9111 static void
9112 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9113                                      GtkRBTree         *tree,
9114                                      GtkTreeViewColumn *column,
9115                                      gint              *x1,
9116                                      gint              *x2)
9117 {
9118   GtkTreeViewColumn *tmp_column = NULL;
9119   gint total_width;
9120   GList *list;
9121   gboolean rtl;
9122
9123   if (x1)
9124     *x1 = 0;
9125
9126   if (x2)
9127     *x2 = 0;
9128
9129   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9130
9131   total_width = 0;
9132   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9133        list;
9134        list = (rtl ? list->prev : list->next))
9135     {
9136       tmp_column = list->data;
9137
9138       if (tmp_column == column)
9139         break;
9140
9141       if (gtk_tree_view_column_get_visible (tmp_column))
9142         total_width += gtk_tree_view_column_get_width (tmp_column);
9143     }
9144
9145   if (tmp_column != column)
9146     {
9147       g_warning (G_STRLOC": passed-in column isn't in the tree");
9148       return;
9149     }
9150
9151   if (x1)
9152     *x1 = total_width;
9153
9154   if (x2)
9155     {
9156       if (gtk_tree_view_column_get_visible (column))
9157         *x2 = total_width + gtk_tree_view_column_get_width (column);
9158       else
9159         *x2 = total_width; /* width of 0 */
9160     }
9161 }
9162
9163 static void
9164 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9165                                 GtkRBTree   *tree,
9166                                 gint        *x1,
9167                                 gint        *x2)
9168 {
9169   gint x_offset = 0;
9170   GList *list;
9171   GtkTreeViewColumn *tmp_column = NULL;
9172   gint total_width;
9173   gboolean indent_expanders;
9174   gboolean rtl;
9175
9176   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9177
9178   total_width = 0;
9179   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9180        list;
9181        list = (rtl ? list->prev : list->next))
9182     {
9183       tmp_column = list->data;
9184
9185       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9186         {
9187           if (rtl)
9188             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - tree_view->priv->expander_size;
9189           else
9190             x_offset = total_width;
9191           break;
9192         }
9193
9194       if (gtk_tree_view_column_get_visible (tmp_column))
9195         total_width += gtk_tree_view_column_get_width (tmp_column);
9196     }
9197
9198   gtk_widget_style_get (GTK_WIDGET (tree_view),
9199                         "indent-expanders", &indent_expanders,
9200                         NULL);
9201
9202   if (indent_expanders)
9203     {
9204       if (rtl)
9205         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9206       else
9207         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9208     }
9209
9210   *x1 = x_offset;
9211
9212   if (tmp_column &&
9213       gtk_tree_view_column_get_visible (tmp_column))
9214     /* +1 because x2 isn't included in the range. */
9215     *x2 = *x1 + tree_view->priv->expander_size + 1;
9216   else
9217     *x2 = *x1;
9218 }
9219
9220 static void
9221 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9222                           GtkRBTree   *tree,
9223                           GtkTreeIter *iter,
9224                           gint         depth,
9225                           gboolean     recurse)
9226 {
9227   GtkRBNode *temp = NULL;
9228   GtkTreePath *path = NULL;
9229
9230   do
9231     {
9232       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9233       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9234
9235       if (tree_view->priv->fixed_height > 0)
9236         {
9237           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9238             {
9239               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9240               _gtk_rbtree_node_mark_valid (tree, temp);
9241             }
9242         }
9243
9244       if (tree_view->priv->is_list)
9245         continue;
9246
9247       if (recurse)
9248         {
9249           GtkTreeIter child;
9250
9251           if (!path)
9252             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9253           else
9254             gtk_tree_path_next (path);
9255
9256           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9257             {
9258               gboolean expand;
9259
9260               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9261
9262               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9263                   && !expand)
9264                 {
9265                   temp->children = _gtk_rbtree_new ();
9266                   temp->children->parent_tree = tree;
9267                   temp->children->parent_node = temp;
9268                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9269                 }
9270             }
9271         }
9272
9273       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9274         {
9275           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9276             temp->flags ^= GTK_RBNODE_IS_PARENT;
9277         }
9278     }
9279   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9280
9281   if (path)
9282     gtk_tree_path_free (path);
9283 }
9284
9285 /* Make sure the node is visible vertically */
9286 static void
9287 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9288                                   GtkRBTree   *tree,
9289                                   GtkRBNode   *node)
9290 {
9291   gint node_dy, height;
9292   GtkTreePath *path = NULL;
9293
9294   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9295     return;
9296
9297   /* just return if the node is visible, avoiding a costly expose */
9298   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9299   height = gtk_tree_view_get_row_height (tree_view, node);
9300   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9301       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9302       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9303                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9304     return;
9305
9306   path = _gtk_tree_view_find_path (tree_view, tree, node);
9307   if (path)
9308     {
9309       /* We process updates because we want to clear old selected items when we scroll.
9310        * if this is removed, we get a "selection streak" at the bottom. */
9311       gtk_tree_view_bin_process_updates (tree_view);
9312
9313       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9314       gtk_tree_path_free (path);
9315     }
9316 }
9317
9318 static void
9319 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9320                                     GtkTreeViewColumn *column,
9321                                     gboolean           focus_to_cell)
9322 {
9323   GtkAllocation allocation;
9324   gint x, width;
9325
9326   if (column == NULL)
9327     return;
9328
9329   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9330   x = allocation.x;
9331   width = allocation.width;
9332
9333   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9334     {
9335       /* The column is larger than the horizontal page size.  If the
9336        * column has cells which can be focussed individually, then we make
9337        * sure the cell which gets focus is fully visible (if even the
9338        * focus cell is bigger than the page size, we make sure the
9339        * left-hand side of the cell is visible).
9340        *
9341        * If the column does not have an activatable cell, we
9342        * make sure the left-hand side of the column is visible.
9343        */
9344
9345       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9346         {
9347           GtkCellArea *cell_area;
9348           GtkCellRenderer *focus_cell;
9349
9350           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9351           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9352
9353           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9354                                                       &x, &width))
9355             {
9356               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9357                 {
9358                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9359                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9360                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9361                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9362                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9363                 }
9364             }
9365         }
9366
9367       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9368     }
9369   else
9370     {
9371       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9372           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9373                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9374       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9375         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9376   }
9377 }
9378
9379 /* This function could be more efficient.  I'll optimize it if profiling seems
9380  * to imply that it is important */
9381 GtkTreePath *
9382 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9383                           GtkRBTree   *tree,
9384                           GtkRBNode   *node)
9385 {
9386   GtkTreePath *path;
9387   GtkRBTree *tmp_tree;
9388   GtkRBNode *tmp_node, *last;
9389   gint count;
9390
9391   path = gtk_tree_path_new ();
9392
9393   g_return_val_if_fail (node != NULL, path);
9394   g_return_val_if_fail (node != tree->nil, path);
9395
9396   count = 1 + node->left->count;
9397
9398   last = node;
9399   tmp_node = node->parent;
9400   tmp_tree = tree;
9401   while (tmp_tree)
9402     {
9403       while (tmp_node != tmp_tree->nil)
9404         {
9405           if (tmp_node->right == last)
9406             count += 1 + tmp_node->left->count;
9407           last = tmp_node;
9408           tmp_node = tmp_node->parent;
9409         }
9410       gtk_tree_path_prepend_index (path, count - 1);
9411       last = tmp_tree->parent_node;
9412       tmp_tree = tmp_tree->parent_tree;
9413       if (last)
9414         {
9415           count = 1 + last->left->count;
9416           tmp_node = last->parent;
9417         }
9418     }
9419   return path;
9420 }
9421
9422 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9423  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9424  * both set to NULL.
9425  */
9426 gboolean
9427 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9428                           GtkTreePath  *path,
9429                           GtkRBTree   **tree,
9430                           GtkRBNode   **node)
9431 {
9432   GtkRBNode *tmpnode = NULL;
9433   GtkRBTree *tmptree = tree_view->priv->tree;
9434   gint *indices = gtk_tree_path_get_indices (path);
9435   gint depth = gtk_tree_path_get_depth (path);
9436   gint i = 0;
9437
9438   *node = NULL;
9439   *tree = NULL;
9440
9441   if (depth == 0 || tmptree == NULL)
9442     return FALSE;
9443   do
9444     {
9445       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9446       ++i;
9447       if (tmpnode == NULL)
9448         {
9449           *tree = NULL;
9450           *node = NULL;
9451           return FALSE;
9452         }
9453       if (i >= depth)
9454         {
9455           *tree = tmptree;
9456           *node = tmpnode;
9457           return FALSE;
9458         }
9459       *tree = tmptree;
9460       *node = tmpnode;
9461       tmptree = tmpnode->children;
9462       if (tmptree == NULL)
9463         return TRUE;
9464     }
9465   while (1);
9466 }
9467
9468 static gboolean
9469 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9470                                   GtkTreeViewColumn *column)
9471 {
9472   GList *list;
9473
9474   if (tree_view->priv->is_list)
9475     return FALSE;
9476
9477   if (tree_view->priv->expander_column != NULL)
9478     {
9479       if (tree_view->priv->expander_column == column)
9480         return TRUE;
9481       return FALSE;
9482     }
9483   else
9484     {
9485       for (list = tree_view->priv->columns;
9486            list;
9487            list = list->next)
9488         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9489           break;
9490       if (list && list->data == column)
9491         return TRUE;
9492     }
9493   return FALSE;
9494 }
9495
9496 static inline gboolean
9497 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9498 {
9499   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9500     return TRUE;
9501   /* else */
9502   return FALSE;
9503 }
9504
9505 static void
9506 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9507                                 guint           keyval,
9508                                 guint           modmask,
9509                                 gboolean        add_shifted_binding,
9510                                 GtkMovementStep step,
9511                                 gint            count)
9512 {
9513   
9514   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9515                                 "move-cursor", 2,
9516                                 G_TYPE_ENUM, step,
9517                                 G_TYPE_INT, count);
9518
9519   if (add_shifted_binding)
9520     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9521                                   "move-cursor", 2,
9522                                   G_TYPE_ENUM, step,
9523                                   G_TYPE_INT, count);
9524
9525   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9526    return;
9527
9528   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9529                                 "move-cursor", 2,
9530                                 G_TYPE_ENUM, step,
9531                                 G_TYPE_INT, count);
9532
9533   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9534                                 "move-cursor", 2,
9535                                 G_TYPE_ENUM, step,
9536                                 G_TYPE_INT, count);
9537 }
9538
9539 static gint
9540 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9541                                  GtkTreeIter  *iter,
9542                                  GtkRBTree    *tree,
9543                                  GtkRBNode    *node)
9544 {
9545   gint retval = FALSE;
9546   do
9547     {
9548       g_return_val_if_fail (node != NULL, FALSE);
9549
9550       if (node->children)
9551         {
9552           GtkTreeIter child;
9553           GtkRBTree *new_tree;
9554           GtkRBNode *new_node;
9555
9556           new_tree = node->children;
9557           new_node = new_tree->root;
9558
9559           while (new_node && new_node->left != new_tree->nil)
9560             new_node = new_node->left;
9561
9562           if (!gtk_tree_model_iter_children (model, &child, iter))
9563             return FALSE;
9564
9565           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9566         }
9567
9568       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9569         retval = TRUE;
9570       gtk_tree_model_unref_node (model, iter);
9571       node = _gtk_rbtree_next (tree, node);
9572     }
9573   while (gtk_tree_model_iter_next (model, iter));
9574
9575   return retval;
9576 }
9577
9578 static gint
9579 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9580                                               GtkRBTree   *tree)
9581 {
9582   GtkTreeIter iter;
9583   GtkTreePath *path;
9584   GtkRBNode *node;
9585   gint retval;
9586
9587   if (!tree)
9588     return FALSE;
9589
9590   node = tree->root;
9591   while (node && node->left != tree->nil)
9592     node = node->left;
9593
9594   g_return_val_if_fail (node != NULL, FALSE);
9595   path = _gtk_tree_view_find_path (tree_view, tree, node);
9596   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9597                            &iter, path);
9598   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9599   gtk_tree_path_free (path);
9600
9601   return retval;
9602 }
9603
9604 static void
9605 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9606                                     GtkTreeViewColumn *column)
9607 {
9608   GtkTreeViewColumn *left_column;
9609   GtkTreeViewColumn *cur_column = NULL;
9610   GtkTreeViewColumnReorder *reorder;
9611   gboolean rtl;
9612   GList *tmp_list;
9613   gint left;
9614
9615   /* We want to precalculate the motion list such that we know what column slots
9616    * are available.
9617    */
9618   left_column = NULL;
9619   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9620
9621   /* First, identify all possible drop spots */
9622   if (rtl)
9623     tmp_list = g_list_last (tree_view->priv->columns);
9624   else
9625     tmp_list = g_list_first (tree_view->priv->columns);
9626
9627   while (tmp_list)
9628     {
9629       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9630       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9631
9632       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9633         continue;
9634
9635       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9636       if (left_column != column && cur_column != column &&
9637           tree_view->priv->column_drop_func &&
9638           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9639         {
9640           left_column = cur_column;
9641           continue;
9642         }
9643       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9644       reorder->left_column = left_column;
9645       left_column = reorder->right_column = cur_column;
9646
9647       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9648     }
9649
9650   /* Add the last one */
9651   if (tree_view->priv->column_drop_func == NULL ||
9652       ((left_column != column) &&
9653        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9654     {
9655       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9656       reorder->left_column = left_column;
9657       reorder->right_column = NULL;
9658       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9659     }
9660
9661   /* We quickly check to see if it even makes sense to reorder columns. */
9662   /* If there is nothing that can be moved, then we return */
9663
9664   if (tree_view->priv->column_drag_info == NULL)
9665     return;
9666
9667   /* We know there are always 2 slots possbile, as you can always return column. */
9668   /* If that's all there is, return */
9669   if (tree_view->priv->column_drag_info->next == NULL || 
9670       (tree_view->priv->column_drag_info->next->next == NULL &&
9671        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9672        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9673     {
9674       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9675         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9676       g_list_free (tree_view->priv->column_drag_info);
9677       tree_view->priv->column_drag_info = NULL;
9678       return;
9679     }
9680   /* We fill in the ranges for the columns, now that we've isolated them */
9681   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9682
9683   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9684     {
9685       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9686
9687       reorder->left_align = left;
9688       if (tmp_list->next != NULL)
9689         {
9690           GtkAllocation right_allocation, left_allocation;
9691           GtkWidget    *left_button, *right_button;
9692
9693           g_assert (tmp_list->next->data);
9694
9695           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9696           left_button  = gtk_tree_view_column_get_button
9697             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9698
9699           gtk_widget_get_allocation (right_button, &right_allocation);
9700           gtk_widget_get_allocation (left_button, &left_allocation);
9701           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9702         }
9703       else
9704         {
9705           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9706                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9707         }
9708     }
9709 }
9710
9711 void
9712 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9713                                   GtkTreeViewColumn *column,
9714                                   GdkDevice         *device)
9715 {
9716   GdkEvent *send_event;
9717   GtkAllocation allocation;
9718   GtkAllocation button_allocation;
9719   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9720   GtkWidget *button;
9721   GdkDevice *pointer, *keyboard;
9722
9723   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9724   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9725
9726   gtk_tree_view_set_column_drag_info (tree_view, column);
9727
9728   if (tree_view->priv->column_drag_info == NULL)
9729     return;
9730
9731   button = gtk_tree_view_column_get_button (column);
9732
9733   if (tree_view->priv->drag_window == NULL)
9734     {
9735       GdkWindowAttr attributes;
9736       guint attributes_mask;
9737
9738       gtk_widget_get_allocation (button, &button_allocation);
9739
9740       attributes.window_type = GDK_WINDOW_CHILD;
9741       attributes.wclass = GDK_INPUT_OUTPUT;
9742       attributes.x = button_allocation.x;
9743       attributes.y = 0;
9744       attributes.width = button_allocation.width;
9745       attributes.height = button_allocation.height;
9746       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9747       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9748       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9749
9750       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9751                                                      &attributes,
9752                                                      attributes_mask);
9753       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9754     }
9755
9756   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9757     {
9758       keyboard = device;
9759       pointer = gdk_device_get_associated_device (device);
9760     }
9761   else
9762     {
9763       pointer = device;
9764       keyboard = gdk_device_get_associated_device (device);
9765     }
9766
9767   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9768   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9769
9770   gtk_grab_remove (button);
9771
9772   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9773   send_event->crossing.send_event = TRUE;
9774   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9775   send_event->crossing.subwindow = NULL;
9776   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9777   send_event->crossing.time = GDK_CURRENT_TIME;
9778   gdk_event_set_device (send_event, device);
9779
9780   gtk_propagate_event (button, send_event);
9781   gdk_event_free (send_event);
9782
9783   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9784   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9785   send_event->button.send_event = TRUE;
9786   send_event->button.time = GDK_CURRENT_TIME;
9787   send_event->button.x = -1;
9788   send_event->button.y = -1;
9789   send_event->button.axes = NULL;
9790   send_event->button.state = 0;
9791   send_event->button.button = 1;
9792   send_event->button.x_root = 0;
9793   send_event->button.y_root = 0;
9794   gdk_event_set_device (send_event, device);
9795
9796   gtk_propagate_event (button, send_event);
9797   gdk_event_free (send_event);
9798
9799   /* Kids, don't try this at home */
9800   g_object_ref (button);
9801   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9802   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9803   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9804   g_object_unref (button);
9805
9806   gtk_widget_get_allocation (button, &button_allocation);
9807   tree_view->priv->drag_column_x = button_allocation.x;
9808   allocation = button_allocation;
9809   allocation.x = 0;
9810   gtk_widget_size_allocate (button, &allocation);
9811   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9812
9813   tree_view->priv->drag_column = column;
9814   gdk_window_show (tree_view->priv->drag_window);
9815
9816   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9817   while (gtk_events_pending ())
9818     gtk_main_iteration ();
9819
9820   tree_view->priv->in_column_drag = TRUE;
9821
9822   gdk_device_grab (pointer,
9823                    tree_view->priv->drag_window,
9824                    GDK_OWNERSHIP_NONE,
9825                    FALSE,
9826                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9827                    NULL,
9828                    GDK_CURRENT_TIME);
9829   gdk_device_grab (keyboard,
9830                    tree_view->priv->drag_window,
9831                    GDK_OWNERSHIP_NONE,
9832                    FALSE,
9833                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9834                    NULL,
9835                    GDK_CURRENT_TIME);
9836 }
9837
9838 static void
9839 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9840                                 GtkRBTree          *tree,
9841                                 GtkRBNode          *node)
9842 {
9843   GtkAllocation allocation;
9844   GdkRectangle rect;
9845
9846   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9847     return;
9848
9849   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9850   rect.x = 0;
9851   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9852
9853   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9854   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9855
9856   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9857 }
9858
9859 void
9860 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9861                                 GtkRBTree          *tree,
9862                                 GtkRBNode          *node,
9863                                 const GdkRectangle *clip_rect)
9864 {
9865   GtkAllocation allocation;
9866   GdkRectangle rect;
9867
9868   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9869     return;
9870
9871   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9872   rect.x = 0;
9873   rect.width = MAX (tree_view->priv->width, allocation.width);
9874
9875   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9876   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9877
9878   if (clip_rect)
9879     {
9880       GdkRectangle new_rect;
9881
9882       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9883
9884       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9885     }
9886   else
9887     {
9888       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9889     }
9890 }
9891
9892 static inline gint
9893 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9894 {
9895   if (tree_view->priv->headers_visible)
9896     return tree_view->priv->header_height;
9897   /* else */
9898   return 0;
9899 }
9900
9901 gint
9902 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9903 {
9904   return tree_view->priv->header_height;
9905 }
9906
9907 void
9908 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9909                                        GtkTreeViewRowSeparatorFunc *func,
9910                                        gpointer                    *data)
9911 {
9912   *func = tree_view->priv->row_separator_func;
9913   *data = tree_view->priv->row_separator_data;
9914 }
9915
9916 GtkTreePath *
9917 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9918 {
9919   if (tree_view->priv->anchor)
9920     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9921
9922   return NULL;
9923 }
9924
9925 void
9926 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9927                                 GtkTreePath *anchor_path)
9928 {
9929   if (tree_view->priv->anchor)
9930     {
9931       gtk_tree_row_reference_free (tree_view->priv->anchor);
9932       tree_view->priv->anchor = NULL;
9933     }
9934
9935   if (anchor_path && tree_view->priv->model)
9936     tree_view->priv->anchor =
9937       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
9938                                         tree_view->priv->model, anchor_path);
9939 }
9940
9941 GtkRBTree *
9942 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
9943 {
9944   return tree_view->priv->tree;
9945 }
9946
9947 GdkWindow *
9948 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
9949 {
9950   return tree_view->priv->header_window;
9951 }
9952
9953 void
9954 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
9955                                  GtkTreeViewColumn *column)
9956 {
9957   tree_view->priv->focus_column = column;
9958 }
9959
9960
9961 static void
9962 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9963                                GtkTreePath        *path,
9964                                const GdkRectangle *clip_rect)
9965 {
9966   GtkRBTree *tree = NULL;
9967   GtkRBNode *node = NULL;
9968
9969   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9970
9971   if (tree)
9972     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9973 }
9974
9975 /* x and y are the mouse position
9976  */
9977 static void
9978 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9979                           cairo_t     *cr,
9980                           GtkRBTree   *tree,
9981                           GtkRBNode   *node,
9982                           /* in bin_window coordinates */
9983                           gint         x,
9984                           gint         y)
9985 {
9986   GdkRectangle area;
9987   GtkStateFlags state = 0;
9988   GtkStyleContext *context;
9989   GtkWidget *widget;
9990   gint x_offset = 0;
9991   gint x2;
9992   gint vertical_separator;
9993   gint expander_size;
9994   GtkCellRendererState flags;
9995
9996   widget = GTK_WIDGET (tree_view);
9997   context = gtk_widget_get_style_context (widget);
9998
9999   gtk_widget_style_get (widget,
10000                         "vertical-separator", &vertical_separator,
10001                         NULL);
10002   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
10003
10004   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
10005     return;
10006
10007   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
10008
10009   area.x = x_offset;
10010   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
10011                                                  vertical_separator);
10012   area.width = expander_size;
10013   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10014                                                     vertical_separator);
10015
10016   if (!gtk_widget_get_sensitive (widget))
10017     state |= GTK_STATE_FLAG_INSENSITIVE;
10018   else
10019     {
10020       flags = 0;
10021
10022       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
10023         flags |= GTK_CELL_RENDERER_SELECTED;
10024
10025       state = gtk_cell_renderer_get_state (NULL, widget, flags);
10026
10027       if (node == tree_view->priv->button_pressed_node &&
10028           x >= area.x && x <= (area.x + area.width) &&
10029           y >= area.y && y <= (area.y + area.height))
10030         state |= GTK_STATE_FLAG_FOCUSED;
10031
10032       if (node == tree_view->priv->prelight_node &&
10033           tree_view->priv->arrow_prelit)
10034         state |= GTK_STATE_FLAG_PRELIGHT;
10035     }
10036
10037   if (node->children != NULL)
10038     state |= GTK_STATE_FLAG_ACTIVE;
10039
10040   gtk_style_context_save (context);
10041
10042   gtk_style_context_set_state (context, state);
10043   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10044
10045   gtk_style_context_push_animatable_region (context, node);
10046
10047   gtk_render_expander (context, cr,
10048                        area.x, area.y,
10049                        area.width, area.height);
10050
10051   gtk_style_context_pop_animatable_region (context);
10052   gtk_style_context_restore (context);
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->modify_selection_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->extend_selection_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->extend_selection_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->modify_selection_pressed)
10657     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10658   if (tree_view->priv->extend_selection_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->extend_selection_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           GdkModifierType modify_mod_mask;
10821
10822           modify_mod_mask =
10823             gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
10824                                           GDK_MODIFIER_INTENT_MODIFY_SELECTION);
10825
10826           if ((state & modify_mod_mask) == modify_mod_mask)
10827             tree_view->priv->modify_selection_pressed = TRUE;
10828         }
10829
10830       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10831       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10832
10833       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10834       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10835       gtk_tree_path_free (cursor_path);
10836
10837       tree_view->priv->modify_selection_pressed = FALSE;
10838
10839       return TRUE;
10840     }
10841
10842  out:
10843
10844   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10845   return FALSE;
10846 }
10847
10848 static gboolean
10849 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10850 {
10851   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10852   tree_view->priv->typeselect_flush_timeout = 0;
10853
10854   return FALSE;
10855 }
10856
10857 /* Cut and paste from gtkwindow.c */
10858 static void
10859 send_focus_change (GtkWidget *widget,
10860                    GdkDevice *device,
10861                    gboolean   in)
10862 {
10863   GdkDeviceManager *device_manager;
10864   GList *devices, *d;
10865
10866   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10867   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10868   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10869   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10870
10871   for (d = devices; d; d = d->next)
10872     {
10873       GdkDevice *dev = d->data;
10874       GdkEvent *fevent;
10875       GdkWindow *window;
10876
10877       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10878         continue;
10879
10880       window = gtk_widget_get_window (widget);
10881
10882       /* Skip non-master keyboards that haven't
10883        * selected for events from this window
10884        */
10885       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10886           !gdk_window_get_device_events (window, dev))
10887         continue;
10888
10889       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10890
10891       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10892       fevent->focus_change.window = g_object_ref (window);
10893       fevent->focus_change.in = in;
10894       gdk_event_set_device (fevent, device);
10895
10896       gtk_widget_send_focus_change (widget, fevent);
10897
10898       gdk_event_free (fevent);
10899     }
10900
10901   g_list_free (devices);
10902 }
10903
10904 static void
10905 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10906 {
10907   GtkWidget *frame, *vbox, *toplevel;
10908   GdkScreen *screen;
10909
10910   if (tree_view->priv->search_custom_entry_set)
10911     return;
10912
10913   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10914   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10915
10916    if (tree_view->priv->search_window != NULL)
10917      {
10918        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10919          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10920                                       GTK_WINDOW (tree_view->priv->search_window));
10921        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10922          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10923                                          GTK_WINDOW (tree_view->priv->search_window));
10924
10925        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10926
10927        return;
10928      }
10929    
10930   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10931   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10932
10933   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10934     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10935                                  GTK_WINDOW (tree_view->priv->search_window));
10936
10937   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10938                             GDK_WINDOW_TYPE_HINT_UTILITY);
10939   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10940   g_signal_connect (tree_view->priv->search_window, "delete-event",
10941                     G_CALLBACK (gtk_tree_view_search_delete_event),
10942                     tree_view);
10943   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10944                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10945                     tree_view);
10946   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10947                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10948                     tree_view);
10949   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10950                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10951                     tree_view);
10952
10953   frame = gtk_frame_new (NULL);
10954   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10955   gtk_widget_show (frame);
10956   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10957
10958   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10959   gtk_widget_show (vbox);
10960   gtk_container_add (GTK_CONTAINER (frame), vbox);
10961   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10962
10963   /* add entry */
10964   tree_view->priv->search_entry = gtk_entry_new ();
10965   gtk_widget_show (tree_view->priv->search_entry);
10966   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10967                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10968                     tree_view);
10969   g_signal_connect (tree_view->priv->search_entry,
10970                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10971                     tree_view);
10972
10973   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
10974                     "preedit-changed",
10975                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10976                     tree_view);
10977
10978   gtk_container_add (GTK_CONTAINER (vbox),
10979                      tree_view->priv->search_entry);
10980
10981   gtk_widget_realize (tree_view->priv->search_entry);
10982 }
10983
10984 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10985  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10986  */
10987 static gboolean
10988 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10989                                              GdkDevice   *device,
10990                                              gboolean     keybinding)
10991 {
10992   /* We only start interactive search if we have focus or the columns
10993    * have focus.  If one of our children have focus, we don't want to
10994    * start the search.
10995    */
10996   GList *list;
10997   gboolean found_focus = FALSE;
10998   GtkWidgetClass *entry_parent_class;
10999   
11000   if (!tree_view->priv->enable_search && !keybinding)
11001     return FALSE;
11002
11003   if (tree_view->priv->search_custom_entry_set)
11004     return FALSE;
11005
11006   if (tree_view->priv->search_window != NULL &&
11007       gtk_widget_get_visible (tree_view->priv->search_window))
11008     return TRUE;
11009
11010   for (list = tree_view->priv->columns; list; list = list->next)
11011     {
11012       GtkTreeViewColumn *column;
11013       GtkWidget         *button;
11014
11015       column = list->data;
11016       if (!gtk_tree_view_column_get_visible (column))
11017         continue;
11018
11019       button = gtk_tree_view_column_get_button (column);
11020       if (gtk_widget_has_focus (button))
11021         {
11022           found_focus = TRUE;
11023           break;
11024         }
11025     }
11026   
11027   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11028     found_focus = TRUE;
11029
11030   if (!found_focus)
11031     return FALSE;
11032
11033   if (tree_view->priv->search_column < 0)
11034     return FALSE;
11035
11036   gtk_tree_view_ensure_interactive_directory (tree_view);
11037
11038   if (keybinding)
11039     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11040
11041   /* done, show it */
11042   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11043   gtk_widget_show (tree_view->priv->search_window);
11044   if (tree_view->priv->search_entry_changed_id == 0)
11045     {
11046       tree_view->priv->search_entry_changed_id =
11047         g_signal_connect (tree_view->priv->search_entry, "changed",
11048                           G_CALLBACK (gtk_tree_view_search_init),
11049                           tree_view);
11050     }
11051
11052   tree_view->priv->typeselect_flush_timeout =
11053     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11054                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11055                    tree_view);
11056
11057   /* Grab focus will select all the text.  We don't want that to happen, so we
11058    * call the parent instance and bypass the selection change.  This is probably
11059    * really non-kosher. */
11060   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11061   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11062
11063   /* send focus-in event */
11064   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11065
11066   /* search first matching iter */
11067   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11068
11069   return TRUE;
11070 }
11071
11072 static gboolean
11073 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11074 {
11075   return gtk_tree_view_real_start_interactive_search (tree_view,
11076                                                       gtk_get_current_event_device (),
11077                                                       TRUE);
11078 }
11079
11080 /* this function returns the new width of the column being resized given
11081  * the column and x position of the cursor; the x cursor position is passed
11082  * in as a pointer and automagicly corrected if it's beyond min/max limits
11083  */
11084 static gint
11085 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11086                                 gint       i,
11087                                 gint      *x)
11088 {
11089   GtkAllocation allocation;
11090   GtkTreeViewColumn *column;
11091   GtkRequisition button_req;
11092   gint max_width, min_width;
11093   gint width;
11094   gboolean rtl;
11095
11096   /* first translate the x position from widget->window
11097    * to clist->clist_window
11098    */
11099   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11100   column = g_list_nth (tree_view->priv->columns, i)->data;
11101   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11102   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11103
11104   /* Clamp down the value */
11105   min_width = gtk_tree_view_column_get_min_width (column);
11106   if (min_width == -1)
11107     {
11108       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11109       width = MAX (button_req.width, width);
11110     }
11111   else
11112     width = MAX (min_width, width);
11113
11114   max_width = gtk_tree_view_column_get_max_width (column);
11115   if (max_width != -1)
11116     width = MIN (width, max_width);
11117
11118   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11119
11120   return width;
11121 }
11122
11123
11124 /* FIXME this adjust_allocation is a big cut-and-paste from
11125  * GtkCList, needs to be some "official" way to do this
11126  * factored out.
11127  */
11128 typedef struct
11129 {
11130   GdkWindow *window;
11131   int dx;
11132   int dy;
11133 } ScrollData;
11134
11135 /* The window to which widget->window is relative */
11136 #define ALLOCATION_WINDOW(widget)               \
11137    (!gtk_widget_get_has_window (widget) ?                   \
11138     gtk_widget_get_window (widget) :                        \
11139     gdk_window_get_parent (gtk_widget_get_window (widget)))
11140
11141 static void
11142 adjust_allocation_recurse (GtkWidget *widget,
11143                            gpointer   data)
11144 {
11145   GtkAllocation allocation;
11146   ScrollData *scroll_data = data;
11147
11148   /* Need to really size allocate instead of just poking
11149    * into widget->allocation if the widget is not realized.
11150    * FIXME someone figure out why this was.
11151    */
11152   gtk_widget_get_allocation (widget, &allocation);
11153   if (!gtk_widget_get_realized (widget))
11154     {
11155       if (gtk_widget_get_visible (widget))
11156         {
11157           GdkRectangle tmp_rectangle = allocation;
11158           tmp_rectangle.x += scroll_data->dx;
11159           tmp_rectangle.y += scroll_data->dy;
11160           
11161           gtk_widget_size_allocate (widget, &tmp_rectangle);
11162         }
11163     }
11164   else
11165     {
11166       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11167         {
11168           allocation.x += scroll_data->dx;
11169           allocation.y += scroll_data->dy;
11170           gtk_widget_set_allocation (widget, &allocation);
11171
11172           if (GTK_IS_CONTAINER (widget))
11173             gtk_container_forall (GTK_CONTAINER (widget),
11174                                   adjust_allocation_recurse,
11175                                   data);
11176         }
11177     }
11178 }
11179
11180 static void
11181 adjust_allocation (GtkWidget *widget,
11182                    int        dx,
11183                    int        dy)
11184 {
11185   ScrollData scroll_data;
11186
11187   if (gtk_widget_get_realized (widget))
11188     scroll_data.window = ALLOCATION_WINDOW (widget);
11189   else
11190     scroll_data.window = NULL;
11191     
11192   scroll_data.dx = dx;
11193   scroll_data.dy = dy;
11194   
11195   adjust_allocation_recurse (widget, &scroll_data);
11196 }
11197
11198 /* Callbacks */
11199 static void
11200 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11201                                   GtkTreeView   *tree_view)
11202 {
11203   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11204     {
11205       GtkStyleContext *context;
11206       gint dy;
11207         
11208       gdk_window_move (tree_view->priv->bin_window,
11209                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11210                        gtk_tree_view_get_effective_header_height (tree_view));
11211       gdk_window_move (tree_view->priv->header_window,
11212                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11213                        0);
11214       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11215       if (dy)
11216         {
11217           update_prelight (tree_view,
11218                            tree_view->priv->event_last_x,
11219                            tree_view->priv->event_last_y - dy);
11220
11221           if (tree_view->priv->edited_column)
11222             {
11223               GList *list;
11224               GtkTreeViewChild *child = NULL;
11225               GtkCellEditable *edit_widget;
11226               GtkCellArea *area;
11227
11228               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11229               edit_widget = gtk_cell_area_get_edit_widget (area);
11230               if (GTK_IS_WIDGET (edit_widget))
11231                 {
11232                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11233
11234                   for (list = tree_view->priv->children; list; list = list->next)
11235                     {
11236                       child = (GtkTreeViewChild *)list->data;
11237                       if (child->widget == GTK_WIDGET (edit_widget))
11238                         {
11239                           child->y += dy;
11240                           break;
11241                         }
11242                     }
11243                 }
11244             }
11245         }
11246       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11247
11248       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11249       gtk_style_context_scroll_animations (context, tree_view->priv->bin_window, 0, dy);
11250
11251       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11252         {
11253           /* update our dy and top_row */
11254           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11255
11256           if (!tree_view->priv->in_top_row_to_dy)
11257             gtk_tree_view_dy_to_top_row (tree_view);
11258         }
11259
11260       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
11261       gtk_tree_view_bin_process_updates (tree_view);
11262     }
11263 }
11264
11265 \f
11266
11267 /* Public methods
11268  */
11269
11270 /**
11271  * gtk_tree_view_new:
11272  *
11273  * Creates a new #GtkTreeView widget.
11274  *
11275  * Return value: A newly created #GtkTreeView widget.
11276  **/
11277 GtkWidget *
11278 gtk_tree_view_new (void)
11279 {
11280   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11281 }
11282
11283 /**
11284  * gtk_tree_view_new_with_model:
11285  * @model: the model.
11286  *
11287  * Creates a new #GtkTreeView widget with the model initialized to @model.
11288  *
11289  * Return value: A newly created #GtkTreeView widget.
11290  **/
11291 GtkWidget *
11292 gtk_tree_view_new_with_model (GtkTreeModel *model)
11293 {
11294   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11295 }
11296
11297 /* Public Accessors
11298  */
11299
11300 /**
11301  * gtk_tree_view_get_model:
11302  * @tree_view: a #GtkTreeView
11303  *
11304  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11305  * model is unset.
11306  *
11307  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11308  **/
11309 GtkTreeModel *
11310 gtk_tree_view_get_model (GtkTreeView *tree_view)
11311 {
11312   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11313
11314   return tree_view->priv->model;
11315 }
11316
11317 /**
11318  * gtk_tree_view_set_model:
11319  * @tree_view: A #GtkTreeNode.
11320  * @model: (allow-none): The model.
11321  *
11322  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11323  * set, it will remove it before setting the new model.  If @model is %NULL,
11324  * then it will unset the old model.
11325  **/
11326 void
11327 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11328                          GtkTreeModel *model)
11329 {
11330   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11331   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11332
11333   if (model == tree_view->priv->model)
11334     return;
11335
11336   if (tree_view->priv->scroll_to_path)
11337     {
11338       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11339       tree_view->priv->scroll_to_path = NULL;
11340     }
11341
11342   if (tree_view->priv->model)
11343     {
11344       GList *tmplist = tree_view->priv->columns;
11345       GtkStyleContext *context;
11346
11347       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11348       gtk_tree_view_stop_editing (tree_view, TRUE);
11349
11350       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11351       gtk_style_context_cancel_animations (context, NULL);
11352
11353       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11354                                             gtk_tree_view_row_changed,
11355                                             tree_view);
11356       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11357                                             gtk_tree_view_row_inserted,
11358                                             tree_view);
11359       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11360                                             gtk_tree_view_row_has_child_toggled,
11361                                             tree_view);
11362       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11363                                             gtk_tree_view_row_deleted,
11364                                             tree_view);
11365       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11366                                             gtk_tree_view_rows_reordered,
11367                                             tree_view);
11368
11369       for (; tmplist; tmplist = tmplist->next)
11370         _gtk_tree_view_column_unset_model (tmplist->data,
11371                                            tree_view->priv->model);
11372
11373       if (tree_view->priv->tree)
11374         gtk_tree_view_free_rbtree (tree_view);
11375
11376       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11377       tree_view->priv->drag_dest_row = NULL;
11378       gtk_tree_row_reference_free (tree_view->priv->cursor);
11379       tree_view->priv->cursor = NULL;
11380       gtk_tree_row_reference_free (tree_view->priv->anchor);
11381       tree_view->priv->anchor = NULL;
11382       gtk_tree_row_reference_free (tree_view->priv->top_row);
11383       tree_view->priv->top_row = NULL;
11384       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11385       tree_view->priv->scroll_to_path = NULL;
11386
11387       tree_view->priv->scroll_to_column = NULL;
11388
11389       g_object_unref (tree_view->priv->model);
11390
11391       tree_view->priv->search_column = -1;
11392       tree_view->priv->fixed_height_check = 0;
11393       tree_view->priv->fixed_height = -1;
11394       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11395       tree_view->priv->last_button_x = -1;
11396       tree_view->priv->last_button_y = -1;
11397     }
11398
11399   tree_view->priv->model = model;
11400
11401   if (tree_view->priv->model)
11402     {
11403       gint i;
11404       GtkTreePath *path;
11405       GtkTreeIter iter;
11406       GtkTreeModelFlags flags;
11407
11408       if (tree_view->priv->search_column == -1)
11409         {
11410           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11411             {
11412               GType type = gtk_tree_model_get_column_type (model, i);
11413
11414               if (g_value_type_transformable (type, G_TYPE_STRING))
11415                 {
11416                   tree_view->priv->search_column = i;
11417                   break;
11418                 }
11419             }
11420         }
11421
11422       g_object_ref (tree_view->priv->model);
11423       g_signal_connect (tree_view->priv->model,
11424                         "row-changed",
11425                         G_CALLBACK (gtk_tree_view_row_changed),
11426                         tree_view);
11427       g_signal_connect (tree_view->priv->model,
11428                         "row-inserted",
11429                         G_CALLBACK (gtk_tree_view_row_inserted),
11430                         tree_view);
11431       g_signal_connect (tree_view->priv->model,
11432                         "row-has-child-toggled",
11433                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11434                         tree_view);
11435       g_signal_connect (tree_view->priv->model,
11436                         "row-deleted",
11437                         G_CALLBACK (gtk_tree_view_row_deleted),
11438                         tree_view);
11439       g_signal_connect (tree_view->priv->model,
11440                         "rows-reordered",
11441                         G_CALLBACK (gtk_tree_view_rows_reordered),
11442                         tree_view);
11443
11444       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11445       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11446         tree_view->priv->is_list = TRUE;
11447       else
11448         tree_view->priv->is_list = FALSE;
11449
11450       path = gtk_tree_path_new_first ();
11451       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11452         {
11453           tree_view->priv->tree = _gtk_rbtree_new ();
11454           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11455         }
11456       gtk_tree_path_free (path);
11457
11458       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11459       install_presize_handler (tree_view);
11460     }
11461
11462   g_object_notify (G_OBJECT (tree_view), "model");
11463
11464   if (tree_view->priv->selection)
11465   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11466
11467   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11468     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11469 }
11470
11471 /**
11472  * gtk_tree_view_get_selection:
11473  * @tree_view: A #GtkTreeView.
11474  *
11475  * Gets the #GtkTreeSelection associated with @tree_view.
11476  *
11477  * Return value: (transfer none): A #GtkTreeSelection object.
11478  **/
11479 GtkTreeSelection *
11480 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11481 {
11482   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11483
11484   return tree_view->priv->selection;
11485 }
11486
11487 /**
11488  * gtk_tree_view_get_hadjustment:
11489  * @tree_view: A #GtkTreeView
11490  *
11491  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11492  *
11493  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11494  *     if none is currently being used.
11495  *
11496  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11497  **/
11498 GtkAdjustment *
11499 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11500 {
11501   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11502
11503   return tree_view->priv->hadjustment;
11504 }
11505
11506 /**
11507  * gtk_tree_view_set_hadjustment:
11508  * @tree_view: A #GtkTreeView
11509  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11510  *
11511  * Sets the #GtkAdjustment for the current horizontal aspect.
11512  *
11513  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11514  **/
11515 void
11516 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11517                                GtkAdjustment *adjustment)
11518 {
11519   GtkTreeViewPrivate *priv = tree_view->priv;
11520
11521   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11522   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11523
11524   if (adjustment && priv->hadjustment == adjustment)
11525     return;
11526
11527   if (priv->hadjustment != NULL)
11528     {
11529       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11530                                             gtk_tree_view_adjustment_changed,
11531                                             tree_view);
11532       g_object_unref (priv->hadjustment);
11533     }
11534
11535   if (adjustment == NULL)
11536     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11537                                      0.0, 0.0, 0.0);
11538
11539   g_signal_connect (adjustment, "value-changed",
11540                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11541   priv->hadjustment = g_object_ref_sink (adjustment);
11542   /* FIXME: Adjustment should probably be populated here with fresh values, but
11543    * internal details are too complicated for me to decipher right now.
11544    */
11545   gtk_tree_view_adjustment_changed (NULL, tree_view);
11546
11547   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11548 }
11549
11550 /**
11551  * gtk_tree_view_get_vadjustment:
11552  * @tree_view: A #GtkTreeView
11553  *
11554  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11555  *
11556  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11557  *     if none is currently being used.
11558  *
11559  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11560  **/
11561 GtkAdjustment *
11562 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11563 {
11564   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11565
11566   return tree_view->priv->vadjustment;
11567 }
11568
11569 /**
11570  * gtk_tree_view_set_vadjustment:
11571  * @tree_view: A #GtkTreeView
11572  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11573  *
11574  * Sets the #GtkAdjustment for the current vertical aspect.
11575  *
11576  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11577  **/
11578 void
11579 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11580                                GtkAdjustment *adjustment)
11581 {
11582   GtkTreeViewPrivate *priv = tree_view->priv;
11583
11584   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11585   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11586
11587   if (adjustment && priv->vadjustment == adjustment)
11588     return;
11589
11590   if (priv->vadjustment != NULL)
11591     {
11592       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11593                                             gtk_tree_view_adjustment_changed,
11594                                             tree_view);
11595       g_object_unref (priv->vadjustment);
11596     }
11597
11598   if (adjustment == NULL)
11599     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11600                                      0.0, 0.0, 0.0);
11601
11602   g_signal_connect (adjustment, "value-changed",
11603                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11604   priv->vadjustment = g_object_ref_sink (adjustment);
11605   /* FIXME: Adjustment should probably be populated here with fresh values, but
11606    * internal details are too complicated for me to decipher right now.
11607    */
11608   gtk_tree_view_adjustment_changed (NULL, tree_view);
11609   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11610 }
11611
11612 /* Column and header operations */
11613
11614 /**
11615  * gtk_tree_view_get_headers_visible:
11616  * @tree_view: A #GtkTreeView.
11617  *
11618  * Returns %TRUE if the headers on the @tree_view are visible.
11619  *
11620  * Return value: Whether the headers are visible or not.
11621  **/
11622 gboolean
11623 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11624 {
11625   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11626
11627   return tree_view->priv->headers_visible;
11628 }
11629
11630 /**
11631  * gtk_tree_view_set_headers_visible:
11632  * @tree_view: A #GtkTreeView.
11633  * @headers_visible: %TRUE if the headers are visible
11634  *
11635  * Sets the visibility state of the headers.
11636  **/
11637 void
11638 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11639                                    gboolean     headers_visible)
11640 {
11641   gint x, y;
11642   GList *list;
11643   GtkTreeViewColumn *column;
11644   GtkAllocation allocation;
11645   GtkWidget *button;
11646
11647   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11648
11649   headers_visible = !! headers_visible;
11650
11651   if (tree_view->priv->headers_visible == headers_visible)
11652     return;
11653
11654   tree_view->priv->headers_visible = headers_visible == TRUE;
11655
11656   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11657     {
11658       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11659       if (headers_visible)
11660         {
11661           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11662           gdk_window_move_resize (tree_view->priv->bin_window,
11663                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11664                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11665
11666           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11667             gtk_tree_view_map_buttons (tree_view);
11668         }
11669       else
11670         {
11671           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11672
11673           for (list = tree_view->priv->columns; list; list = list->next)
11674             {
11675               column = list->data;
11676               button = gtk_tree_view_column_get_button (column);
11677
11678               gtk_widget_hide (button);
11679               gtk_widget_unmap (button);
11680             }
11681           gdk_window_hide (tree_view->priv->header_window);
11682         }
11683     }
11684
11685   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11686   gtk_adjustment_configure (tree_view->priv->vadjustment,
11687                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11688                             0,
11689                             tree_view->priv->height,
11690                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11691                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11692                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11693
11694   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11695
11696   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11697 }
11698
11699 /**
11700  * gtk_tree_view_columns_autosize:
11701  * @tree_view: A #GtkTreeView.
11702  *
11703  * Resizes all columns to their optimal width. Only works after the
11704  * treeview has been realized.
11705  **/
11706 void
11707 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11708 {
11709   gboolean dirty = FALSE;
11710   GList *list;
11711   GtkTreeViewColumn *column;
11712
11713   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11714
11715   for (list = tree_view->priv->columns; list; list = list->next)
11716     {
11717       column = list->data;
11718       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11719         continue;
11720       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11721       dirty = TRUE;
11722     }
11723
11724   if (dirty)
11725     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11726 }
11727
11728 /**
11729  * gtk_tree_view_set_headers_clickable:
11730  * @tree_view: A #GtkTreeView.
11731  * @setting: %TRUE if the columns are clickable.
11732  *
11733  * Allow the column title buttons to be clicked.
11734  **/
11735 void
11736 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11737                                      gboolean   setting)
11738 {
11739   GList *list;
11740
11741   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11742
11743   for (list = tree_view->priv->columns; list; list = list->next)
11744     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11745
11746   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11747 }
11748
11749
11750 /**
11751  * gtk_tree_view_get_headers_clickable:
11752  * @tree_view: A #GtkTreeView.
11753  *
11754  * Returns whether all header columns are clickable.
11755  *
11756  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11757  *
11758  * Since: 2.10
11759  **/
11760 gboolean 
11761 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11762 {
11763   GList *list;
11764   
11765   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11766
11767   for (list = tree_view->priv->columns; list; list = list->next)
11768     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11769       return FALSE;
11770
11771   return TRUE;
11772 }
11773
11774 /**
11775  * gtk_tree_view_set_rules_hint
11776  * @tree_view: a #GtkTreeView
11777  * @setting: %TRUE if the tree requires reading across rows
11778  *
11779  * This function tells GTK+ that the user interface for your
11780  * application requires users to read across tree rows and associate
11781  * cells with one another. By default, GTK+ will then render the tree
11782  * with alternating row colors. Do <emphasis>not</emphasis> use it
11783  * just because you prefer the appearance of the ruled tree; that's a
11784  * question for the theme. Some themes will draw tree rows in
11785  * alternating colors even when rules are turned off, and users who
11786  * prefer that appearance all the time can choose those themes. You
11787  * should call this function only as a <emphasis>semantic</emphasis>
11788  * hint to the theme engine that your tree makes alternating colors
11789  * useful from a functional standpoint (since it has lots of columns,
11790  * generally).
11791  *
11792  **/
11793 void
11794 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11795                               gboolean      setting)
11796 {
11797   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11798
11799   setting = setting != FALSE;
11800
11801   if (tree_view->priv->has_rules != setting)
11802     {
11803       tree_view->priv->has_rules = setting;
11804       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11805     }
11806
11807   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11808 }
11809
11810 /**
11811  * gtk_tree_view_get_rules_hint
11812  * @tree_view: a #GtkTreeView
11813  *
11814  * Gets the setting set by gtk_tree_view_set_rules_hint().
11815  *
11816  * Return value: %TRUE if rules are useful for the user of this tree
11817  **/
11818 gboolean
11819 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11820 {
11821   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11822
11823   return tree_view->priv->has_rules;
11824 }
11825
11826 /* Public Column functions
11827  */
11828
11829 /**
11830  * gtk_tree_view_append_column:
11831  * @tree_view: A #GtkTreeView.
11832  * @column: The #GtkTreeViewColumn to add.
11833  *
11834  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11835  * mode enabled, then @column must have its "sizing" property set to be
11836  * GTK_TREE_VIEW_COLUMN_FIXED.
11837  *
11838  * Return value: The number of columns in @tree_view after appending.
11839  **/
11840 gint
11841 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11842                              GtkTreeViewColumn *column)
11843 {
11844   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11845   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11846   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11847
11848   return gtk_tree_view_insert_column (tree_view, column, -1);
11849 }
11850
11851 void
11852 _gtk_tree_view_reset_header_styles (GtkTreeView *tree_view)
11853 {
11854   GList *columns;
11855
11856   for (columns = tree_view->priv->columns; columns; columns = columns->next)
11857     {
11858       GtkTreeViewColumn *column = columns->data;
11859       GtkWidget *header_widget;
11860
11861       if (gtk_tree_view_column_get_visible (column))
11862         continue;
11863
11864       header_widget = gtk_tree_view_column_get_widget (column);
11865
11866       if (!header_widget)
11867         header_widget = gtk_tree_view_column_get_button (column);
11868
11869       gtk_widget_reset_style (header_widget);
11870     }
11871 }
11872
11873
11874 /**
11875  * gtk_tree_view_remove_column:
11876  * @tree_view: A #GtkTreeView.
11877  * @column: The #GtkTreeViewColumn to remove.
11878  *
11879  * Removes @column from @tree_view.
11880  *
11881  * Return value: The number of columns in @tree_view after removing.
11882  **/
11883 gint
11884 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11885                              GtkTreeViewColumn *column)
11886 {
11887   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11888   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11889   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11890
11891   if (tree_view->priv->focus_column == column)
11892     tree_view->priv->focus_column = NULL;
11893
11894   if (tree_view->priv->edited_column == column)
11895     {
11896       gtk_tree_view_stop_editing (tree_view, TRUE);
11897
11898       /* no need to, but just to be sure ... */
11899       tree_view->priv->edited_column = NULL;
11900     }
11901
11902   if (tree_view->priv->expander_column == column)
11903     tree_view->priv->expander_column = NULL;
11904
11905   g_signal_handlers_disconnect_by_func (column,
11906                                         G_CALLBACK (column_sizing_notify),
11907                                         tree_view);
11908
11909   _gtk_tree_view_column_unset_tree_view (column);
11910
11911   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11912   tree_view->priv->n_columns--;
11913
11914   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11915     {
11916       GList *list;
11917
11918       _gtk_tree_view_column_unrealize_button (column);
11919       for (list = tree_view->priv->columns; list; list = list->next)
11920         {
11921           GtkTreeViewColumn *tmp_column;
11922
11923           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11924           if (gtk_tree_view_column_get_visible (tmp_column))
11925             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11926         }
11927
11928       if (tree_view->priv->n_columns == 0 &&
11929           gtk_tree_view_get_headers_visible (tree_view))
11930         gdk_window_hide (tree_view->priv->header_window);
11931
11932       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11933     }
11934
11935   _gtk_tree_view_reset_header_styles (tree_view);
11936
11937   g_object_unref (column);
11938   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11939
11940   return tree_view->priv->n_columns;
11941 }
11942
11943 /**
11944  * gtk_tree_view_insert_column:
11945  * @tree_view: A #GtkTreeView.
11946  * @column: The #GtkTreeViewColumn to be inserted.
11947  * @position: The position to insert @column in.
11948  *
11949  * This inserts the @column into the @tree_view at @position.  If @position is
11950  * -1, then the column is inserted at the end. If @tree_view has
11951  * "fixed_height" mode enabled, then @column must have its "sizing" property
11952  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11953  *
11954  * Return value: The number of columns in @tree_view after insertion.
11955  **/
11956 gint
11957 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11958                              GtkTreeViewColumn *column,
11959                              gint               position)
11960 {
11961   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11962   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11963   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11964
11965   if (tree_view->priv->fixed_height_mode)
11966     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11967                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11968
11969   g_object_ref_sink (column);
11970
11971   if (tree_view->priv->n_columns == 0 &&
11972       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11973       gtk_tree_view_get_headers_visible (tree_view))
11974     {
11975       gdk_window_show (tree_view->priv->header_window);
11976     }
11977
11978   g_signal_connect (column, "notify::sizing",
11979                     G_CALLBACK (column_sizing_notify), tree_view);
11980
11981   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11982                                             column, position);
11983   tree_view->priv->n_columns++;
11984
11985   _gtk_tree_view_column_set_tree_view (column, tree_view);
11986
11987   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11988     {
11989       GList *list;
11990
11991       _gtk_tree_view_column_realize_button (column);
11992
11993       for (list = tree_view->priv->columns; list; list = list->next)
11994         {
11995           column = GTK_TREE_VIEW_COLUMN (list->data);
11996           if (gtk_tree_view_column_get_visible (column))
11997             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11998         }
11999       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12000     }
12001
12002   _gtk_tree_view_reset_header_styles (tree_view);
12003   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12004
12005   return tree_view->priv->n_columns;
12006 }
12007
12008 /**
12009  * gtk_tree_view_insert_column_with_attributes:
12010  * @tree_view: A #GtkTreeView
12011  * @position: The position to insert the new column in
12012  * @title: The title to set the header to
12013  * @cell: The #GtkCellRenderer
12014  * @...: A %NULL-terminated list of attributes
12015  *
12016  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
12017  * @position.  If @position is -1, then the newly created column is inserted at
12018  * the end.  The column is initialized with the attributes given. If @tree_view
12019  * has "fixed_height" mode enabled, then the new column will have its sizing
12020  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12021  *
12022  * Return value: The number of columns in @tree_view after insertion.
12023  **/
12024 gint
12025 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12026                                              gint             position,
12027                                              const gchar     *title,
12028                                              GtkCellRenderer *cell,
12029                                              ...)
12030 {
12031   GtkTreeViewColumn *column;
12032   gchar *attribute;
12033   va_list args;
12034   gint column_id;
12035
12036   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12037
12038   column = gtk_tree_view_column_new ();
12039   if (tree_view->priv->fixed_height_mode)
12040     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12041
12042   gtk_tree_view_column_set_title (column, title);
12043   gtk_tree_view_column_pack_start (column, cell, TRUE);
12044
12045   va_start (args, cell);
12046
12047   attribute = va_arg (args, gchar *);
12048
12049   while (attribute != NULL)
12050     {
12051       column_id = va_arg (args, gint);
12052       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12053       attribute = va_arg (args, gchar *);
12054     }
12055
12056   va_end (args);
12057
12058   gtk_tree_view_insert_column (tree_view, column, position);
12059
12060   return tree_view->priv->n_columns;
12061 }
12062
12063 /**
12064  * gtk_tree_view_insert_column_with_data_func:
12065  * @tree_view: a #GtkTreeView
12066  * @position: Position to insert, -1 for append
12067  * @title: column title
12068  * @cell: cell renderer for column
12069  * @func: function to set attributes of cell renderer
12070  * @data: data for @func
12071  * @dnotify: destroy notifier for @data
12072  *
12073  * Convenience function that inserts a new column into the #GtkTreeView
12074  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
12075  * attributes (normally using data from the model). See also
12076  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12077  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12078  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12079  *
12080  * Return value: number of columns in the tree view post-insert
12081  **/
12082 gint
12083 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12084                                              gint                       position,
12085                                              const gchar               *title,
12086                                              GtkCellRenderer           *cell,
12087                                              GtkTreeCellDataFunc        func,
12088                                              gpointer                   data,
12089                                              GDestroyNotify             dnotify)
12090 {
12091   GtkTreeViewColumn *column;
12092
12093   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12094
12095   column = gtk_tree_view_column_new ();
12096   if (tree_view->priv->fixed_height_mode)
12097     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12098
12099   gtk_tree_view_column_set_title (column, title);
12100   gtk_tree_view_column_pack_start (column, cell, TRUE);
12101   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12102
12103   gtk_tree_view_insert_column (tree_view, column, position);
12104
12105   return tree_view->priv->n_columns;
12106 }
12107
12108 /**
12109  * gtk_tree_view_get_column:
12110  * @tree_view: A #GtkTreeView.
12111  * @n: The position of the column, counting from 0.
12112  *
12113  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12114  *
12115  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12116  *     position is outside the range of columns.
12117  **/
12118 GtkTreeViewColumn *
12119 gtk_tree_view_get_column (GtkTreeView *tree_view,
12120                           gint         n)
12121 {
12122   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12123
12124   if (n < 0 || n >= tree_view->priv->n_columns)
12125     return NULL;
12126
12127   if (tree_view->priv->columns == NULL)
12128     return NULL;
12129
12130   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12131 }
12132
12133 /**
12134  * gtk_tree_view_get_columns:
12135  * @tree_view: A #GtkTreeView
12136  *
12137  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12138  * The returned list must be freed with g_list_free ().
12139  *
12140  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12141  **/
12142 GList *
12143 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12144 {
12145   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12146
12147   return g_list_copy (tree_view->priv->columns);
12148 }
12149
12150 /**
12151  * gtk_tree_view_move_column_after:
12152  * @tree_view: A #GtkTreeView
12153  * @column: The #GtkTreeViewColumn to be moved.
12154  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12155  *
12156  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12157  * @column is placed in the first position.
12158  **/
12159 void
12160 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12161                                  GtkTreeViewColumn *column,
12162                                  GtkTreeViewColumn *base_column)
12163 {
12164   GList *column_list_el, *base_el = NULL;
12165
12166   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12167
12168   column_list_el = g_list_find (tree_view->priv->columns, column);
12169   g_return_if_fail (column_list_el != NULL);
12170
12171   if (base_column)
12172     {
12173       base_el = g_list_find (tree_view->priv->columns, base_column);
12174       g_return_if_fail (base_el != NULL);
12175     }
12176
12177   if (column_list_el->prev == base_el)
12178     return;
12179
12180   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12181   if (base_el == NULL)
12182     {
12183       column_list_el->prev = NULL;
12184       column_list_el->next = tree_view->priv->columns;
12185       if (column_list_el->next)
12186         column_list_el->next->prev = column_list_el;
12187       tree_view->priv->columns = column_list_el;
12188     }
12189   else
12190     {
12191       column_list_el->prev = base_el;
12192       column_list_el->next = base_el->next;
12193       if (column_list_el->next)
12194         column_list_el->next->prev = column_list_el;
12195       base_el->next = column_list_el;
12196     }
12197
12198   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12199     {
12200       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12201       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12202     }
12203
12204   _gtk_tree_view_reset_header_styles (tree_view);
12205   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12206 }
12207
12208 /**
12209  * gtk_tree_view_set_expander_column:
12210  * @tree_view: A #GtkTreeView
12211  * @column: %NULL, or the column to draw the expander arrow at.
12212  *
12213  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12214  * If @column is %NULL, then the expander arrow is always at the first 
12215  * visible column.
12216  *
12217  * If you do not want expander arrow to appear in your tree, set the 
12218  * expander column to a hidden column.
12219  **/
12220 void
12221 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12222                                    GtkTreeViewColumn *column)
12223 {
12224   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12225   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12226
12227   if (tree_view->priv->expander_column != column)
12228     {
12229       GList *list;
12230
12231       if (column)
12232         {
12233           /* Confirm that column is in tree_view */
12234           for (list = tree_view->priv->columns; list; list = list->next)
12235             if (list->data == column)
12236               break;
12237           g_return_if_fail (list != NULL);
12238         }
12239
12240       tree_view->priv->expander_column = column;
12241       g_object_notify (G_OBJECT (tree_view), "expander-column");
12242     }
12243 }
12244
12245 /**
12246  * gtk_tree_view_get_expander_column:
12247  * @tree_view: A #GtkTreeView
12248  *
12249  * Returns the column that is the current expander column.
12250  * This column has the expander arrow drawn next to it.
12251  *
12252  * Return value: (transfer none): The expander column.
12253  **/
12254 GtkTreeViewColumn *
12255 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12256 {
12257   GList *list;
12258
12259   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12260
12261   for (list = tree_view->priv->columns; list; list = list->next)
12262     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12263       return (GtkTreeViewColumn *) list->data;
12264   return NULL;
12265 }
12266
12267
12268 /**
12269  * gtk_tree_view_set_column_drag_function:
12270  * @tree_view: A #GtkTreeView.
12271  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12272  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12273  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12274  *
12275  * Sets a user function for determining where a column may be dropped when
12276  * dragged.  This function is called on every column pair in turn at the
12277  * beginning of a column drag to determine where a drop can take place.  The
12278  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12279  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12280  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12281  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12282  * @tree_view reverts to the default behavior of allowing all columns to be
12283  * dropped everywhere.
12284  **/
12285 void
12286 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12287                                         GtkTreeViewColumnDropFunc  func,
12288                                         gpointer                   user_data,
12289                                         GDestroyNotify             destroy)
12290 {
12291   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12292
12293   if (tree_view->priv->column_drop_func_data_destroy)
12294     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12295
12296   tree_view->priv->column_drop_func = func;
12297   tree_view->priv->column_drop_func_data = user_data;
12298   tree_view->priv->column_drop_func_data_destroy = destroy;
12299 }
12300
12301 /**
12302  * gtk_tree_view_scroll_to_point:
12303  * @tree_view: a #GtkTreeView
12304  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12305  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12306  *
12307  * Scrolls the tree view such that the top-left corner of the visible
12308  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12309  * in tree coordinates.  The @tree_view must be realized before
12310  * this function is called.  If it isn't, you probably want to be
12311  * using gtk_tree_view_scroll_to_cell().
12312  *
12313  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12314  **/
12315 void
12316 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12317                                gint         tree_x,
12318                                gint         tree_y)
12319 {
12320   GtkAdjustment *hadj;
12321   GtkAdjustment *vadj;
12322
12323   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12324   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12325
12326   hadj = tree_view->priv->hadjustment;
12327   vadj = tree_view->priv->vadjustment;
12328
12329   if (tree_x != -1)
12330     gtk_adjustment_set_value (hadj, tree_x);
12331   if (tree_y != -1)
12332     gtk_adjustment_set_value (vadj, tree_y);
12333 }
12334
12335 /**
12336  * gtk_tree_view_scroll_to_cell:
12337  * @tree_view: A #GtkTreeView.
12338  * @path: (allow-none): The path of the row to move to, or %NULL.
12339  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12340  * @use_align: whether to use alignment arguments, or %FALSE.
12341  * @row_align: The vertical alignment of the row specified by @path.
12342  * @col_align: The horizontal alignment of the column specified by @column.
12343  *
12344  * Moves the alignments of @tree_view to the position specified by @column and
12345  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12346  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12347  * or @path need to be non-%NULL.  @row_align determines where the row is
12348  * placed, and @col_align determines where @column is placed.  Both are expected
12349  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12350  * right/bottom alignment, 0.5 means center.
12351  *
12352  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12353  * tree does the minimum amount of work to scroll the cell onto the screen.
12354  * This means that the cell will be scrolled to the edge closest to its current
12355  * position.  If the cell is currently visible on the screen, nothing is done.
12356  *
12357  * This function only works if the model is set, and @path is a valid row on the
12358  * model.  If the model changes before the @tree_view is realized, the centered
12359  * path will be modified to reflect this change.
12360  **/
12361 void
12362 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12363                               GtkTreePath       *path,
12364                               GtkTreeViewColumn *column,
12365                               gboolean           use_align,
12366                               gfloat             row_align,
12367                               gfloat             col_align)
12368 {
12369   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12370   g_return_if_fail (tree_view->priv->model != NULL);
12371   g_return_if_fail (tree_view->priv->tree != NULL);
12372   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12373   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12374   g_return_if_fail (path != NULL || column != NULL);
12375
12376 #if 0
12377   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12378            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12379 #endif
12380   row_align = CLAMP (row_align, 0.0, 1.0);
12381   col_align = CLAMP (col_align, 0.0, 1.0);
12382
12383
12384   /* Note: Despite the benefits that come from having one code path for the
12385    * scrolling code, we short-circuit validate_visible_area's immplementation as
12386    * it is much slower than just going to the point.
12387    */
12388   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12389       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12390       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12391       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12392     {
12393       if (tree_view->priv->scroll_to_path)
12394         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12395
12396       tree_view->priv->scroll_to_path = NULL;
12397       tree_view->priv->scroll_to_column = NULL;
12398
12399       if (path)
12400         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12401       if (column)
12402         tree_view->priv->scroll_to_column = column;
12403       tree_view->priv->scroll_to_use_align = use_align;
12404       tree_view->priv->scroll_to_row_align = row_align;
12405       tree_view->priv->scroll_to_col_align = col_align;
12406
12407       install_presize_handler (tree_view);
12408     }
12409   else
12410     {
12411       GdkRectangle cell_rect;
12412       GdkRectangle vis_rect;
12413       gint dest_x, dest_y;
12414
12415       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12416       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12417
12418       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12419
12420       dest_x = vis_rect.x;
12421       dest_y = vis_rect.y;
12422
12423       if (column)
12424         {
12425           if (use_align)
12426             {
12427               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12428             }
12429           else
12430             {
12431               if (cell_rect.x < vis_rect.x)
12432                 dest_x = cell_rect.x;
12433               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12434                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12435             }
12436         }
12437
12438       if (path)
12439         {
12440           if (use_align)
12441             {
12442               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12443               dest_y = MAX (dest_y, 0);
12444             }
12445           else
12446             {
12447               if (cell_rect.y < vis_rect.y)
12448                 dest_y = cell_rect.y;
12449               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12450                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12451             }
12452         }
12453
12454       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12455     }
12456 }
12457
12458 /**
12459  * gtk_tree_view_row_activated:
12460  * @tree_view: A #GtkTreeView
12461  * @path: The #GtkTreePath to be activated.
12462  * @column: The #GtkTreeViewColumn to be activated.
12463  *
12464  * Activates the cell determined by @path and @column.
12465  **/
12466 void
12467 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12468                              GtkTreePath       *path,
12469                              GtkTreeViewColumn *column)
12470 {
12471   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12472
12473   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12474 }
12475
12476
12477 static void
12478 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12479                                           GtkRBNode *node,
12480                                           gpointer   data)
12481 {
12482   GtkTreeView *tree_view = data;
12483
12484   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12485       node->children)
12486     {
12487       GtkTreePath *path;
12488       GtkTreeIter iter;
12489
12490       path = _gtk_tree_view_find_path (tree_view, tree, node);
12491       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12492
12493       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12494
12495       gtk_tree_path_free (path);
12496     }
12497
12498   if (node->children)
12499     _gtk_rbtree_traverse (node->children,
12500                           node->children->root,
12501                           G_PRE_ORDER,
12502                           gtk_tree_view_expand_all_emission_helper,
12503                           tree_view);
12504 }
12505
12506 /**
12507  * gtk_tree_view_expand_all:
12508  * @tree_view: A #GtkTreeView.
12509  *
12510  * Recursively expands all nodes in the @tree_view.
12511  **/
12512 void
12513 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12514 {
12515   GtkTreePath *path;
12516   GtkRBTree *tree;
12517   GtkRBNode *node;
12518
12519   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12520
12521   if (tree_view->priv->tree == NULL)
12522     return;
12523
12524   path = gtk_tree_path_new_first ();
12525   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12526
12527   while (node)
12528     {
12529       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12530       node = _gtk_rbtree_next (tree, node);
12531       gtk_tree_path_next (path);
12532   }
12533
12534   gtk_tree_path_free (path);
12535 }
12536
12537 /**
12538  * gtk_tree_view_collapse_all:
12539  * @tree_view: A #GtkTreeView.
12540  *
12541  * Recursively collapses all visible, expanded nodes in @tree_view.
12542  **/
12543 void
12544 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12545 {
12546   GtkRBTree *tree;
12547   GtkRBNode *node;
12548   GtkTreePath *path;
12549   gint *indices;
12550
12551   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12552
12553   if (tree_view->priv->tree == NULL)
12554     return;
12555
12556   path = gtk_tree_path_new ();
12557   gtk_tree_path_down (path);
12558   indices = gtk_tree_path_get_indices (path);
12559
12560   tree = tree_view->priv->tree;
12561   node = tree->root;
12562   while (node && node->left != tree->nil)
12563     node = node->left;
12564
12565   while (node)
12566     {
12567       if (node->children)
12568         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12569       indices[0]++;
12570       node = _gtk_rbtree_next (tree, node);
12571     }
12572
12573   gtk_tree_path_free (path);
12574 }
12575
12576 /**
12577  * gtk_tree_view_expand_to_path:
12578  * @tree_view: A #GtkTreeView.
12579  * @path: path to a row.
12580  *
12581  * Expands the row at @path. This will also expand all parent rows of
12582  * @path as necessary.
12583  *
12584  * Since: 2.2
12585  **/
12586 void
12587 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12588                               GtkTreePath *path)
12589 {
12590   gint i, depth;
12591   gint *indices;
12592   GtkTreePath *tmp;
12593
12594   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12595   g_return_if_fail (path != NULL);
12596
12597   depth = gtk_tree_path_get_depth (path);
12598   indices = gtk_tree_path_get_indices (path);
12599
12600   tmp = gtk_tree_path_new ();
12601   g_return_if_fail (tmp != NULL);
12602
12603   for (i = 0; i < depth; i++)
12604     {
12605       gtk_tree_path_append_index (tmp, indices[i]);
12606       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12607     }
12608
12609   gtk_tree_path_free (tmp);
12610 }
12611
12612 /* FIXME the bool return values for expand_row and collapse_row are
12613  * not analagous; they should be TRUE if the row had children and
12614  * was not already in the requested state.
12615  */
12616
12617
12618 static gboolean
12619 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12620                                GtkTreePath *path,
12621                                GtkRBTree   *tree,
12622                                GtkRBNode   *node,
12623                                gboolean     open_all,
12624                                gboolean     animate)
12625 {
12626   GtkTreeIter iter;
12627   GtkTreeIter temp;
12628   gboolean expand;
12629
12630   if (animate)
12631     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12632                   "gtk-enable-animations", &animate,
12633                   NULL);
12634
12635   remove_auto_expand_timeout (tree_view);
12636
12637   if (node->children && !open_all)
12638     return FALSE;
12639
12640   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12641     return FALSE;
12642
12643   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12644   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12645     return FALSE;
12646
12647
12648    if (node->children && open_all)
12649     {
12650       gboolean retval = FALSE;
12651       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12652
12653       gtk_tree_path_append_index (tmp_path, 0);
12654       tree = node->children;
12655       node = tree->root;
12656       while (node->left != tree->nil)
12657         node = node->left;
12658       /* try to expand the children */
12659       do
12660         {
12661          gboolean t;
12662          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12663                                             TRUE, animate);
12664          if (t)
12665            retval = TRUE;
12666
12667          gtk_tree_path_next (tmp_path);
12668          node = _gtk_rbtree_next (tree, node);
12669        }
12670       while (node != NULL);
12671
12672       gtk_tree_path_free (tmp_path);
12673
12674       return retval;
12675     }
12676
12677   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12678
12679   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12680     return FALSE;
12681
12682   if (expand)
12683     return FALSE;
12684
12685   node->children = _gtk_rbtree_new ();
12686   node->children->parent_tree = tree;
12687   node->children->parent_node = node;
12688
12689   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12690
12691   gtk_tree_view_build_tree (tree_view,
12692                             node->children,
12693                             &temp,
12694                             gtk_tree_path_get_depth (path) + 1,
12695                             open_all);
12696
12697   if (animate)
12698     {
12699       GtkStyleContext *context;
12700
12701       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12702
12703       gtk_style_context_save (context);
12704       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12705
12706       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12707                                              node, GTK_STATE_ACTIVE, TRUE);
12708
12709       _gtk_style_context_invalidate_animation_areas (context);
12710       gtk_style_context_restore (context);
12711     }
12712
12713   install_presize_handler (tree_view);
12714
12715   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12716   if (open_all && node->children)
12717     {
12718       _gtk_rbtree_traverse (node->children,
12719                             node->children->root,
12720                             G_PRE_ORDER,
12721                             gtk_tree_view_expand_all_emission_helper,
12722                             tree_view);
12723     }
12724   return TRUE;
12725 }
12726
12727
12728 /**
12729  * gtk_tree_view_expand_row:
12730  * @tree_view: a #GtkTreeView
12731  * @path: path to a row
12732  * @open_all: whether to recursively expand, or just expand immediate children
12733  *
12734  * Opens the row so its children are visible.
12735  *
12736  * Return value: %TRUE if the row existed and had children
12737  **/
12738 gboolean
12739 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12740                           GtkTreePath *path,
12741                           gboolean     open_all)
12742 {
12743   GtkRBTree *tree;
12744   GtkRBNode *node;
12745
12746   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12747   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12748   g_return_val_if_fail (path != NULL, FALSE);
12749
12750   if (_gtk_tree_view_find_node (tree_view,
12751                                 path,
12752                                 &tree,
12753                                 &node))
12754     return FALSE;
12755
12756   if (tree != NULL)
12757     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12758   else
12759     return FALSE;
12760 }
12761
12762 static gboolean
12763 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12764                                  GtkTreePath *path,
12765                                  GtkRBTree   *tree,
12766                                  GtkRBNode   *node,
12767                                  gboolean     animate)
12768 {
12769   GtkTreeIter iter;
12770   GtkTreeIter children;
12771   gboolean collapse;
12772   gint x, y;
12773   GList *list;
12774   GdkWindow *child, *parent;
12775
12776   if (animate)
12777     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12778                   "gtk-enable-animations", &animate,
12779                   NULL);
12780
12781   remove_auto_expand_timeout (tree_view);
12782
12783   if (node->children == NULL)
12784     return FALSE;
12785   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12786
12787   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12788
12789   if (collapse)
12790     return FALSE;
12791
12792   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12793    * a chance to prelight the correct node below */
12794
12795   if (tree_view->priv->prelight_tree)
12796     {
12797       GtkRBTree *parent_tree;
12798       GtkRBNode *parent_node;
12799
12800       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12801       parent_node = tree_view->priv->prelight_tree->parent_node;
12802       while (parent_tree)
12803         {
12804           if (parent_tree == tree && parent_node == node)
12805             {
12806               ensure_unprelighted (tree_view);
12807               break;
12808             }
12809           parent_node = parent_tree->parent_node;
12810           parent_tree = parent_tree->parent_tree;
12811         }
12812     }
12813
12814   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12815
12816   for (list = tree_view->priv->columns; list; list = list->next)
12817     {
12818       GtkTreeViewColumn *column = list->data;
12819
12820       if (gtk_tree_view_column_get_visible (column) == FALSE)
12821         continue;
12822       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12823         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12824     }
12825
12826   if (tree_view->priv->destroy_count_func)
12827     {
12828       GtkTreePath *child_path;
12829       gint child_count = 0;
12830       child_path = gtk_tree_path_copy (path);
12831       gtk_tree_path_down (child_path);
12832       if (node->children)
12833         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12834       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12835       gtk_tree_path_free (child_path);
12836     }
12837
12838   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12839     {
12840       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12841
12842       if (gtk_tree_path_is_ancestor (path, cursor_path))
12843         {
12844           gtk_tree_row_reference_free (tree_view->priv->cursor);
12845           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12846                                                                       tree_view->priv->model,
12847                                                                       path);
12848         }
12849       gtk_tree_path_free (cursor_path);
12850     }
12851
12852   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12853     {
12854       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12855       if (gtk_tree_path_is_ancestor (path, anchor_path))
12856         {
12857           gtk_tree_row_reference_free (tree_view->priv->anchor);
12858           tree_view->priv->anchor = NULL;
12859         }
12860       gtk_tree_path_free (anchor_path);
12861     }
12862
12863   /* Stop a pending double click */
12864   tree_view->priv->last_button_x = -1;
12865   tree_view->priv->last_button_y = -1;
12866
12867   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12868     {
12869       _gtk_rbtree_remove (node->children);
12870       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12871     }
12872   else
12873     _gtk_rbtree_remove (node->children);
12874
12875   if (animate)
12876     {
12877       GtkStyleContext *context;
12878
12879       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12880
12881       gtk_style_context_save (context);
12882       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12883
12884       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12885                                              node, GTK_STATE_ACTIVE, FALSE);
12886
12887       _gtk_style_context_invalidate_animation_areas (context);
12888       gtk_style_context_restore (context);
12889     }
12890
12891   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12892     {
12893       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12894     }
12895
12896   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12897   
12898   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12899     {
12900       /* now that we've collapsed all rows, we want to try to set the prelight
12901        * again. To do this, we fake a motion event and send it to ourselves. */
12902
12903       child = tree_view->priv->bin_window;
12904       parent = gdk_window_get_parent (child);
12905
12906       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12907         {
12908           GdkEventMotion event;
12909           gint child_x, child_y;
12910
12911           gdk_window_get_position (child, &child_x, &child_y);
12912
12913           event.window = tree_view->priv->bin_window;
12914           event.x = x - child_x;
12915           event.y = y - child_y;
12916
12917           /* despite the fact this isn't a real event, I'm almost positive it will
12918            * never trigger a drag event.  maybe_drag is the only function that uses
12919            * more than just event.x and event.y. */
12920           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12921         }
12922     }
12923
12924   return TRUE;
12925 }
12926
12927 /**
12928  * gtk_tree_view_collapse_row:
12929  * @tree_view: a #GtkTreeView
12930  * @path: path to a row in the @tree_view
12931  *
12932  * Collapses a row (hides its child rows, if they exist).
12933  *
12934  * Return value: %TRUE if the row was collapsed.
12935  **/
12936 gboolean
12937 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12938                             GtkTreePath *path)
12939 {
12940   GtkRBTree *tree;
12941   GtkRBNode *node;
12942
12943   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12944   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12945   g_return_val_if_fail (path != NULL, FALSE);
12946
12947   if (_gtk_tree_view_find_node (tree_view,
12948                                 path,
12949                                 &tree,
12950                                 &node))
12951     return FALSE;
12952
12953   if (tree == NULL || node->children == NULL)
12954     return FALSE;
12955
12956   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12957 }
12958
12959 static void
12960 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12961                                         GtkRBTree              *tree,
12962                                         GtkTreePath            *path,
12963                                         GtkTreeViewMappingFunc  func,
12964                                         gpointer                user_data)
12965 {
12966   GtkRBNode *node;
12967
12968   if (tree == NULL || tree->root == NULL)
12969     return;
12970
12971   node = tree->root;
12972
12973   while (node && node->left != tree->nil)
12974     node = node->left;
12975
12976   while (node)
12977     {
12978       if (node->children)
12979         {
12980           (* func) (tree_view, path, user_data);
12981           gtk_tree_path_down (path);
12982           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12983           gtk_tree_path_up (path);
12984         }
12985       gtk_tree_path_next (path);
12986       node = _gtk_rbtree_next (tree, node);
12987     }
12988 }
12989
12990 /**
12991  * gtk_tree_view_map_expanded_rows:
12992  * @tree_view: A #GtkTreeView
12993  * @func: (scope call): A function to be called
12994  * @data: User data to be passed to the function.
12995  *
12996  * Calls @func on all expanded rows.
12997  **/
12998 void
12999 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
13000                                  GtkTreeViewMappingFunc  func,
13001                                  gpointer                user_data)
13002 {
13003   GtkTreePath *path;
13004
13005   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13006   g_return_if_fail (func != NULL);
13007
13008   path = gtk_tree_path_new_first ();
13009
13010   gtk_tree_view_map_expanded_rows_helper (tree_view,
13011                                           tree_view->priv->tree,
13012                                           path, func, user_data);
13013
13014   gtk_tree_path_free (path);
13015 }
13016
13017 /**
13018  * gtk_tree_view_row_expanded:
13019  * @tree_view: A #GtkTreeView.
13020  * @path: A #GtkTreePath to test expansion state.
13021  *
13022  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13023  *
13024  * Return value: %TRUE if #path is expanded.
13025  **/
13026 gboolean
13027 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13028                             GtkTreePath *path)
13029 {
13030   GtkRBTree *tree;
13031   GtkRBNode *node;
13032
13033   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13034   g_return_val_if_fail (path != NULL, FALSE);
13035
13036   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13037
13038   if (node == NULL)
13039     return FALSE;
13040
13041   return (node->children != NULL);
13042 }
13043
13044 /**
13045  * gtk_tree_view_get_reorderable:
13046  * @tree_view: a #GtkTreeView
13047  *
13048  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13049  * gtk_tree_view_set_reorderable().
13050  *
13051  * Return value: %TRUE if the tree can be reordered.
13052  **/
13053 gboolean
13054 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13055 {
13056   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13057
13058   return tree_view->priv->reorderable;
13059 }
13060
13061 /**
13062  * gtk_tree_view_set_reorderable:
13063  * @tree_view: A #GtkTreeView.
13064  * @reorderable: %TRUE, if the tree can be reordered.
13065  *
13066  * This function is a convenience function to allow you to reorder
13067  * models that support the #GtkTreeDragSourceIface and the
13068  * #GtkTreeDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13069  * these.  If @reorderable is %TRUE, then the user can reorder the
13070  * model by dragging and dropping rows. The developer can listen to
13071  * these changes by connecting to the model's row_inserted and
13072  * row_deleted signals. The reordering is implemented by setting up
13073  * the tree view as a drag source and destination. Therefore, drag and
13074  * drop can not be used in a reorderable view for any other purpose.
13075  *
13076  * This function does not give you any degree of control over the order -- any
13077  * reordering is allowed.  If more control is needed, you should probably
13078  * handle drag and drop manually.
13079  **/
13080 void
13081 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13082                                gboolean     reorderable)
13083 {
13084   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13085
13086   reorderable = reorderable != FALSE;
13087
13088   if (tree_view->priv->reorderable == reorderable)
13089     return;
13090
13091   if (reorderable)
13092     {
13093       const GtkTargetEntry row_targets[] = {
13094         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13095       };
13096
13097       gtk_tree_view_enable_model_drag_source (tree_view,
13098                                               GDK_BUTTON1_MASK,
13099                                               row_targets,
13100                                               G_N_ELEMENTS (row_targets),
13101                                               GDK_ACTION_MOVE);
13102       gtk_tree_view_enable_model_drag_dest (tree_view,
13103                                             row_targets,
13104                                             G_N_ELEMENTS (row_targets),
13105                                             GDK_ACTION_MOVE);
13106     }
13107   else
13108     {
13109       gtk_tree_view_unset_rows_drag_source (tree_view);
13110       gtk_tree_view_unset_rows_drag_dest (tree_view);
13111     }
13112
13113   tree_view->priv->reorderable = reorderable;
13114
13115   g_object_notify (G_OBJECT (tree_view), "reorderable");
13116 }
13117
13118 static void
13119 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13120                                GtkTreePath     *path,
13121                                gboolean         clear_and_select,
13122                                gboolean         clamp_node)
13123 {
13124   GtkRBTree *tree = NULL;
13125   GtkRBNode *node = NULL;
13126
13127   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13128     {
13129       GtkTreePath *cursor_path;
13130       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13131       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
13132       gtk_tree_path_free (cursor_path);
13133     }
13134
13135   gtk_tree_row_reference_free (tree_view->priv->cursor);
13136   tree_view->priv->cursor = NULL;
13137
13138   /* One cannot set the cursor on a separator.   Also, if
13139    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13140    * before finding the tree and node belonging to path.  The
13141    * path maps to a non-existing path and we will silently bail out.
13142    * We unset tree and node to avoid further processing.
13143    */
13144   if (!row_is_separator (tree_view, NULL, path)
13145       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
13146     {
13147       tree_view->priv->cursor =
13148           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
13149                                             tree_view->priv->model,
13150                                             path);
13151     }
13152   else
13153     {
13154       tree = NULL;
13155       node = NULL;
13156     }
13157
13158   if (tree != NULL)
13159     {
13160       GtkRBTree *new_tree = NULL;
13161       GtkRBNode *new_node = NULL;
13162
13163       if (clear_and_select && !tree_view->priv->modify_selection_pressed)
13164         {
13165           GtkTreeSelectMode mode = 0;
13166
13167           if (tree_view->priv->extend_selection_pressed)
13168             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13169
13170           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13171                                                     node, tree, path, mode,
13172                                                     FALSE);
13173         }
13174
13175       /* We have to re-find tree and node here again, somebody might have
13176        * cleared the node or the whole tree in the GtkTreeSelection::changed
13177        * callback. If the nodes differ we bail out here.
13178        */
13179       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13180
13181       if (tree != new_tree || node != new_node)
13182         return;
13183
13184       if (clamp_node)
13185         {
13186           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
13187           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13188         }
13189     }
13190
13191   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13192 }
13193
13194 /**
13195  * gtk_tree_view_get_cursor:
13196  * @tree_view: A #GtkTreeView
13197  * @path: (out) (transfer full) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13198  * @focus_column: (out) (transfer none) (allow-none): A pointer to be filled with the current focus column, or %NULL
13199  *
13200  * Fills in @path and @focus_column with the current path and focus column.  If
13201  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13202  * currently has focus, then *@focus_column will be %NULL.
13203  *
13204  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13205  * you are done with it.
13206  **/
13207 void
13208 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13209                           GtkTreePath       **path,
13210                           GtkTreeViewColumn **focus_column)
13211 {
13212   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13213
13214   if (path)
13215     {
13216       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13217         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13218       else
13219         *path = NULL;
13220     }
13221
13222   if (focus_column)
13223     {
13224       *focus_column = tree_view->priv->focus_column;
13225     }
13226 }
13227
13228 /**
13229  * gtk_tree_view_set_cursor:
13230  * @tree_view: A #GtkTreeView
13231  * @path: A #GtkTreePath
13232  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13233  * @start_editing: %TRUE if the specified cell should start being edited.
13234  *
13235  * Sets the current keyboard focus to be at @path, and selects it.  This is
13236  * useful when you want to focus the user's attention on a particular row.  If
13237  * @focus_column is not %NULL, then focus is given to the column specified by 
13238  * it. Additionally, if @focus_column is specified, and @start_editing is 
13239  * %TRUE, then editing should be started in the specified cell.  
13240  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13241  * in order to give keyboard focus to the widget.  Please note that editing 
13242  * can only happen when the widget is realized.
13243  *
13244  * If @path is invalid for @model, the current cursor (if any) will be unset
13245  * and the function will return without failing.
13246  **/
13247 void
13248 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13249                           GtkTreePath       *path,
13250                           GtkTreeViewColumn *focus_column,
13251                           gboolean           start_editing)
13252 {
13253   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13254                                     NULL, start_editing);
13255 }
13256
13257 /**
13258  * gtk_tree_view_set_cursor_on_cell:
13259  * @tree_view: A #GtkTreeView
13260  * @path: A #GtkTreePath
13261  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13262  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13263  * @start_editing: %TRUE if the specified cell should start being edited.
13264  *
13265  * Sets the current keyboard focus to be at @path, and selects it.  This is
13266  * useful when you want to focus the user's attention on a particular row.  If
13267  * @focus_column is not %NULL, then focus is given to the column specified by
13268  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13269  * contains 2 or more editable or activatable cells, then focus is given to
13270  * the cell specified by @focus_cell. Additionally, if @focus_column is
13271  * specified, and @start_editing is %TRUE, then editing should be started in
13272  * the specified cell.  This function is often followed by
13273  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13274  * widget.  Please note that editing can only happen when the widget is
13275  * realized.
13276  *
13277  * If @path is invalid for @model, the current cursor (if any) will be unset
13278  * and the function will return without failing.
13279  *
13280  * Since: 2.2
13281  **/
13282 void
13283 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13284                                   GtkTreePath       *path,
13285                                   GtkTreeViewColumn *focus_column,
13286                                   GtkCellRenderer   *focus_cell,
13287                                   gboolean           start_editing)
13288 {
13289   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13290   g_return_if_fail (path != NULL);
13291   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13292
13293   if (!tree_view->priv->model)
13294     return;
13295
13296   if (focus_cell)
13297     {
13298       g_return_if_fail (focus_column);
13299       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13300     }
13301
13302   /* cancel the current editing, if it exists */
13303   if (tree_view->priv->edited_column &&
13304       gtk_cell_area_get_edit_widget
13305       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13306     gtk_tree_view_stop_editing (tree_view, TRUE);
13307
13308   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
13309
13310   if (focus_column &&
13311       gtk_tree_view_column_get_visible (focus_column))
13312     {
13313       GList *list;
13314       gboolean column_in_tree = FALSE;
13315
13316       for (list = tree_view->priv->columns; list; list = list->next)
13317         if (list->data == focus_column)
13318           {
13319             column_in_tree = TRUE;
13320             break;
13321           }
13322       g_return_if_fail (column_in_tree);
13323       tree_view->priv->focus_column = focus_column;
13324       if (focus_cell)
13325         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13326       if (start_editing)
13327         gtk_tree_view_start_editing (tree_view, path, TRUE);
13328     }
13329 }
13330
13331 /**
13332  * gtk_tree_view_get_bin_window:
13333  * @tree_view: A #GtkTreeView
13334  *
13335  * Returns the window that @tree_view renders to.
13336  * This is used primarily to compare to <literal>event->window</literal>
13337  * to confirm that the event on @tree_view is on the right window.
13338  *
13339  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13340  *     hasn't been realized yet
13341  **/
13342 GdkWindow *
13343 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13344 {
13345   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13346
13347   return tree_view->priv->bin_window;
13348 }
13349
13350 /**
13351  * gtk_tree_view_get_path_at_pos:
13352  * @tree_view: A #GtkTreeView.
13353  * @x: The x position to be identified (relative to bin_window).
13354  * @y: The y position to be identified (relative to bin_window).
13355  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13356  * @column: (out) (transfer none) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13357  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13358  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13359  *
13360  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13361  * (please see gtk_tree_view_get_bin_window()).
13362  * That is, @x and @y are relative to an events coordinates. @x and @y must
13363  * come from an event on the @tree_view only where <literal>event->window ==
13364  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13365  * things like popup menus. If @path is non-%NULL, then it will be filled
13366  * with the #GtkTreePath at that point.  This path should be freed with
13367  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13368  * with the column at that point.  @cell_x and @cell_y return the coordinates
13369  * relative to the cell background (i.e. the @background_area passed to
13370  * gtk_cell_renderer_render()).  This function is only meaningful if
13371  * @tree_view is realized.  Therefore this function will always return %FALSE
13372  * if @tree_view is not realized or does not have a model.
13373  *
13374  * For converting widget coordinates (eg. the ones you get from
13375  * GtkWidget::query-tooltip), please see
13376  * gtk_tree_view_convert_widget_to_bin_window_coords().
13377  *
13378  * Return value: %TRUE if a row exists at that coordinate.
13379  **/
13380 gboolean
13381 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13382                                gint                x,
13383                                gint                y,
13384                                GtkTreePath       **path,
13385                                GtkTreeViewColumn **column,
13386                                gint               *cell_x,
13387                                gint               *cell_y)
13388 {
13389   GtkRBTree *tree;
13390   GtkRBNode *node;
13391   gint y_offset;
13392
13393   g_return_val_if_fail (tree_view != NULL, FALSE);
13394
13395   if (path)
13396     *path = NULL;
13397   if (column)
13398     *column = NULL;
13399
13400   if (tree_view->priv->bin_window == NULL)
13401     return FALSE;
13402
13403   if (tree_view->priv->tree == NULL)
13404     return FALSE;
13405
13406   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13407     return FALSE;
13408
13409   if (x < 0 || y < 0)
13410     return FALSE;
13411
13412   if (column || cell_x)
13413     {
13414       GtkTreeViewColumn *tmp_column;
13415       GtkTreeViewColumn *last_column = NULL;
13416       GList *list;
13417       gint remaining_x = x;
13418       gboolean found = FALSE;
13419       gboolean rtl;
13420       gint width;
13421
13422       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13423       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13424            list;
13425            list = (rtl ? list->prev : list->next))
13426         {
13427           tmp_column = list->data;
13428
13429           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13430             continue;
13431
13432           last_column = tmp_column;
13433           width = gtk_tree_view_column_get_width (tmp_column);
13434           if (remaining_x <= width)
13435             {
13436               found = TRUE;
13437
13438               if (column)
13439                 *column = tmp_column;
13440
13441               if (cell_x)
13442                 *cell_x = remaining_x;
13443
13444               break;
13445             }
13446           remaining_x -= width;
13447         }
13448
13449       /* If found is FALSE and there is a last_column, then it the remainder
13450        * space is in that area
13451        */
13452       if (!found)
13453         {
13454           if (last_column)
13455             {
13456               if (column)
13457                 *column = last_column;
13458               
13459               if (cell_x)
13460                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13461             }
13462           else
13463             {
13464               return FALSE;
13465             }
13466         }
13467     }
13468
13469   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13470                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13471                                       &tree, &node);
13472
13473   if (tree == NULL)
13474     return FALSE;
13475
13476   if (cell_y)
13477     *cell_y = y_offset;
13478
13479   if (path)
13480     *path = _gtk_tree_view_find_path (tree_view, tree, node);
13481
13482   return TRUE;
13483 }
13484
13485
13486 static inline gint
13487 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13488                                     GtkRBNode   *node,
13489                                     gint         vertical_separator)
13490 {
13491   int height;
13492
13493   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13494    * i.e. just the cells, no spacing.
13495    *
13496    * The cell area height is at least expander_size - vertical_separator.
13497    * For regular nodes, the height is then at least expander_size. We should
13498    * be able to enforce the expander_size minimum here, because this
13499    * function will not be called for irregular (e.g. separator) rows.
13500    */
13501   height = gtk_tree_view_get_row_height (tree_view, node);
13502   if (height < tree_view->priv->expander_size)
13503     height = tree_view->priv->expander_size;
13504
13505   return height - vertical_separator;
13506 }
13507
13508 static inline gint
13509 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13510                                       GtkRBTree   *tree,
13511                                       GtkRBNode   *node,
13512                                       gint         vertical_separator)
13513 {
13514   int offset;
13515
13516   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13517   offset += vertical_separator / 2;
13518
13519   return offset;
13520 }
13521
13522 /**
13523  * gtk_tree_view_get_cell_area:
13524  * @tree_view: a #GtkTreeView
13525  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13526  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13527  * @rect: (out): rectangle to fill with cell rect
13528  *
13529  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13530  * row specified by @path and the column specified by @column.  If @path is
13531  * %NULL, or points to a path not currently displayed, the @y and @height fields
13532  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13533  * fields will be filled with 0.  The sum of all cell rects does not cover the
13534  * entire tree; there are extra pixels in between rows, for example. The
13535  * returned rectangle is equivalent to the @cell_area passed to
13536  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13537  * realized.
13538  **/
13539 void
13540 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13541                              GtkTreePath        *path,
13542                              GtkTreeViewColumn  *column,
13543                              GdkRectangle       *rect)
13544 {
13545   GtkRBTree *tree = NULL;
13546   GtkRBNode *node = NULL;
13547   gint vertical_separator;
13548   gint horizontal_separator;
13549
13550   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13551   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13552   g_return_if_fail (rect != NULL);
13553   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13554   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13555
13556   gtk_widget_style_get (GTK_WIDGET (tree_view),
13557                         "vertical-separator", &vertical_separator,
13558                         "horizontal-separator", &horizontal_separator,
13559                         NULL);
13560
13561   rect->x = 0;
13562   rect->y = 0;
13563   rect->width = 0;
13564   rect->height = 0;
13565
13566   if (column)
13567     {
13568       rect->x = gtk_tree_view_column_get_x_offset (column) + horizontal_separator/2;
13569       rect->width = gtk_tree_view_column_get_width (column) - horizontal_separator;
13570     }
13571
13572   if (path)
13573     {
13574       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13575
13576       /* Get vertical coords */
13577       if ((!ret && tree == NULL) || ret)
13578         return;
13579
13580       if (row_is_separator (tree_view, NULL, path))
13581         {
13582           /* There isn't really a "cell area" for separator, so we
13583            * return the y, height values for background area instead.
13584            */
13585           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13586           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13587         }
13588       else
13589         {
13590           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13591                                                           vertical_separator);
13592           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13593                                                              vertical_separator);
13594         }
13595
13596       if (column &&
13597           gtk_tree_view_is_expander_column (tree_view, column))
13598         {
13599           gint depth = gtk_tree_path_get_depth (path);
13600           gboolean rtl;
13601
13602           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13603
13604           if (!rtl)
13605             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13606           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13607
13608           if (gtk_tree_view_draw_expanders (tree_view))
13609             {
13610               if (!rtl)
13611                 rect->x += depth * tree_view->priv->expander_size;
13612               rect->width -= depth * tree_view->priv->expander_size;
13613             }
13614
13615           rect->width = MAX (rect->width, 0);
13616         }
13617     }
13618 }
13619
13620 static inline gint
13621 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13622                               GtkRBNode   *node)
13623 {
13624   int height;
13625
13626   /* The "background" areas of all rows/cells add up to cover the entire tree.
13627    * The background includes all inter-row and inter-cell spacing.
13628    *
13629    * If the row pointed at by node does not have a height set, we default
13630    * to expander_size, which is the minimum height for regular nodes.
13631    * Non-regular nodes (e.g. separators) can have a height set smaller
13632    * than expander_size and should not be overruled here.
13633    */
13634   height = GTK_RBNODE_GET_HEIGHT (node);
13635   if (height <= 0)
13636     height = tree_view->priv->expander_size;
13637
13638   return height;
13639 }
13640
13641 static inline gint
13642 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13643                                 GtkRBTree   *tree,
13644                                 GtkRBNode   *node)
13645 {
13646   int offset;
13647
13648   offset = _gtk_rbtree_node_find_offset (tree, node);
13649
13650   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13651 }
13652
13653 /**
13654  * gtk_tree_view_get_background_area:
13655  * @tree_view: a #GtkTreeView
13656  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13657  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13658  * @rect: (out): rectangle to fill with cell background rect
13659  *
13660  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13661  * row specified by @path and the column specified by @column.  If @path is
13662  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13663  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13664  * fields will be filled with 0.  The returned rectangle is equivalent to the
13665  * @background_area passed to gtk_cell_renderer_render().  These background
13666  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13667  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13668  * itself, excluding surrounding borders and the tree expander area.
13669  *
13670  **/
13671 void
13672 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13673                                    GtkTreePath        *path,
13674                                    GtkTreeViewColumn  *column,
13675                                    GdkRectangle       *rect)
13676 {
13677   GtkRBTree *tree = NULL;
13678   GtkRBNode *node = NULL;
13679
13680   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13681   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13682   g_return_if_fail (rect != NULL);
13683
13684   rect->x = 0;
13685   rect->y = 0;
13686   rect->width = 0;
13687   rect->height = 0;
13688
13689   if (path)
13690     {
13691       /* Get vertical coords */
13692
13693       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13694           tree == NULL)
13695         return;
13696
13697       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13698       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13699     }
13700
13701   if (column)
13702     {
13703       gint x2 = 0;
13704
13705       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13706       rect->width = x2 - rect->x;
13707     }
13708 }
13709
13710 /**
13711  * gtk_tree_view_get_visible_rect:
13712  * @tree_view: a #GtkTreeView
13713  * @visible_rect: (out): rectangle to fill
13714  *
13715  * Fills @visible_rect with the currently-visible region of the
13716  * buffer, in tree coordinates. Convert to bin_window coordinates with
13717  * gtk_tree_view_convert_tree_to_bin_window_coords().
13718  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13719  * scrollable area of the tree.
13720  **/
13721 void
13722 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13723                                 GdkRectangle *visible_rect)
13724 {
13725   GtkAllocation allocation;
13726   GtkWidget *widget;
13727
13728   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13729
13730   widget = GTK_WIDGET (tree_view);
13731
13732   if (visible_rect)
13733     {
13734       gtk_widget_get_allocation (widget, &allocation);
13735       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13736       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13737       visible_rect->width = allocation.width;
13738       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13739     }
13740 }
13741
13742 /**
13743  * gtk_tree_view_convert_widget_to_tree_coords:
13744  * @tree_view: a #GtkTreeView
13745  * @wx: X coordinate relative to the widget
13746  * @wy: Y coordinate relative to the widget
13747  * @tx: (out): return location for tree X coordinate
13748  * @ty: (out): return location for tree Y coordinate
13749  *
13750  * Converts widget coordinates to coordinates for the
13751  * tree (the full scrollable area of the tree).
13752  *
13753  * Since: 2.12
13754  **/
13755 void
13756 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13757                                              gint         wx,
13758                                              gint         wy,
13759                                              gint        *tx,
13760                                              gint        *ty)
13761 {
13762   gint x, y;
13763
13764   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13765
13766   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13767                                                      wx, wy,
13768                                                      &x, &y);
13769   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13770                                                    x, y,
13771                                                    tx, ty);
13772 }
13773
13774 /**
13775  * gtk_tree_view_convert_tree_to_widget_coords:
13776  * @tree_view: a #GtkTreeView
13777  * @tx: X coordinate relative to the tree
13778  * @ty: Y coordinate relative to the tree
13779  * @wx: (out): return location for widget X coordinate
13780  * @wy: (out): return location for widget Y coordinate
13781  *
13782  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13783  * to widget coordinates.
13784  *
13785  * Since: 2.12
13786  **/
13787 void
13788 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13789                                              gint         tx,
13790                                              gint         ty,
13791                                              gint        *wx,
13792                                              gint        *wy)
13793 {
13794   gint x, y;
13795
13796   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13797
13798   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13799                                                    tx, ty,
13800                                                    &x, &y);
13801   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13802                                                      x, y,
13803                                                      wx, wy);
13804 }
13805
13806 /**
13807  * gtk_tree_view_convert_widget_to_bin_window_coords:
13808  * @tree_view: a #GtkTreeView
13809  * @wx: X coordinate relative to the widget
13810  * @wy: Y coordinate relative to the widget
13811  * @bx: (out): return location for bin_window X coordinate
13812  * @by: (out): return location for bin_window Y coordinate
13813  *
13814  * Converts widget coordinates to coordinates for the bin_window
13815  * (see gtk_tree_view_get_bin_window()).
13816  *
13817  * Since: 2.12
13818  **/
13819 void
13820 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13821                                                    gint         wx,
13822                                                    gint         wy,
13823                                                    gint        *bx,
13824                                                    gint        *by)
13825 {
13826   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13827
13828   if (bx)
13829     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13830   if (by)
13831     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13832 }
13833
13834 /**
13835  * gtk_tree_view_convert_bin_window_to_widget_coords:
13836  * @tree_view: a #GtkTreeView
13837  * @bx: bin_window X coordinate
13838  * @by: bin_window Y coordinate
13839  * @wx: (out): return location for widget X coordinate
13840  * @wy: (out): return location for widget Y coordinate
13841  *
13842  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13843  * to widget relative coordinates.
13844  *
13845  * Since: 2.12
13846  **/
13847 void
13848 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13849                                                    gint         bx,
13850                                                    gint         by,
13851                                                    gint        *wx,
13852                                                    gint        *wy)
13853 {
13854   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13855
13856   if (wx)
13857     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13858   if (wy)
13859     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13860 }
13861
13862 /**
13863  * gtk_tree_view_convert_tree_to_bin_window_coords:
13864  * @tree_view: a #GtkTreeView
13865  * @tx: tree X coordinate
13866  * @ty: tree Y coordinate
13867  * @bx: (out): return location for X coordinate relative to bin_window
13868  * @by: (out): return location for Y coordinate relative to bin_window
13869  *
13870  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13871  * to bin_window coordinates.
13872  *
13873  * Since: 2.12
13874  **/
13875 void
13876 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13877                                                  gint         tx,
13878                                                  gint         ty,
13879                                                  gint        *bx,
13880                                                  gint        *by)
13881 {
13882   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13883
13884   if (bx)
13885     *bx = tx;
13886   if (by)
13887     *by = ty - tree_view->priv->dy;
13888 }
13889
13890 /**
13891  * gtk_tree_view_convert_bin_window_to_tree_coords:
13892  * @tree_view: a #GtkTreeView
13893  * @bx: X coordinate relative to bin_window
13894  * @by: Y coordinate relative to bin_window
13895  * @tx: (out): return location for tree X coordinate
13896  * @ty: (out): return location for tree Y coordinate
13897  *
13898  * Converts bin_window coordinates to coordinates for the
13899  * tree (the full scrollable area of the tree).
13900  *
13901  * Since: 2.12
13902  **/
13903 void
13904 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13905                                                  gint         bx,
13906                                                  gint         by,
13907                                                  gint        *tx,
13908                                                  gint        *ty)
13909 {
13910   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13911
13912   if (tx)
13913     *tx = bx;
13914   if (ty)
13915     *ty = by + tree_view->priv->dy;
13916 }
13917
13918
13919
13920 /**
13921  * gtk_tree_view_get_visible_range:
13922  * @tree_view: A #GtkTreeView
13923  * @start_path: (out) (allow-none): Return location for start of region,
13924  *              or %NULL.
13925  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
13926  *
13927  * Sets @start_path and @end_path to be the first and last visible path.
13928  * Note that there may be invisible paths in between.
13929  *
13930  * The paths should be freed with gtk_tree_path_free() after use.
13931  *
13932  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13933  *
13934  * Since: 2.8
13935  **/
13936 gboolean
13937 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13938                                  GtkTreePath **start_path,
13939                                  GtkTreePath **end_path)
13940 {
13941   GtkRBTree *tree;
13942   GtkRBNode *node;
13943   gboolean retval;
13944   
13945   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13946
13947   if (!tree_view->priv->tree)
13948     return FALSE;
13949
13950   retval = TRUE;
13951
13952   if (start_path)
13953     {
13954       _gtk_rbtree_find_offset (tree_view->priv->tree,
13955                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13956                                &tree, &node);
13957       if (node)
13958         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13959       else
13960         retval = FALSE;
13961     }
13962
13963   if (end_path)
13964     {
13965       gint y;
13966
13967       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
13968         y = tree_view->priv->height - 1;
13969       else
13970         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
13971
13972       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13973       if (node)
13974         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13975       else
13976         retval = FALSE;
13977     }
13978
13979   return retval;
13980 }
13981
13982 /**
13983  * gtk_tree_view_is_blank_at_pos:
13984  * @tree_view: A #GtkTreeView
13985  * @x: The x position to be identified (relative to bin_window)
13986  * @y: The y position to be identified (relative to bin_window)
13987  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13988  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13989  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13990  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13991  *
13992  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
13993  * cell content nor an expander arrow is drawn at the location. If so, the
13994  * location can be considered as the background. You might wish to take
13995  * special action on clicks on the background, such as clearing a current
13996  * selection, having a custom context menu or starting rubber banding.
13997  *
13998  * The @x and @y coordinate that are provided must be relative to bin_window
13999  * coordinates.  That is, @x and @y must come from an event on @tree_view
14000  * where <literal>event->window == gtk_tree_view_get_bin_window (<!-- -->)</literal>.
14001  *
14002  * For converting widget coordinates (eg. the ones you get from
14003  * GtkWidget::query-tooltip), please see
14004  * gtk_tree_view_convert_widget_to_bin_window_coords().
14005  *
14006  * The @path, @column, @cell_x and @cell_y arguments will be filled in
14007  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
14008  * gtk_tree_view_get_path_at_pos() for more information.
14009  *
14010  * Return value: %TRUE if the area at the given coordinates is blank,
14011  * %FALSE otherwise.
14012  *
14013  * Since: 3.0
14014  */
14015 gboolean
14016 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
14017                                gint                x,
14018                                gint                y,
14019                                GtkTreePath       **path,
14020                                GtkTreeViewColumn **column,
14021                                gint               *cell_x,
14022                                gint               *cell_y)
14023 {
14024   GtkRBTree *tree;
14025   GtkRBNode *node;
14026   GtkTreeIter iter;
14027   GtkTreePath *real_path;
14028   GtkTreeViewColumn *real_column;
14029   GdkRectangle cell_area, background_area;
14030
14031   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14032
14033   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14034                                       &real_path, &real_column,
14035                                       cell_x, cell_y))
14036     /* If there's no path here, it is blank */
14037     return TRUE;
14038
14039   if (path)
14040     *path = real_path;
14041
14042   if (column)
14043     *column = real_column;
14044
14045   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14046   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14047
14048   /* Check if there's an expander arrow at (x, y) */
14049   if (real_column == tree_view->priv->expander_column
14050       && gtk_tree_view_draw_expanders (tree_view))
14051     {
14052       gboolean over_arrow;
14053
14054       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14055
14056       if (over_arrow)
14057         {
14058           if (!path)
14059             gtk_tree_path_free (real_path);
14060           return FALSE;
14061         }
14062     }
14063
14064   /* Otherwise, have the column see if there's a cell at (x, y) */
14065   gtk_tree_view_column_cell_set_cell_data (real_column,
14066                                            tree_view->priv->model,
14067                                            &iter,
14068                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14069                                            node->children ? TRUE : FALSE);
14070
14071   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14072                                      &background_area);
14073   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14074                                &cell_area);
14075
14076   if (!path)
14077     gtk_tree_path_free (real_path);
14078
14079   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14080                                                 &cell_area,
14081                                                 &background_area,
14082                                                 x, y);
14083 }
14084
14085 static void
14086 unset_reorderable (GtkTreeView *tree_view)
14087 {
14088   if (tree_view->priv->reorderable)
14089     {
14090       tree_view->priv->reorderable = FALSE;
14091       g_object_notify (G_OBJECT (tree_view), "reorderable");
14092     }
14093 }
14094
14095 /**
14096  * gtk_tree_view_enable_model_drag_source:
14097  * @tree_view: a #GtkTreeView
14098  * @start_button_mask: Mask of allowed buttons to start drag
14099  * @targets: (array length=n_targets): the table of targets that the drag will support
14100  * @n_targets: the number of items in @targets
14101  * @actions: the bitmask of possible actions for a drag from this
14102  *    widget
14103  *
14104  * Turns @tree_view into a drag source for automatic DND. Calling this
14105  * method sets #GtkTreeView:reorderable to %FALSE.
14106  **/
14107 void
14108 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14109                                         GdkModifierType           start_button_mask,
14110                                         const GtkTargetEntry     *targets,
14111                                         gint                      n_targets,
14112                                         GdkDragAction             actions)
14113 {
14114   TreeViewDragInfo *di;
14115
14116   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14117
14118   gtk_drag_source_set (GTK_WIDGET (tree_view),
14119                        0,
14120                        targets,
14121                        n_targets,
14122                        actions);
14123
14124   di = ensure_info (tree_view);
14125
14126   di->start_button_mask = start_button_mask;
14127   di->source_actions = actions;
14128   di->source_set = TRUE;
14129
14130   unset_reorderable (tree_view);
14131 }
14132
14133 /**
14134  * gtk_tree_view_enable_model_drag_dest:
14135  * @tree_view: a #GtkTreeView
14136  * @targets: (array length=n_targets): the table of targets that
14137  *           the drag will support
14138  * @n_targets: the number of items in @targets
14139  * @actions: the bitmask of possible actions for a drag from this
14140  *    widget
14141  * 
14142  * Turns @tree_view into a drop destination for automatic DND. Calling
14143  * this method sets #GtkTreeView:reorderable to %FALSE.
14144  **/
14145 void
14146 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14147                                       const GtkTargetEntry     *targets,
14148                                       gint                      n_targets,
14149                                       GdkDragAction             actions)
14150 {
14151   TreeViewDragInfo *di;
14152
14153   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14154
14155   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14156                      0,
14157                      targets,
14158                      n_targets,
14159                      actions);
14160
14161   di = ensure_info (tree_view);
14162   di->dest_set = TRUE;
14163
14164   unset_reorderable (tree_view);
14165 }
14166
14167 /**
14168  * gtk_tree_view_unset_rows_drag_source:
14169  * @tree_view: a #GtkTreeView
14170  *
14171  * Undoes the effect of
14172  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14173  * #GtkTreeView:reorderable to %FALSE.
14174  **/
14175 void
14176 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14177 {
14178   TreeViewDragInfo *di;
14179
14180   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14181
14182   di = get_info (tree_view);
14183
14184   if (di)
14185     {
14186       if (di->source_set)
14187         {
14188           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14189           di->source_set = FALSE;
14190         }
14191
14192       if (!di->dest_set && !di->source_set)
14193         remove_info (tree_view);
14194     }
14195   
14196   unset_reorderable (tree_view);
14197 }
14198
14199 /**
14200  * gtk_tree_view_unset_rows_drag_dest:
14201  * @tree_view: a #GtkTreeView
14202  *
14203  * Undoes the effect of
14204  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14205  * #GtkTreeView:reorderable to %FALSE.
14206  **/
14207 void
14208 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14209 {
14210   TreeViewDragInfo *di;
14211
14212   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14213
14214   di = get_info (tree_view);
14215
14216   if (di)
14217     {
14218       if (di->dest_set)
14219         {
14220           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14221           di->dest_set = FALSE;
14222         }
14223
14224       if (!di->dest_set && !di->source_set)
14225         remove_info (tree_view);
14226     }
14227
14228   unset_reorderable (tree_view);
14229 }
14230
14231 /**
14232  * gtk_tree_view_set_drag_dest_row:
14233  * @tree_view: a #GtkTreeView
14234  * @path: (allow-none): The path of the row to highlight, or %NULL
14235  * @pos: Specifies whether to drop before, after or into the row
14236  *
14237  * Sets the row that is highlighted for feedback.
14238  * If @path is %NULL, an existing highlight is removed.
14239  */
14240 void
14241 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14242                                  GtkTreePath            *path,
14243                                  GtkTreeViewDropPosition pos)
14244 {
14245   GtkTreePath *current_dest;
14246
14247   /* Note; this function is exported to allow a custom DND
14248    * implementation, so it can't touch TreeViewDragInfo
14249    */
14250
14251   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14252
14253   current_dest = NULL;
14254
14255   if (tree_view->priv->drag_dest_row)
14256     {
14257       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14258       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14259     }
14260
14261   /* special case a drop on an empty model */
14262   tree_view->priv->empty_view_drop = 0;
14263
14264   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14265       && gtk_tree_path_get_depth (path) == 1
14266       && gtk_tree_path_get_indices (path)[0] == 0)
14267     {
14268       gint n_children;
14269
14270       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14271                                                    NULL);
14272
14273       if (!n_children)
14274         tree_view->priv->empty_view_drop = 1;
14275     }
14276
14277   tree_view->priv->drag_dest_pos = pos;
14278
14279   if (path)
14280     {
14281       tree_view->priv->drag_dest_row =
14282         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14283       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14284     }
14285   else
14286     tree_view->priv->drag_dest_row = NULL;
14287
14288   if (current_dest)
14289     {
14290       GtkRBTree *tree, *new_tree;
14291       GtkRBNode *node, *new_node;
14292
14293       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14294       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14295
14296       if (tree && node)
14297         {
14298           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14299           if (new_tree && new_node)
14300             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14301
14302           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14303           if (new_tree && new_node)
14304             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14305         }
14306       gtk_tree_path_free (current_dest);
14307     }
14308 }
14309
14310 /**
14311  * gtk_tree_view_get_drag_dest_row:
14312  * @tree_view: a #GtkTreeView
14313  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14314  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14315  * 
14316  * Gets information about the row that is highlighted for feedback.
14317  **/
14318 void
14319 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14320                                  GtkTreePath             **path,
14321                                  GtkTreeViewDropPosition  *pos)
14322 {
14323   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14324
14325   if (path)
14326     {
14327       if (tree_view->priv->drag_dest_row)
14328         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14329       else
14330         {
14331           if (tree_view->priv->empty_view_drop)
14332             *path = gtk_tree_path_new_from_indices (0, -1);
14333           else
14334             *path = NULL;
14335         }
14336     }
14337
14338   if (pos)
14339     *pos = tree_view->priv->drag_dest_pos;
14340 }
14341
14342 /**
14343  * gtk_tree_view_get_dest_row_at_pos:
14344  * @tree_view: a #GtkTreeView
14345  * @drag_x: the position to determine the destination row for
14346  * @drag_y: the position to determine the destination row for
14347  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14348  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14349  * 
14350  * Determines the destination row for a given position.  @drag_x and
14351  * @drag_y are expected to be in widget coordinates.  This function is only
14352  * meaningful if @tree_view is realized.  Therefore this function will always
14353  * return %FALSE if @tree_view is not realized or does not have a model.
14354  * 
14355  * Return value: whether there is a row at the given position, %TRUE if this
14356  * is indeed the case.
14357  **/
14358 gboolean
14359 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14360                                    gint                     drag_x,
14361                                    gint                     drag_y,
14362                                    GtkTreePath            **path,
14363                                    GtkTreeViewDropPosition *pos)
14364 {
14365   gint cell_y;
14366   gint bin_x, bin_y;
14367   gdouble offset_into_row;
14368   gdouble third;
14369   GdkRectangle cell;
14370   GtkTreeViewColumn *column = NULL;
14371   GtkTreePath *tmp_path = NULL;
14372
14373   /* Note; this function is exported to allow a custom DND
14374    * implementation, so it can't touch TreeViewDragInfo
14375    */
14376
14377   g_return_val_if_fail (tree_view != NULL, FALSE);
14378   g_return_val_if_fail (drag_x >= 0, FALSE);
14379   g_return_val_if_fail (drag_y >= 0, FALSE);
14380
14381   if (path)
14382     *path = NULL;
14383
14384   if (tree_view->priv->bin_window == NULL)
14385     return FALSE;
14386
14387   if (tree_view->priv->tree == NULL)
14388     return FALSE;
14389
14390   /* If in the top third of a row, we drop before that row; if
14391    * in the bottom third, drop after that row; if in the middle,
14392    * and the row has children, drop into the row.
14393    */
14394   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14395                                                      &bin_x, &bin_y);
14396
14397   if (!gtk_tree_view_get_path_at_pos (tree_view,
14398                                       bin_x,
14399                                       bin_y,
14400                                       &tmp_path,
14401                                       &column,
14402                                       NULL,
14403                                       &cell_y))
14404     return FALSE;
14405
14406   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14407                                      &cell);
14408
14409   offset_into_row = cell_y;
14410
14411   if (path)
14412     *path = tmp_path;
14413   else
14414     gtk_tree_path_free (tmp_path);
14415
14416   tmp_path = NULL;
14417
14418   third = cell.height / 3.0;
14419
14420   if (pos)
14421     {
14422       if (offset_into_row < third)
14423         {
14424           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14425         }
14426       else if (offset_into_row < (cell.height / 2.0))
14427         {
14428           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14429         }
14430       else if (offset_into_row < third * 2.0)
14431         {
14432           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14433         }
14434       else
14435         {
14436           *pos = GTK_TREE_VIEW_DROP_AFTER;
14437         }
14438     }
14439
14440   return TRUE;
14441 }
14442
14443
14444
14445 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14446 /**
14447  * gtk_tree_view_create_row_drag_icon:
14448  * @tree_view: a #GtkTreeView
14449  * @path: a #GtkTreePath in @tree_view
14450  *
14451  * Creates a #cairo_surface_t representation of the row at @path.  
14452  * This image is used for a drag icon.
14453  *
14454  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14455  **/
14456 cairo_surface_t *
14457 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14458                                     GtkTreePath  *path)
14459 {
14460   GtkTreeIter   iter;
14461   GtkRBTree    *tree;
14462   GtkRBNode    *node;
14463   GtkStyleContext *context;
14464   GtkStateFlags state;
14465   gint cell_offset;
14466   GList *list;
14467   GdkRectangle background_area;
14468   GtkWidget *widget;
14469   gint depth;
14470   /* start drawing inside the black outline */
14471   gint x = 1, y = 1;
14472   cairo_surface_t *surface;
14473   gint bin_window_width;
14474   gboolean is_separator = FALSE;
14475   gboolean rtl, allow_rules;
14476   cairo_t *cr;
14477
14478   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14479   g_return_val_if_fail (path != NULL, NULL);
14480
14481   widget = GTK_WIDGET (tree_view);
14482
14483   if (!gtk_widget_get_realized (widget))
14484     return NULL;
14485
14486   depth = gtk_tree_path_get_depth (path);
14487
14488   _gtk_tree_view_find_node (tree_view,
14489                             path,
14490                             &tree,
14491                             &node);
14492
14493   if (tree == NULL)
14494     return NULL;
14495
14496   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14497                                 &iter,
14498                                 path))
14499     return NULL;
14500
14501   context = gtk_widget_get_style_context (widget);
14502
14503   gtk_style_context_save (context);
14504
14505   state = gtk_widget_get_state_flags (widget);
14506   gtk_style_context_set_state (context, state);
14507
14508   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
14509   gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, 0);
14510
14511   gtk_widget_style_get (widget,
14512                         "allow-rules", &allow_rules,
14513                         NULL);
14514
14515   if (allow_rules && tree_view->priv->has_rules)
14516     {
14517       GtkRegionFlags row_flags;
14518
14519       if (_gtk_rbtree_node_find_parity (tree, node))
14520         row_flags = GTK_REGION_ODD;
14521       else
14522         row_flags = GTK_REGION_EVEN;
14523
14524       gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
14525     }
14526
14527   is_separator = row_is_separator (tree_view, &iter, NULL);
14528
14529   cell_offset = x;
14530
14531   background_area.y = y;
14532   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14533
14534   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14535
14536   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14537                                                CAIRO_CONTENT_COLOR,
14538                                                bin_window_width + 2,
14539                                                background_area.height + 2);
14540
14541   cr = cairo_create (surface);
14542
14543   gtk_render_background (context, cr, 0, 0,
14544                          bin_window_width + 2,
14545                          background_area.height + 2);
14546
14547   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14548
14549   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14550       list;
14551       list = (rtl ? list->prev : list->next))
14552     {
14553       GtkTreeViewColumn *column = list->data;
14554       GdkRectangle cell_area;
14555       gint vertical_separator;
14556
14557       if (!gtk_tree_view_column_get_visible (column))
14558         continue;
14559
14560       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14561                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14562                                                node->children?TRUE:FALSE);
14563
14564       background_area.x = cell_offset;
14565       background_area.width = gtk_tree_view_column_get_width (column);
14566
14567       gtk_widget_style_get (widget,
14568                             "vertical-separator", &vertical_separator,
14569                             NULL);
14570
14571       cell_area = background_area;
14572
14573       cell_area.y += vertical_separator / 2;
14574       cell_area.height -= vertical_separator;
14575
14576       if (gtk_tree_view_is_expander_column (tree_view, column))
14577         {
14578           if (!rtl)
14579             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14580           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14581
14582           if (gtk_tree_view_draw_expanders (tree_view))
14583             {
14584               if (!rtl)
14585                 cell_area.x += depth * tree_view->priv->expander_size;
14586               cell_area.width -= depth * tree_view->priv->expander_size;
14587             }
14588         }
14589
14590       if (gtk_tree_view_column_cell_is_visible (column))
14591         {
14592           if (is_separator)
14593             {
14594               gtk_style_context_save (context);
14595               gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
14596
14597               gtk_render_line (context, cr,
14598                                cell_area.x,
14599                                cell_area.y + cell_area.height / 2,
14600                                cell_area.x + cell_area.width,
14601                                cell_area.y + cell_area.height / 2);
14602
14603               gtk_style_context_restore (context);
14604             }
14605           else
14606             {
14607               _gtk_tree_view_column_cell_render (column,
14608                                                  cr,
14609                                                  &background_area,
14610                                                  &cell_area,
14611                                                  0, FALSE);
14612             }
14613         }
14614       cell_offset += gtk_tree_view_column_get_width (column);
14615     }
14616
14617   cairo_set_source_rgb (cr, 0, 0, 0);
14618   cairo_rectangle (cr, 
14619                    0.5, 0.5, 
14620                    bin_window_width + 1,
14621                    background_area.height + 1);
14622   cairo_set_line_width (cr, 1.0);
14623   cairo_stroke (cr);
14624
14625   cairo_destroy (cr);
14626
14627   cairo_surface_set_device_offset (surface, 2, 2);
14628
14629   gtk_style_context_restore (context);
14630
14631   return surface;
14632 }
14633
14634
14635 /**
14636  * gtk_tree_view_set_destroy_count_func:
14637  * @tree_view: A #GtkTreeView
14638  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14639  * @data: (allow-none): User data to be passed to @func, or %NULL
14640  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14641  *
14642  * This function should almost never be used.  It is meant for private use by
14643  * ATK for determining the number of visible children that are removed when the
14644  * user collapses a row, or a row is deleted.
14645  **/
14646 void
14647 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14648                                       GtkTreeDestroyCountFunc  func,
14649                                       gpointer                 data,
14650                                       GDestroyNotify           destroy)
14651 {
14652   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14653
14654   if (tree_view->priv->destroy_count_destroy)
14655     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14656
14657   tree_view->priv->destroy_count_func = func;
14658   tree_view->priv->destroy_count_data = data;
14659   tree_view->priv->destroy_count_destroy = destroy;
14660 }
14661
14662
14663 /*
14664  * Interactive search
14665  */
14666
14667 /**
14668  * gtk_tree_view_set_enable_search:
14669  * @tree_view: A #GtkTreeView
14670  * @enable_search: %TRUE, if the user can search interactively
14671  *
14672  * If @enable_search is set, then the user can type in text to search through
14673  * the tree interactively (this is sometimes called "typeahead find").
14674  * 
14675  * Note that even if this is %FALSE, the user can still initiate a search 
14676  * using the "start-interactive-search" key binding.
14677  */
14678 void
14679 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14680                                  gboolean     enable_search)
14681 {
14682   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14683
14684   enable_search = !!enable_search;
14685   
14686   if (tree_view->priv->enable_search != enable_search)
14687     {
14688        tree_view->priv->enable_search = enable_search;
14689        g_object_notify (G_OBJECT (tree_view), "enable-search");
14690     }
14691 }
14692
14693 /**
14694  * gtk_tree_view_get_enable_search:
14695  * @tree_view: A #GtkTreeView
14696  *
14697  * Returns whether or not the tree allows to start interactive searching 
14698  * by typing in text.
14699  *
14700  * Return value: whether or not to let the user search interactively
14701  */
14702 gboolean
14703 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14704 {
14705   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14706
14707   return tree_view->priv->enable_search;
14708 }
14709
14710
14711 /**
14712  * gtk_tree_view_get_search_column:
14713  * @tree_view: A #GtkTreeView
14714  *
14715  * Gets the column searched on by the interactive search code.
14716  *
14717  * Return value: the column the interactive search code searches in.
14718  */
14719 gint
14720 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14721 {
14722   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14723
14724   return (tree_view->priv->search_column);
14725 }
14726
14727 /**
14728  * gtk_tree_view_set_search_column:
14729  * @tree_view: A #GtkTreeView
14730  * @column: the column of the model to search in, or -1 to disable searching
14731  *
14732  * Sets @column as the column where the interactive search code should
14733  * search in for the current model. 
14734  * 
14735  * If the search column is set, users can use the "start-interactive-search"
14736  * key binding to bring up search popup. The enable-search property controls
14737  * whether simply typing text will also start an interactive search.
14738  *
14739  * Note that @column refers to a column of the current model. The search 
14740  * column is reset to -1 when the model is changed.
14741  */
14742 void
14743 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14744                                  gint         column)
14745 {
14746   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14747   g_return_if_fail (column >= -1);
14748
14749   if (tree_view->priv->search_column == column)
14750     return;
14751
14752   tree_view->priv->search_column = column;
14753   g_object_notify (G_OBJECT (tree_view), "search-column");
14754 }
14755
14756 /**
14757  * gtk_tree_view_get_search_equal_func: (skip)
14758  * @tree_view: A #GtkTreeView
14759  *
14760  * Returns the compare function currently in use.
14761  *
14762  * Return value: the currently used compare function for the search code.
14763  */
14764
14765 GtkTreeViewSearchEqualFunc
14766 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14767 {
14768   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14769
14770   return tree_view->priv->search_equal_func;
14771 }
14772
14773 /**
14774  * gtk_tree_view_set_search_equal_func:
14775  * @tree_view: A #GtkTreeView
14776  * @search_equal_func: the compare function to use during the search
14777  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14778  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14779  *
14780  * Sets the compare function for the interactive search capabilities; note
14781  * that somewhat like strcmp() returning 0 for equality
14782  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14783  **/
14784 void
14785 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14786                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14787                                      gpointer                    search_user_data,
14788                                      GDestroyNotify              search_destroy)
14789 {
14790   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14791   g_return_if_fail (search_equal_func != NULL);
14792
14793   if (tree_view->priv->search_destroy)
14794     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14795
14796   tree_view->priv->search_equal_func = search_equal_func;
14797   tree_view->priv->search_user_data = search_user_data;
14798   tree_view->priv->search_destroy = search_destroy;
14799   if (tree_view->priv->search_equal_func == NULL)
14800     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14801 }
14802
14803 /**
14804  * gtk_tree_view_get_search_entry:
14805  * @tree_view: A #GtkTreeView
14806  *
14807  * Returns the #GtkEntry which is currently in use as interactive search
14808  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14809  * will be returned.
14810  *
14811  * Return value: (transfer none): the entry currently in use as search entry.
14812  *
14813  * Since: 2.10
14814  */
14815 GtkEntry *
14816 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14817 {
14818   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14819
14820   if (tree_view->priv->search_custom_entry_set)
14821     return GTK_ENTRY (tree_view->priv->search_entry);
14822
14823   return NULL;
14824 }
14825
14826 /**
14827  * gtk_tree_view_set_search_entry:
14828  * @tree_view: A #GtkTreeView
14829  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14830  *
14831  * Sets the entry which the interactive search code will use for this
14832  * @tree_view.  This is useful when you want to provide a search entry
14833  * in our interface at all time at a fixed position.  Passing %NULL for
14834  * @entry will make the interactive search code use the built-in popup
14835  * entry again.
14836  *
14837  * Since: 2.10
14838  */
14839 void
14840 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14841                                 GtkEntry    *entry)
14842 {
14843   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14844   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14845
14846   if (tree_view->priv->search_custom_entry_set)
14847     {
14848       if (tree_view->priv->search_entry_changed_id)
14849         {
14850           g_signal_handler_disconnect (tree_view->priv->search_entry,
14851                                        tree_view->priv->search_entry_changed_id);
14852           tree_view->priv->search_entry_changed_id = 0;
14853         }
14854       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14855                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14856                                             tree_view);
14857
14858       g_object_unref (tree_view->priv->search_entry);
14859     }
14860   else if (tree_view->priv->search_window)
14861     {
14862       gtk_widget_destroy (tree_view->priv->search_window);
14863
14864       tree_view->priv->search_window = NULL;
14865     }
14866
14867   if (entry)
14868     {
14869       tree_view->priv->search_entry = g_object_ref (entry);
14870       tree_view->priv->search_custom_entry_set = TRUE;
14871
14872       if (tree_view->priv->search_entry_changed_id == 0)
14873         {
14874           tree_view->priv->search_entry_changed_id =
14875             g_signal_connect (tree_view->priv->search_entry, "changed",
14876                               G_CALLBACK (gtk_tree_view_search_init),
14877                               tree_view);
14878         }
14879       
14880         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14881                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14882                           tree_view);
14883
14884         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14885     }
14886   else
14887     {
14888       tree_view->priv->search_entry = NULL;
14889       tree_view->priv->search_custom_entry_set = FALSE;
14890     }
14891 }
14892
14893 /**
14894  * gtk_tree_view_set_search_position_func:
14895  * @tree_view: A #GtkTreeView
14896  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14897  *    to use the default search position function
14898  * @data: (allow-none): user data to pass to @func, or %NULL
14899  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14900  *
14901  * Sets the function to use when positioning the search dialog.
14902  *
14903  * Since: 2.10
14904  **/
14905 void
14906 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14907                                         GtkTreeViewSearchPositionFunc  func,
14908                                         gpointer                       user_data,
14909                                         GDestroyNotify                 destroy)
14910 {
14911   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14912
14913   if (tree_view->priv->search_position_destroy)
14914     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14915
14916   tree_view->priv->search_position_func = func;
14917   tree_view->priv->search_position_user_data = user_data;
14918   tree_view->priv->search_position_destroy = destroy;
14919   if (tree_view->priv->search_position_func == NULL)
14920     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14921 }
14922
14923 /**
14924  * gtk_tree_view_get_search_position_func: (skip)
14925  * @tree_view: A #GtkTreeView
14926  *
14927  * Returns the positioning function currently in use.
14928  *
14929  * Return value: the currently used function for positioning the search dialog.
14930  *
14931  * Since: 2.10
14932  */
14933 GtkTreeViewSearchPositionFunc
14934 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14935 {
14936   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14937
14938   return tree_view->priv->search_position_func;
14939 }
14940
14941
14942 static void
14943 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14944                                   GtkTreeView *tree_view,
14945                                   GdkDevice   *device)
14946 {
14947   if (tree_view->priv->disable_popdown)
14948     return;
14949
14950   if (tree_view->priv->search_entry_changed_id)
14951     {
14952       g_signal_handler_disconnect (tree_view->priv->search_entry,
14953                                    tree_view->priv->search_entry_changed_id);
14954       tree_view->priv->search_entry_changed_id = 0;
14955     }
14956   if (tree_view->priv->typeselect_flush_timeout)
14957     {
14958       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14959       tree_view->priv->typeselect_flush_timeout = 0;
14960     }
14961         
14962   if (gtk_widget_get_visible (search_dialog))
14963     {
14964       /* send focus-in event */
14965       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14966       gtk_widget_hide (search_dialog);
14967       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14968       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14969     }
14970 }
14971
14972 static void
14973 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14974                                     GtkWidget   *search_dialog,
14975                                     gpointer     user_data)
14976 {
14977   gint x, y;
14978   gint tree_x, tree_y;
14979   gint tree_width, tree_height;
14980   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14981   GdkScreen *screen = gdk_window_get_screen (tree_window);
14982   GtkRequisition requisition;
14983   gint monitor_num;
14984   GdkRectangle monitor;
14985
14986   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14987   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14988
14989   gtk_widget_realize (search_dialog);
14990
14991   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14992   tree_width = gdk_window_get_width (tree_window);
14993   tree_height = gdk_window_get_height (tree_window);
14994   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14995
14996   if (tree_x + tree_width > gdk_screen_get_width (screen))
14997     x = gdk_screen_get_width (screen) - requisition.width;
14998   else if (tree_x + tree_width - requisition.width < 0)
14999     x = 0;
15000   else
15001     x = tree_x + tree_width - requisition.width;
15002
15003   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
15004     y = gdk_screen_get_height (screen) - requisition.height;
15005   else if (tree_y + tree_height < 0) /* isn't really possible ... */
15006     y = 0;
15007   else
15008     y = tree_y + tree_height;
15009
15010   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
15011 }
15012
15013 static void
15014 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
15015                                       GtkMenu  *menu,
15016                                       gpointer  data)
15017 {
15018   GtkTreeView *tree_view = (GtkTreeView *)data;
15019
15020   tree_view->priv->disable_popdown = 1;
15021   g_signal_connect (menu, "hide",
15022                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15023 }
15024
15025 /* Because we're visible but offscreen, we just set a flag in the preedit
15026  * callback.
15027  */
15028 static void
15029 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15030                                       GtkTreeView  *tree_view)
15031 {
15032   tree_view->priv->imcontext_changed = 1;
15033   if (tree_view->priv->typeselect_flush_timeout)
15034     {
15035       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15036       tree_view->priv->typeselect_flush_timeout =
15037         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15038                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15039                        tree_view);
15040     }
15041
15042 }
15043
15044 static void
15045 gtk_tree_view_search_activate (GtkEntry    *entry,
15046                                GtkTreeView *tree_view)
15047 {
15048   GtkTreePath *path;
15049   GtkRBNode *node;
15050   GtkRBTree *tree;
15051
15052   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
15053                                     tree_view,
15054                                     gtk_get_current_event_device ());
15055
15056   /* If we have a row selected and it's the cursor row, we activate
15057    * the row XXX */
15058   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
15059     {
15060       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
15061       
15062       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15063       
15064       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
15065         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15066       
15067       gtk_tree_path_free (path);
15068     }
15069 }
15070
15071 static gboolean
15072 gtk_tree_view_real_search_enable_popdown (gpointer data)
15073 {
15074   GtkTreeView *tree_view = (GtkTreeView *)data;
15075
15076   tree_view->priv->disable_popdown = 0;
15077
15078   return FALSE;
15079 }
15080
15081 static void
15082 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15083                                      gpointer   data)
15084 {
15085   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15086 }
15087
15088 static gboolean
15089 gtk_tree_view_search_delete_event (GtkWidget *widget,
15090                                    GdkEventAny *event,
15091                                    GtkTreeView *tree_view)
15092 {
15093   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15094
15095   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15096
15097   return TRUE;
15098 }
15099
15100 static gboolean
15101 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15102                                          GdkEventButton *event,
15103                                          GtkTreeView *tree_view)
15104 {
15105   GdkDevice *keyb_device;
15106
15107   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15108
15109   keyb_device = gdk_device_get_associated_device (event->device);
15110   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15111
15112   if (event->window == tree_view->priv->bin_window)
15113     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15114
15115   return TRUE;
15116 }
15117
15118 static gboolean
15119 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15120                                    GdkEventScroll *event,
15121                                    GtkTreeView *tree_view)
15122 {
15123   gboolean retval = FALSE;
15124
15125   if (event->direction == GDK_SCROLL_UP)
15126     {
15127       gtk_tree_view_search_move (widget, tree_view, TRUE);
15128       retval = TRUE;
15129     }
15130   else if (event->direction == GDK_SCROLL_DOWN)
15131     {
15132       gtk_tree_view_search_move (widget, tree_view, FALSE);
15133       retval = TRUE;
15134     }
15135
15136   /* renew the flush timeout */
15137   if (retval && tree_view->priv->typeselect_flush_timeout
15138       && !tree_view->priv->search_custom_entry_set)
15139     {
15140       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15141       tree_view->priv->typeselect_flush_timeout =
15142         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15143                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15144                        tree_view);
15145     }
15146
15147   return retval;
15148 }
15149
15150 static gboolean
15151 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15152                                       GdkEventKey *event,
15153                                       GtkTreeView *tree_view)
15154 {
15155   GdkModifierType default_accel;
15156   gboolean        retval = FALSE;
15157
15158   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15159   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15160
15161   /* close window and cancel the search */
15162   if (!tree_view->priv->search_custom_entry_set
15163       && (event->keyval == GDK_KEY_Escape ||
15164           event->keyval == GDK_KEY_Tab ||
15165             event->keyval == GDK_KEY_KP_Tab ||
15166             event->keyval == GDK_KEY_ISO_Left_Tab))
15167     {
15168       gtk_tree_view_search_dialog_hide (widget, tree_view,
15169                                         gdk_event_get_device ((GdkEvent *) event));
15170       return TRUE;
15171     }
15172
15173   default_accel = gtk_widget_get_modifier_mask (widget,
15174                                                 GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
15175
15176   /* select previous matching iter */
15177   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15178     {
15179       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15180         gtk_widget_error_bell (widget);
15181
15182       retval = TRUE;
15183     }
15184
15185   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK))
15186       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15187     {
15188       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15189         gtk_widget_error_bell (widget);
15190
15191       retval = TRUE;
15192     }
15193
15194   /* select next matching iter */
15195   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15196     {
15197       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15198         gtk_widget_error_bell (widget);
15199
15200       retval = TRUE;
15201     }
15202
15203   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == default_accel)
15204       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15205     {
15206       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15207         gtk_widget_error_bell (widget);
15208
15209       retval = TRUE;
15210     }
15211
15212   /* renew the flush timeout */
15213   if (retval && tree_view->priv->typeselect_flush_timeout
15214       && !tree_view->priv->search_custom_entry_set)
15215     {
15216       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15217       tree_view->priv->typeselect_flush_timeout =
15218         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15219                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15220                        tree_view);
15221     }
15222
15223   return retval;
15224 }
15225
15226 /*  this function returns FALSE if there is a search string but
15227  *  nothing was found, and TRUE otherwise.
15228  */
15229 static gboolean
15230 gtk_tree_view_search_move (GtkWidget   *window,
15231                            GtkTreeView *tree_view,
15232                            gboolean     up)
15233 {
15234   gboolean ret;
15235   gint len;
15236   gint count = 0;
15237   const gchar *text;
15238   GtkTreeIter iter;
15239   GtkTreeModel *model;
15240   GtkTreeSelection *selection;
15241
15242   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15243
15244   g_return_val_if_fail (text != NULL, FALSE);
15245
15246   len = strlen (text);
15247
15248   if (up && tree_view->priv->selected_iter == 1)
15249     return strlen (text) < 1;
15250
15251   len = strlen (text);
15252
15253   if (len < 1)
15254     return TRUE;
15255
15256   model = gtk_tree_view_get_model (tree_view);
15257   selection = gtk_tree_view_get_selection (tree_view);
15258
15259   /* search */
15260   gtk_tree_selection_unselect_all (selection);
15261   if (!gtk_tree_model_get_iter_first (model, &iter))
15262     return TRUE;
15263
15264   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15265                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15266
15267   if (ret)
15268     {
15269       /* found */
15270       tree_view->priv->selected_iter += up?(-1):(1);
15271       return TRUE;
15272     }
15273   else
15274     {
15275       /* return to old iter */
15276       count = 0;
15277       gtk_tree_model_get_iter_first (model, &iter);
15278       gtk_tree_view_search_iter (model, selection,
15279                                  &iter, text,
15280                                  &count, tree_view->priv->selected_iter);
15281       return FALSE;
15282     }
15283 }
15284
15285 static gboolean
15286 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15287                                  gint          column,
15288                                  const gchar  *key,
15289                                  GtkTreeIter  *iter,
15290                                  gpointer      search_data)
15291 {
15292   gboolean retval = TRUE;
15293   const gchar *str;
15294   gchar *normalized_string;
15295   gchar *normalized_key;
15296   gchar *case_normalized_string = NULL;
15297   gchar *case_normalized_key = NULL;
15298   GValue value = G_VALUE_INIT;
15299   GValue transformed = G_VALUE_INIT;
15300
15301   gtk_tree_model_get_value (model, iter, column, &value);
15302
15303   g_value_init (&transformed, G_TYPE_STRING);
15304
15305   if (!g_value_transform (&value, &transformed))
15306     {
15307       g_value_unset (&value);
15308       return TRUE;
15309     }
15310
15311   g_value_unset (&value);
15312
15313   str = g_value_get_string (&transformed);
15314   if (!str)
15315     {
15316       g_value_unset (&transformed);
15317       return TRUE;
15318     }
15319
15320   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15321   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15322
15323   if (normalized_string && normalized_key)
15324     {
15325       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15326       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15327
15328       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15329         retval = FALSE;
15330     }
15331
15332   g_value_unset (&transformed);
15333   g_free (normalized_key);
15334   g_free (normalized_string);
15335   g_free (case_normalized_key);
15336   g_free (case_normalized_string);
15337
15338   return retval;
15339 }
15340
15341 static gboolean
15342 gtk_tree_view_search_iter (GtkTreeModel     *model,
15343                            GtkTreeSelection *selection,
15344                            GtkTreeIter      *iter,
15345                            const gchar      *text,
15346                            gint             *count,
15347                            gint              n)
15348 {
15349   GtkRBTree *tree = NULL;
15350   GtkRBNode *node = NULL;
15351   GtkTreePath *path;
15352
15353   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15354
15355   path = gtk_tree_model_get_path (model, iter);
15356   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15357
15358   do
15359     {
15360       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15361         {
15362           (*count)++;
15363           if (*count == n)
15364             {
15365               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15366                                             TRUE, 0.5, 0.0);
15367               gtk_tree_selection_select_iter (selection, iter);
15368               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15369
15370               if (path)
15371                 gtk_tree_path_free (path);
15372
15373               return TRUE;
15374             }
15375         }
15376
15377       if (node->children)
15378         {
15379           gboolean has_child;
15380           GtkTreeIter tmp;
15381
15382           tree = node->children;
15383           node = tree->root;
15384
15385           while (node->left != tree->nil)
15386             node = node->left;
15387
15388           tmp = *iter;
15389           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15390           gtk_tree_path_down (path);
15391
15392           /* sanity check */
15393           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15394         }
15395       else
15396         {
15397           gboolean done = FALSE;
15398
15399           do
15400             {
15401               node = _gtk_rbtree_next (tree, node);
15402
15403               if (node)
15404                 {
15405                   gboolean has_next;
15406
15407                   has_next = gtk_tree_model_iter_next (model, iter);
15408
15409                   done = TRUE;
15410                   gtk_tree_path_next (path);
15411
15412                   /* sanity check */
15413                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15414                 }
15415               else
15416                 {
15417                   gboolean has_parent;
15418                   GtkTreeIter tmp_iter = *iter;
15419
15420                   node = tree->parent_node;
15421                   tree = tree->parent_tree;
15422
15423                   if (!tree)
15424                     {
15425                       if (path)
15426                         gtk_tree_path_free (path);
15427
15428                       /* we've run out of tree, done with this func */
15429                       return FALSE;
15430                     }
15431
15432                   has_parent = gtk_tree_model_iter_parent (model,
15433                                                            iter,
15434                                                            &tmp_iter);
15435                   gtk_tree_path_up (path);
15436
15437                   /* sanity check */
15438                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15439                 }
15440             }
15441           while (!done);
15442         }
15443     }
15444   while (1);
15445
15446   return FALSE;
15447 }
15448
15449 static void
15450 gtk_tree_view_search_init (GtkWidget   *entry,
15451                            GtkTreeView *tree_view)
15452 {
15453   gint ret;
15454   gint count = 0;
15455   const gchar *text;
15456   GtkTreeIter iter;
15457   GtkTreeModel *model;
15458   GtkTreeSelection *selection;
15459
15460   g_return_if_fail (GTK_IS_ENTRY (entry));
15461   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15462
15463   text = gtk_entry_get_text (GTK_ENTRY (entry));
15464
15465   model = gtk_tree_view_get_model (tree_view);
15466   selection = gtk_tree_view_get_selection (tree_view);
15467
15468   /* search */
15469   gtk_tree_selection_unselect_all (selection);
15470   if (tree_view->priv->typeselect_flush_timeout
15471       && !tree_view->priv->search_custom_entry_set)
15472     {
15473       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15474       tree_view->priv->typeselect_flush_timeout =
15475         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15476                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15477                        tree_view);
15478     }
15479
15480   if (*text == '\0')
15481     return;
15482
15483   if (!gtk_tree_model_get_iter_first (model, &iter))
15484     return;
15485
15486   ret = gtk_tree_view_search_iter (model, selection,
15487                                    &iter, text,
15488                                    &count, 1);
15489
15490   if (ret)
15491     tree_view->priv->selected_iter = 1;
15492 }
15493
15494 void
15495 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15496                                 GtkTreeViewColumn *column,
15497                                 GtkCellEditable   *cell_editable)
15498 {
15499   if (tree_view->priv->edited_column == NULL)
15500     return;
15501
15502   g_return_if_fail (column == tree_view->priv->edited_column);
15503
15504   tree_view->priv->edited_column = NULL;
15505
15506   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15507     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15508
15509   gtk_container_remove (GTK_CONTAINER (tree_view),
15510                         GTK_WIDGET (cell_editable));
15511
15512   /* FIXME should only redraw a single node */
15513   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15514 }
15515
15516 static gboolean
15517 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15518                              GtkTreePath *cursor_path,
15519                              gboolean     edit_only)
15520 {
15521   GtkTreeIter iter;
15522   GdkRectangle cell_area;
15523   GtkTreeViewColumn *focus_column;
15524   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15525   gint retval = FALSE;
15526   GtkRBTree *cursor_tree;
15527   GtkRBNode *cursor_node;
15528
15529   g_assert (tree_view->priv->focus_column);
15530   focus_column = tree_view->priv->focus_column;
15531
15532   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15533     return FALSE;
15534
15535   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15536       cursor_node == NULL)
15537     return FALSE;
15538
15539   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15540
15541   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15542
15543   gtk_tree_view_column_cell_set_cell_data (focus_column,
15544                                            tree_view->priv->model,
15545                                            &iter,
15546                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15547                                            cursor_node->children ? TRUE : FALSE);
15548   gtk_tree_view_get_cell_area (tree_view,
15549                                cursor_path,
15550                                focus_column,
15551                                &cell_area);
15552
15553   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15554                               _gtk_tree_view_column_get_context (focus_column),
15555                               GTK_WIDGET (tree_view),
15556                               &cell_area,
15557                               flags, edit_only))
15558     retval = TRUE;
15559
15560   return retval;
15561 }
15562
15563 void
15564 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15565                              GtkTreeViewColumn *column,
15566                              GtkTreePath       *path,
15567                              GtkCellEditable   *cell_editable,
15568                              GdkRectangle      *cell_area)
15569 {
15570   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15571   GtkRequisition requisition;
15572
15573   tree_view->priv->edited_column = column;
15574
15575   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15576   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15577
15578   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15579                                  &requisition, NULL);
15580
15581   tree_view->priv->draw_keyfocus = TRUE;
15582
15583   if (requisition.height < cell_area->height)
15584     {
15585       gint diff = cell_area->height - requisition.height;
15586       gtk_tree_view_put (tree_view,
15587                          GTK_WIDGET (cell_editable),
15588                          cell_area->x, cell_area->y + diff/2,
15589                          cell_area->width, requisition.height);
15590     }
15591   else
15592     {
15593       gtk_tree_view_put (tree_view,
15594                          GTK_WIDGET (cell_editable),
15595                          cell_area->x, cell_area->y,
15596                          cell_area->width, cell_area->height);
15597     }
15598 }
15599
15600 static void
15601 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15602                             gboolean     cancel_editing)
15603 {
15604   GtkTreeViewColumn *column;
15605
15606   if (tree_view->priv->edited_column == NULL)
15607     return;
15608
15609   /*
15610    * This is very evil. We need to do this, because
15611    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15612    * later on. If gtk_tree_view_row_changed notices
15613    * tree_view->priv->edited_column != NULL, it'll call
15614    * gtk_tree_view_stop_editing again. Bad things will happen then.
15615    *
15616    * Please read that again if you intend to modify anything here.
15617    */
15618
15619   column = tree_view->priv->edited_column;
15620   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15621   tree_view->priv->edited_column = NULL;
15622 }
15623
15624
15625 /**
15626  * gtk_tree_view_set_hover_selection:
15627  * @tree_view: a #GtkTreeView
15628  * @hover: %TRUE to enable hover selection mode
15629  *
15630  * Enables or disables the hover selection mode of @tree_view.
15631  * Hover selection makes the selected row follow the pointer.
15632  * Currently, this works only for the selection modes 
15633  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15634  * 
15635  * Since: 2.6
15636  **/
15637 void     
15638 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15639                                    gboolean     hover)
15640 {
15641   hover = hover != FALSE;
15642
15643   if (hover != tree_view->priv->hover_selection)
15644     {
15645       tree_view->priv->hover_selection = hover;
15646
15647       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15648     }
15649 }
15650
15651 /**
15652  * gtk_tree_view_get_hover_selection:
15653  * @tree_view: a #GtkTreeView
15654  * 
15655  * Returns whether hover selection mode is turned on for @tree_view.
15656  * 
15657  * Return value: %TRUE if @tree_view is in hover selection mode
15658  *
15659  * Since: 2.6 
15660  **/
15661 gboolean 
15662 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15663 {
15664   return tree_view->priv->hover_selection;
15665 }
15666
15667 /**
15668  * gtk_tree_view_set_hover_expand:
15669  * @tree_view: a #GtkTreeView
15670  * @expand: %TRUE to enable hover selection mode
15671  *
15672  * Enables of disables the hover expansion mode of @tree_view.
15673  * Hover expansion makes rows expand or collapse if the pointer 
15674  * moves over them.
15675  * 
15676  * Since: 2.6
15677  **/
15678 void     
15679 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15680                                 gboolean     expand)
15681 {
15682   expand = expand != FALSE;
15683
15684   if (expand != tree_view->priv->hover_expand)
15685     {
15686       tree_view->priv->hover_expand = expand;
15687
15688       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15689     }
15690 }
15691
15692 /**
15693  * gtk_tree_view_get_hover_expand:
15694  * @tree_view: a #GtkTreeView
15695  * 
15696  * Returns whether hover expansion mode is turned on for @tree_view.
15697  * 
15698  * Return value: %TRUE if @tree_view is in hover expansion mode
15699  *
15700  * Since: 2.6 
15701  **/
15702 gboolean 
15703 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15704 {
15705   return tree_view->priv->hover_expand;
15706 }
15707
15708 /**
15709  * gtk_tree_view_set_rubber_banding:
15710  * @tree_view: a #GtkTreeView
15711  * @enable: %TRUE to enable rubber banding
15712  *
15713  * Enables or disables rubber banding in @tree_view.  If the selection mode
15714  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15715  * multiple rows by dragging the mouse.
15716  * 
15717  * Since: 2.10
15718  **/
15719 void
15720 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15721                                   gboolean     enable)
15722 {
15723   enable = enable != FALSE;
15724
15725   if (enable != tree_view->priv->rubber_banding_enable)
15726     {
15727       tree_view->priv->rubber_banding_enable = enable;
15728
15729       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15730     }
15731 }
15732
15733 /**
15734  * gtk_tree_view_get_rubber_banding:
15735  * @tree_view: a #GtkTreeView
15736  * 
15737  * Returns whether rubber banding is turned on for @tree_view.  If the
15738  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15739  * user to select multiple rows by dragging the mouse.
15740  * 
15741  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15742  *
15743  * Since: 2.10
15744  **/
15745 gboolean
15746 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15747 {
15748   return tree_view->priv->rubber_banding_enable;
15749 }
15750
15751 /**
15752  * gtk_tree_view_is_rubber_banding_active:
15753  * @tree_view: a #GtkTreeView
15754  * 
15755  * Returns whether a rubber banding operation is currently being done
15756  * in @tree_view.
15757  *
15758  * Return value: %TRUE if a rubber banding operation is currently being
15759  * done in @tree_view.
15760  *
15761  * Since: 2.12
15762  **/
15763 gboolean
15764 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15765 {
15766   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15767
15768   if (tree_view->priv->rubber_banding_enable
15769       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15770     return TRUE;
15771
15772   return FALSE;
15773 }
15774
15775 /**
15776  * gtk_tree_view_get_row_separator_func: (skip)
15777  * @tree_view: a #GtkTreeView
15778  * 
15779  * Returns the current row separator function.
15780  * 
15781  * Return value: the current row separator function.
15782  *
15783  * Since: 2.6
15784  **/
15785 GtkTreeViewRowSeparatorFunc 
15786 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15787 {
15788   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15789
15790   return tree_view->priv->row_separator_func;
15791 }
15792
15793 /**
15794  * gtk_tree_view_set_row_separator_func:
15795  * @tree_view: a #GtkTreeView
15796  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15797  * @data: (allow-none): user data to pass to @func, or %NULL
15798  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15799  * 
15800  * Sets the row separator function, which is used to determine
15801  * whether a row should be drawn as a separator. If the row separator
15802  * function is %NULL, no separators are drawn. This is the default value.
15803  *
15804  * Since: 2.6
15805  **/
15806 void
15807 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15808                                       GtkTreeViewRowSeparatorFunc  func,
15809                                       gpointer                     data,
15810                                       GDestroyNotify               destroy)
15811 {
15812   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15813
15814   if (tree_view->priv->row_separator_destroy)
15815     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15816
15817   tree_view->priv->row_separator_func = func;
15818   tree_view->priv->row_separator_data = data;
15819   tree_view->priv->row_separator_destroy = destroy;
15820
15821   /* Have the tree recalculate heights */
15822   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15823   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15824 }
15825
15826   
15827 static void
15828 gtk_tree_view_grab_notify (GtkWidget *widget,
15829                            gboolean   was_grabbed)
15830 {
15831   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15832
15833   tree_view->priv->in_grab = !was_grabbed;
15834
15835   if (!was_grabbed)
15836     {
15837       tree_view->priv->pressed_button = -1;
15838
15839       if (tree_view->priv->rubber_band_status)
15840         gtk_tree_view_stop_rubber_band (tree_view);
15841     }
15842 }
15843
15844 static void
15845 gtk_tree_view_state_flags_changed (GtkWidget     *widget,
15846                                    GtkStateFlags  previous_state)
15847 {
15848   if (gtk_widget_get_realized (widget))
15849     {
15850       GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15851       GtkStyleContext *context;
15852
15853       context = gtk_widget_get_style_context (widget);
15854       gtk_style_context_set_background (context, tree_view->priv->bin_window);
15855     }
15856
15857   gtk_widget_queue_draw (widget);
15858 }
15859
15860 /**
15861  * gtk_tree_view_get_grid_lines:
15862  * @tree_view: a #GtkTreeView
15863  *
15864  * Returns which grid lines are enabled in @tree_view.
15865  *
15866  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15867  * are enabled.
15868  *
15869  * Since: 2.10
15870  */
15871 GtkTreeViewGridLines
15872 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15873 {
15874   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15875
15876   return tree_view->priv->grid_lines;
15877 }
15878
15879 /**
15880  * gtk_tree_view_set_grid_lines:
15881  * @tree_view: a #GtkTreeView
15882  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15883  * enable.
15884  *
15885  * Sets which grid lines to draw in @tree_view.
15886  *
15887  * Since: 2.10
15888  */
15889 void
15890 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15891                               GtkTreeViewGridLines   grid_lines)
15892 {
15893   GtkTreeViewPrivate *priv;
15894   GtkWidget *widget;
15895   GtkTreeViewGridLines old_grid_lines;
15896
15897   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15898
15899   priv = tree_view->priv;
15900   widget = GTK_WIDGET (tree_view);
15901
15902   old_grid_lines = priv->grid_lines;
15903   priv->grid_lines = grid_lines;
15904   
15905   if (gtk_widget_get_realized (widget))
15906     {
15907       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15908           priv->grid_line_width)
15909         {
15910           priv->grid_line_width = 0;
15911         }
15912       
15913       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15914           !priv->grid_line_width)
15915         {
15916           gint8 *dash_list;
15917
15918           gtk_widget_style_get (widget,
15919                                 "grid-line-width", &priv->grid_line_width,
15920                                 "grid-line-pattern", (gchar *)&dash_list,
15921                                 NULL);
15922       
15923           if (dash_list)
15924             {
15925               priv->grid_line_dashes[0] = dash_list[0];
15926               if (dash_list[0])
15927                 priv->grid_line_dashes[1] = dash_list[1];
15928               
15929               g_free (dash_list);
15930             }
15931           else
15932             {
15933               priv->grid_line_dashes[0] = 1;
15934               priv->grid_line_dashes[1] = 1;
15935             }
15936         }      
15937     }
15938
15939   if (old_grid_lines != grid_lines)
15940     {
15941       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15942       
15943       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15944     }
15945 }
15946
15947 /**
15948  * gtk_tree_view_get_enable_tree_lines:
15949  * @tree_view: a #GtkTreeView.
15950  *
15951  * Returns whether or not tree lines are drawn in @tree_view.
15952  *
15953  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15954  * otherwise.
15955  *
15956  * Since: 2.10
15957  */
15958 gboolean
15959 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15960 {
15961   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15962
15963   return tree_view->priv->tree_lines_enabled;
15964 }
15965
15966 /**
15967  * gtk_tree_view_set_enable_tree_lines:
15968  * @tree_view: a #GtkTreeView
15969  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15970  *
15971  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15972  * This does not have any visible effects for lists.
15973  *
15974  * Since: 2.10
15975  */
15976 void
15977 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15978                                      gboolean     enabled)
15979 {
15980   GtkTreeViewPrivate *priv;
15981   GtkWidget *widget;
15982   gboolean was_enabled;
15983
15984   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15985
15986   enabled = enabled != FALSE;
15987
15988   priv = tree_view->priv;
15989   widget = GTK_WIDGET (tree_view);
15990
15991   was_enabled = priv->tree_lines_enabled;
15992
15993   priv->tree_lines_enabled = enabled;
15994
15995   if (gtk_widget_get_realized (widget))
15996     {
15997       if (!enabled && priv->tree_line_width)
15998         {
15999           priv->tree_line_width = 0;
16000         }
16001       
16002       if (enabled && !priv->tree_line_width)
16003         {
16004           gint8 *dash_list;
16005           gtk_widget_style_get (widget,
16006                                 "tree-line-width", &priv->tree_line_width,
16007                                 "tree-line-pattern", (gchar *)&dash_list,
16008                                 NULL);
16009           
16010           if (dash_list)
16011             {
16012               priv->tree_line_dashes[0] = dash_list[0];
16013               if (dash_list[0])
16014                 priv->tree_line_dashes[1] = dash_list[1];
16015               
16016               g_free (dash_list);
16017             }
16018           else
16019             {
16020               priv->tree_line_dashes[0] = 1;
16021               priv->tree_line_dashes[1] = 1;
16022             }
16023         }
16024     }
16025
16026   if (was_enabled != enabled)
16027     {
16028       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16029
16030       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
16031     }
16032 }
16033
16034
16035 /**
16036  * gtk_tree_view_set_show_expanders:
16037  * @tree_view: a #GtkTreeView
16038  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16039  *
16040  * Sets whether to draw and enable expanders and indent child rows in
16041  * @tree_view.  When disabled there will be no expanders visible in trees
16042  * and there will be no way to expand and collapse rows by default.  Also
16043  * note that hiding the expanders will disable the default indentation.  You
16044  * can set a custom indentation in this case using
16045  * gtk_tree_view_set_level_indentation().
16046  * This does not have any visible effects for lists.
16047  *
16048  * Since: 2.12
16049  */
16050 void
16051 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16052                                   gboolean     enabled)
16053 {
16054   gboolean was_enabled;
16055
16056   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16057
16058   enabled = enabled != FALSE;
16059   was_enabled = tree_view->priv->show_expanders;
16060
16061   tree_view->priv->show_expanders = enabled == TRUE;
16062
16063   if (enabled != was_enabled)
16064     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16065 }
16066
16067 /**
16068  * gtk_tree_view_get_show_expanders:
16069  * @tree_view: a #GtkTreeView.
16070  *
16071  * Returns whether or not expanders are drawn in @tree_view.
16072  *
16073  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
16074  * otherwise.
16075  *
16076  * Since: 2.12
16077  */
16078 gboolean
16079 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16080 {
16081   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16082
16083   return tree_view->priv->show_expanders;
16084 }
16085
16086 /**
16087  * gtk_tree_view_set_level_indentation:
16088  * @tree_view: a #GtkTreeView
16089  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16090  *
16091  * Sets the amount of extra indentation for child levels to use in @tree_view
16092  * in addition to the default indentation.  The value should be specified in
16093  * pixels, a value of 0 disables this feature and in this case only the default
16094  * indentation will be used.
16095  * This does not have any visible effects for lists.
16096  *
16097  * Since: 2.12
16098  */
16099 void
16100 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16101                                      gint         indentation)
16102 {
16103   tree_view->priv->level_indentation = indentation;
16104
16105   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16106 }
16107
16108 /**
16109  * gtk_tree_view_get_level_indentation:
16110  * @tree_view: a #GtkTreeView.
16111  *
16112  * Returns the amount, in pixels, of extra indentation for child levels
16113  * in @tree_view.
16114  *
16115  * Return value: the amount of extra indentation for child levels in
16116  * @tree_view.  A return value of 0 means that this feature is disabled.
16117  *
16118  * Since: 2.12
16119  */
16120 gint
16121 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16122 {
16123   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16124
16125   return tree_view->priv->level_indentation;
16126 }
16127
16128 /**
16129  * gtk_tree_view_set_tooltip_row:
16130  * @tree_view: a #GtkTreeView
16131  * @tooltip: a #GtkTooltip
16132  * @path: a #GtkTreePath
16133  *
16134  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16135  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16136  * See also gtk_tooltip_set_tip_area().
16137  *
16138  * Since: 2.12
16139  */
16140 void
16141 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16142                                GtkTooltip  *tooltip,
16143                                GtkTreePath *path)
16144 {
16145   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16146   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16147
16148   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16149 }
16150
16151 /**
16152  * gtk_tree_view_set_tooltip_cell:
16153  * @tree_view: a #GtkTreeView
16154  * @tooltip: a #GtkTooltip
16155  * @path: (allow-none): a #GtkTreePath or %NULL
16156  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16157  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16158  *
16159  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16160  * in common.  For example if @path is %NULL and @column is set, the tip
16161  * area will be set to the full area covered by @column.  See also
16162  * gtk_tooltip_set_tip_area().
16163  *
16164  * Note that if @path is not specified and @cell is set and part of a column
16165  * containing the expander, the tooltip might not show and hide at the correct
16166  * position.  In such cases @path must be set to the current node under the
16167  * mouse cursor for this function to operate correctly.
16168  *
16169  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16170  *
16171  * Since: 2.12
16172  */
16173 void
16174 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16175                                 GtkTooltip        *tooltip,
16176                                 GtkTreePath       *path,
16177                                 GtkTreeViewColumn *column,
16178                                 GtkCellRenderer   *cell)
16179 {
16180   GtkAllocation allocation;
16181   GdkRectangle rect;
16182
16183   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16184   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16185   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16186   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16187
16188   /* Determine x values. */
16189   if (column && cell)
16190     {
16191       GdkRectangle tmp;
16192       gint start, width;
16193
16194       /* We always pass in path here, whether it is NULL or not.
16195        * For cells in expander columns path must be specified so that
16196        * we can correctly account for the indentation.  This also means
16197        * that the tooltip is constrained vertically by the "Determine y
16198        * values" code below; this is not a real problem since cells actually
16199        * don't stretch vertically in constrast to columns.
16200        */
16201       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16202       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16203
16204       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16205                                                          tmp.x + start, 0,
16206                                                          &rect.x, NULL);
16207       rect.width = width;
16208     }
16209   else if (column)
16210     {
16211       GdkRectangle tmp;
16212
16213       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16214       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16215                                                          tmp.x, 0,
16216                                                          &rect.x, NULL);
16217       rect.width = tmp.width;
16218     }
16219   else
16220     {
16221       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16222       rect.x = 0;
16223       rect.width = allocation.width;
16224     }
16225
16226   /* Determine y values. */
16227   if (path)
16228     {
16229       GdkRectangle tmp;
16230
16231       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16232       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16233                                                          0, tmp.y,
16234                                                          NULL, &rect.y);
16235       rect.height = tmp.height;
16236     }
16237   else
16238     {
16239       rect.y = 0;
16240       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16241     }
16242
16243   gtk_tooltip_set_tip_area (tooltip, &rect);
16244 }
16245
16246 /**
16247  * gtk_tree_view_get_tooltip_context:
16248  * @tree_view: a #GtkTreeView
16249  * @x: (inout): the x coordinate (relative to widget coordinates)
16250  * @y: (inout): the y coordinate (relative to widget coordinates)
16251  * @keyboard_tip: whether this is a keyboard tooltip or not
16252  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
16253  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16254  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16255  *
16256  * This function is supposed to be used in a #GtkWidget::query-tooltip
16257  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16258  * which are received in the signal handler, should be passed to this
16259  * function without modification.
16260  *
16261  * The return value indicates whether there is a tree view row at the given
16262  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16263  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16264  * @model, @path and @iter which have been provided will be set to point to
16265  * that row and the corresponding model.  @x and @y will always be converted
16266  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16267  *
16268  * Return value: whether or not the given tooltip context points to a row.
16269  *
16270  * Since: 2.12
16271  */
16272 gboolean
16273 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16274                                    gint          *x,
16275                                    gint          *y,
16276                                    gboolean       keyboard_tip,
16277                                    GtkTreeModel **model,
16278                                    GtkTreePath  **path,
16279                                    GtkTreeIter   *iter)
16280 {
16281   GtkTreePath *tmppath = NULL;
16282
16283   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16284   g_return_val_if_fail (x != NULL, FALSE);
16285   g_return_val_if_fail (y != NULL, FALSE);
16286
16287   if (keyboard_tip)
16288     {
16289       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16290
16291       if (!tmppath)
16292         return FALSE;
16293     }
16294   else
16295     {
16296       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16297                                                          x, y);
16298
16299       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16300                                           &tmppath, NULL, NULL, NULL))
16301         return FALSE;
16302     }
16303
16304   if (model)
16305     *model = gtk_tree_view_get_model (tree_view);
16306
16307   if (iter)
16308     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16309                              iter, tmppath);
16310
16311   if (path)
16312     *path = tmppath;
16313   else
16314     gtk_tree_path_free (tmppath);
16315
16316   return TRUE;
16317 }
16318
16319 static gboolean
16320 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16321                                     gint        x,
16322                                     gint        y,
16323                                     gboolean    keyboard_tip,
16324                                     GtkTooltip *tooltip,
16325                                     gpointer    data)
16326 {
16327   GValue value = G_VALUE_INIT;
16328   GValue transformed = G_VALUE_INIT;
16329   GtkTreeIter iter;
16330   GtkTreePath *path;
16331   GtkTreeModel *model;
16332   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16333
16334   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16335                                           &x, &y,
16336                                           keyboard_tip,
16337                                           &model, &path, &iter))
16338     return FALSE;
16339
16340   gtk_tree_model_get_value (model, &iter,
16341                             tree_view->priv->tooltip_column, &value);
16342
16343   g_value_init (&transformed, G_TYPE_STRING);
16344
16345   if (!g_value_transform (&value, &transformed))
16346     {
16347       g_value_unset (&value);
16348       gtk_tree_path_free (path);
16349
16350       return FALSE;
16351     }
16352
16353   g_value_unset (&value);
16354
16355   if (!g_value_get_string (&transformed))
16356     {
16357       g_value_unset (&transformed);
16358       gtk_tree_path_free (path);
16359
16360       return FALSE;
16361     }
16362
16363   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16364   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16365
16366   gtk_tree_path_free (path);
16367   g_value_unset (&transformed);
16368
16369   return TRUE;
16370 }
16371
16372 /**
16373  * gtk_tree_view_set_tooltip_column:
16374  * @tree_view: a #GtkTreeView
16375  * @column: an integer, which is a valid column number for @tree_view's model
16376  *
16377  * If you only plan to have simple (text-only) tooltips on full rows, you
16378  * can use this function to have #GtkTreeView handle these automatically
16379  * for you. @column should be set to the column in @tree_view's model
16380  * containing the tooltip texts, or -1 to disable this feature.
16381  *
16382  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
16383  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16384  *
16385  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16386  * so &amp;, &lt;, etc have to be escaped in the text.
16387  *
16388  * Since: 2.12
16389  */
16390 void
16391 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16392                                   gint         column)
16393 {
16394   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16395
16396   if (column == tree_view->priv->tooltip_column)
16397     return;
16398
16399   if (column == -1)
16400     {
16401       g_signal_handlers_disconnect_by_func (tree_view,
16402                                             gtk_tree_view_set_tooltip_query_cb,
16403                                             NULL);
16404       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16405     }
16406   else
16407     {
16408       if (tree_view->priv->tooltip_column == -1)
16409         {
16410           g_signal_connect (tree_view, "query-tooltip",
16411                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16412           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16413         }
16414     }
16415
16416   tree_view->priv->tooltip_column = column;
16417   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16418 }
16419
16420 /**
16421  * gtk_tree_view_get_tooltip_column:
16422  * @tree_view: a #GtkTreeView
16423  *
16424  * Returns the column of @tree_view's model which is being used for
16425  * displaying tooltips on @tree_view's rows.
16426  *
16427  * Return value: the index of the tooltip column that is currently being
16428  * used, or -1 if this is disabled.
16429  *
16430  * Since: 2.12
16431  */
16432 gint
16433 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16434 {
16435   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16436
16437   return tree_view->priv->tooltip_column;
16438 }