]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Removed calculation of background area when about to edit a cell (no need to check...
[~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 #include <math.h>
23 #include <string.h>
24 #include <gdk/gdkkeysyms.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmain.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtkalignment.h"
36 #include "gtklabel.h"
37 #include "gtkhbox.h"
38 #include "gtkvbox.h"
39 #include "gtkarrow.h"
40 #include "gtkintl.h"
41 #include "gtkbindings.h"
42 #include "gtkcontainer.h"
43 #include "gtkentry.h"
44 #include "gtkframe.h"
45 #include "gtktreemodelsort.h"
46 #include "gtktooltip.h"
47 #include "gtkscrollable.h"
48 #include "gtkcelllayout.h"
49 #include "gtkprivate.h"
50 #include "gtkwidgetprivate.h"
51 #include "gtkentryprivate.h"
52
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_shift;
402   gint rubber_band_ctrl;
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 ctrl_pressed : 1;
467   guint shift_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 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
580                                                     GtkAllocation    *allocation);
581 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
582                                                     cairo_t          *cr);
583 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
584                                                     GdkEventKey      *event);
585 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
586                                                     GdkEventKey      *event);
587 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
588                                                     GdkEventMotion   *event);
589 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
590                                                     GdkEventCrossing *event);
591 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
592                                                     GdkEventCrossing *event);
593 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
594                                                     GdkEventButton   *event);
595 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
596                                                     GdkEventButton   *event);
597 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
598                                                     GdkEventGrabBroken *event);
599 #if 0
600 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
601                                                     GdkEventConfigure *event);
602 #endif
603
604 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
605                                                     GtkWidget        *child);
606 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
607                                                     GdkEventFocus    *event);
608 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
609                                                     GtkDirectionType  direction);
610 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
611 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
612                                                     GtkStyle         *previous_style);
613 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
614                                                     gboolean          was_grabbed);
615 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
616                                                     GtkStateType      previous_state);
617
618 /* container signals */
619 static void     gtk_tree_view_remove               (GtkContainer     *container,
620                                                     GtkWidget        *widget);
621 static void     gtk_tree_view_forall               (GtkContainer     *container,
622                                                     gboolean          include_internals,
623                                                     GtkCallback       callback,
624                                                     gpointer          callback_data);
625
626 /* Source side drag signals */
627 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
628                                             GdkDragContext   *context);
629 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
630                                             GdkDragContext   *context);
631 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
632                                             GdkDragContext   *context,
633                                             GtkSelectionData *selection_data,
634                                             guint             info,
635                                             guint             time);
636 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
637                                             GdkDragContext   *context);
638
639 /* Target side drag signals */
640 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
641                                                   GdkDragContext   *context,
642                                                   guint             time);
643 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
644                                                   GdkDragContext   *context,
645                                                   gint              x,
646                                                   gint              y,
647                                                   guint             time);
648 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
649                                                   GdkDragContext   *context,
650                                                   gint              x,
651                                                   gint              y,
652                                                   guint             time);
653 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
654                                                   GdkDragContext   *context,
655                                                   gint              x,
656                                                   gint              y,
657                                                   GtkSelectionData *selection_data,
658                                                   guint             info,
659                                                   guint             time);
660
661 /* tree_model signals */
662 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
663                                                            GtkAdjustment   *adjustment);
664 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
665                                                            GtkAdjustment   *adjustment);
666 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
667                                                            GtkMovementStep  step,
668                                                            gint             count);
669 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
670 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
671 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
672                                                            gboolean         start_editing);
673 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
674 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
675                                                                gboolean         logical,
676                                                                gboolean         expand,
677                                                                gboolean         open_all);
678 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
679 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
680                                                            GtkTreePath     *path,
681                                                            GtkTreeIter     *iter,
682                                                            gpointer         data);
683 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
684                                                            GtkTreePath     *path,
685                                                            GtkTreeIter     *iter,
686                                                            gpointer         data);
687 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
688                                                            GtkTreePath     *path,
689                                                            GtkTreeIter     *iter,
690                                                            gpointer         data);
691 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
692                                                            GtkTreePath     *path,
693                                                            gpointer         data);
694 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
695                                                            GtkTreePath     *parent,
696                                                            GtkTreeIter     *iter,
697                                                            gint            *new_order,
698                                                            gpointer         data);
699
700 /* Incremental reflow */
701 static gboolean validate_row             (GtkTreeView *tree_view,
702                                           GtkRBTree   *tree,
703                                           GtkRBNode   *node,
704                                           GtkTreeIter *iter,
705                                           GtkTreePath *path);
706 static void     validate_visible_area    (GtkTreeView *tree_view);
707 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
708 static gboolean do_validate_rows         (GtkTreeView *tree_view,
709                                           gboolean     size_request);
710 static gboolean validate_rows            (GtkTreeView *tree_view);
711 static gboolean presize_handler_callback (gpointer     data);
712 static void     install_presize_handler  (GtkTreeView *tree_view);
713 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
714 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
715                                              GtkTreePath *path,
716                                              gint         offset);
717 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
718 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
719 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
720
721 /* Internal functions */
722 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
723                                                               GtkTreeViewColumn  *column);
724 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
725 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
726                                                               guint               keyval,
727                                                               guint               modmask,
728                                                               gboolean            add_shifted_binding,
729                                                               GtkMovementStep     step,
730                                                               gint                count);
731 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
732                                                               GtkRBTree          *tree);
733 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
734                                                               GtkTreePath        *path,
735                                                               const GdkRectangle *clip_rect);
736 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
737                                                               GtkRBTree          *tree,
738                                                               GtkRBNode          *node);
739 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
740                                                               cairo_t            *cr,
741                                                               GtkRBTree          *tree,
742                                                               GtkRBNode          *node,
743                                                               gint                x,
744                                                               gint                y);
745 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
746                                                               GtkRBTree          *tree,
747                                                               gint               *x1,
748                                                               gint               *x2);
749 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
750                                                               gint                i,
751                                                               gint               *x);
752 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
753                                                               GtkTreeView        *tree_view);
754 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
755                                                               GtkRBTree          *tree,
756                                                               GtkTreeIter        *iter,
757                                                               gint                depth,
758                                                               gboolean            recurse);
759 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
760                                                               GtkRBTree          *tree,
761                                                               GtkRBNode          *node);
762 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
763                                                               GtkTreeViewColumn  *column,
764                                                               gboolean            focus_to_cell);
765 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
766                                                               GdkEventMotion     *event);
767 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
768 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
769                                                               gint                count);
770 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
771                                                               gint                count);
772 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
773                                                               gint                count);
774 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
775                                                               gint                count);
776 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
777                                                               GtkTreePath        *path,
778                                                               GtkRBTree          *tree,
779                                                               GtkRBNode          *node,
780                                                               gboolean            animate);
781 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
782                                                               GtkTreePath        *path,
783                                                               GtkRBTree          *tree,
784                                                               GtkRBNode          *node,
785                                                               gboolean            open_all,
786                                                               gboolean            animate);
787 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
788                                                               GtkTreePath        *path,
789                                                               gboolean            clear_and_select,
790                                                               gboolean            clamp_node);
791 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
792 static void     column_sizing_notify                         (GObject            *object,
793                                                               GParamSpec         *pspec,
794                                                               gpointer            data);
795 static gboolean expand_collapse_timeout                      (gpointer            data);
796 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
797                                                               GtkRBTree          *tree,
798                                                               GtkRBNode          *node,
799                                                               gboolean            expand);
800 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
801 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
802 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
803 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
804 static void     update_prelight                              (GtkTreeView        *tree_view,
805                                                               int                 x,
806                                                               int                 y);
807
808 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
809
810 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
811                                                               GtkRBTree   *tree,
812                                                               GtkRBNode   *node,
813                                                               gint         vertical_separator);
814 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
815                                                               GtkRBNode   *node,
816                                                               gint         vertical_separator);
817
818 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
819                                                               GtkRBTree   *tree,
820                                                               GtkRBNode   *node);
821 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
822                                                               GtkRBNode   *node);
823
824 /* interactive search */
825 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
826 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
827                                                          GtkTreeView      *tree_view,
828                                                          GdkDevice        *device);
829 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
830                                                          GtkWidget        *search_dialog,
831                                                          gpointer          user_data);
832 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
833                                                          GtkMenu          *menu,
834                                                          gpointer          data);
835 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
836                                                          GtkTreeView      *tree_view);
837 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
838                                                          GtkTreeView      *tree_view);
839 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
840 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
841                                                          gpointer          data);
842 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
843                                                          GdkEventAny      *event,
844                                                          GtkTreeView      *tree_view);
845 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
846                                                          GdkEventButton   *event,
847                                                          GtkTreeView      *tree_view);
848 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
849                                                          GdkEventScroll   *event,
850                                                          GtkTreeView      *tree_view);
851 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
852                                                          GdkEventKey      *event,
853                                                          GtkTreeView      *tree_view);
854 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
855                                                          GtkTreeView      *tree_view,
856                                                          gboolean          up);
857 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
858                                                          gint              column,
859                                                          const gchar      *key,
860                                                          GtkTreeIter      *iter,
861                                                          gpointer          search_data);
862 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
863                                                          GtkTreeSelection *selection,
864                                                          GtkTreeIter      *iter,
865                                                          const gchar      *text,
866                                                          gint             *count,
867                                                          gint              n);
868 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
869                                                          GtkTreeView      *tree_view);
870 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
871                                                          GtkWidget        *child_widget,
872                                                          gint              x,
873                                                          gint              y,
874                                                          gint              width,
875                                                          gint              height);
876 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
877                                                          GtkTreePath      *cursor_path);
878 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
879                                                          gboolean     cancel_editing);
880 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
881                                                              GdkDevice   *device,
882                                                              gboolean     keybinding);
883 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
884 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
885                                                          GtkTreeViewColumn *column,
886                                                          gint               drop_position);
887
888 /* GtkBuildable */
889 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
890                                                             GtkBuilder        *builder,
891                                                             GObject           *child,
892                                                             const gchar       *type);
893 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
894                                                             GtkBuilder        *builder,
895                                                             const gchar       *childname);
896 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
897
898
899 static gboolean scroll_row_timeout                   (gpointer     data);
900 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
901 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
902
903 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
904
905 \f
906
907 /* GType Methods
908  */
909
910 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
911                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
912                                                 gtk_tree_view_buildable_init)
913                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
914
915 static void
916 gtk_tree_view_class_init (GtkTreeViewClass *class)
917 {
918   GObjectClass *o_class;
919   GtkWidgetClass *widget_class;
920   GtkContainerClass *container_class;
921   GtkBindingSet *binding_set;
922
923   binding_set = gtk_binding_set_by_class (class);
924
925   o_class = (GObjectClass *) class;
926   widget_class = (GtkWidgetClass *) class;
927   container_class = (GtkContainerClass *) class;
928
929   /* GObject signals */
930   o_class->set_property = gtk_tree_view_set_property;
931   o_class->get_property = gtk_tree_view_get_property;
932   o_class->finalize = gtk_tree_view_finalize;
933
934   /* GtkWidget signals */
935   widget_class->destroy = gtk_tree_view_destroy;
936   widget_class->map = gtk_tree_view_map;
937   widget_class->realize = gtk_tree_view_realize;
938   widget_class->unrealize = gtk_tree_view_unrealize;
939   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
940   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
941   widget_class->size_allocate = gtk_tree_view_size_allocate;
942   widget_class->button_press_event = gtk_tree_view_button_press;
943   widget_class->button_release_event = gtk_tree_view_button_release;
944   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
945   /*widget_class->configure_event = gtk_tree_view_configure;*/
946   widget_class->motion_notify_event = gtk_tree_view_motion;
947   widget_class->draw = gtk_tree_view_draw;
948   widget_class->key_press_event = gtk_tree_view_key_press;
949   widget_class->key_release_event = gtk_tree_view_key_release;
950   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
951   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
952   widget_class->focus_out_event = gtk_tree_view_focus_out;
953   widget_class->drag_begin = gtk_tree_view_drag_begin;
954   widget_class->drag_end = gtk_tree_view_drag_end;
955   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
956   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
957   widget_class->drag_leave = gtk_tree_view_drag_leave;
958   widget_class->drag_motion = gtk_tree_view_drag_motion;
959   widget_class->drag_drop = gtk_tree_view_drag_drop;
960   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
961   widget_class->focus = gtk_tree_view_focus;
962   widget_class->grab_focus = gtk_tree_view_grab_focus;
963   widget_class->style_set = gtk_tree_view_style_set;
964   widget_class->grab_notify = gtk_tree_view_grab_notify;
965   widget_class->state_changed = gtk_tree_view_state_changed;
966
967   /* GtkContainer signals */
968   container_class->remove = gtk_tree_view_remove;
969   container_class->forall = gtk_tree_view_forall;
970   container_class->set_focus_child = gtk_tree_view_set_focus_child;
971
972   class->move_cursor = gtk_tree_view_real_move_cursor;
973   class->select_all = gtk_tree_view_real_select_all;
974   class->unselect_all = gtk_tree_view_real_unselect_all;
975   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
976   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
977   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
978   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
979   class->start_interactive_search = gtk_tree_view_start_interactive_search;
980
981   /* Properties */
982
983   g_object_class_install_property (o_class,
984                                    PROP_MODEL,
985                                    g_param_spec_object ("model",
986                                                         P_("TreeView Model"),
987                                                         P_("The model for the tree view"),
988                                                         GTK_TYPE_TREE_MODEL,
989                                                         GTK_PARAM_READWRITE));
990
991   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
992   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
993   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
994   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
995
996   g_object_class_install_property (o_class,
997                                    PROP_HEADERS_VISIBLE,
998                                    g_param_spec_boolean ("headers-visible",
999                                                          P_("Headers Visible"),
1000                                                          P_("Show the column header buttons"),
1001                                                          TRUE,
1002                                                          GTK_PARAM_READWRITE));
1003
1004   g_object_class_install_property (o_class,
1005                                    PROP_HEADERS_CLICKABLE,
1006                                    g_param_spec_boolean ("headers-clickable",
1007                                                          P_("Headers Clickable"),
1008                                                          P_("Column headers respond to click events"),
1009                                                          TRUE,
1010                                                          GTK_PARAM_READWRITE));
1011
1012   g_object_class_install_property (o_class,
1013                                    PROP_EXPANDER_COLUMN,
1014                                    g_param_spec_object ("expander-column",
1015                                                         P_("Expander Column"),
1016                                                         P_("Set the column for the expander column"),
1017                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1018                                                         GTK_PARAM_READWRITE));
1019
1020   g_object_class_install_property (o_class,
1021                                    PROP_REORDERABLE,
1022                                    g_param_spec_boolean ("reorderable",
1023                                                          P_("Reorderable"),
1024                                                          P_("View is reorderable"),
1025                                                          FALSE,
1026                                                          GTK_PARAM_READWRITE));
1027
1028   g_object_class_install_property (o_class,
1029                                    PROP_RULES_HINT,
1030                                    g_param_spec_boolean ("rules-hint",
1031                                                          P_("Rules Hint"),
1032                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1033                                                          FALSE,
1034                                                          GTK_PARAM_READWRITE));
1035
1036     g_object_class_install_property (o_class,
1037                                      PROP_ENABLE_SEARCH,
1038                                      g_param_spec_boolean ("enable-search",
1039                                                            P_("Enable Search"),
1040                                                            P_("View allows user to search through columns interactively"),
1041                                                            TRUE,
1042                                                            GTK_PARAM_READWRITE));
1043
1044     g_object_class_install_property (o_class,
1045                                      PROP_SEARCH_COLUMN,
1046                                      g_param_spec_int ("search-column",
1047                                                        P_("Search Column"),
1048                                                        P_("Model column to search through during interactive search"),
1049                                                        -1,
1050                                                        G_MAXINT,
1051                                                        -1,
1052                                                        GTK_PARAM_READWRITE));
1053
1054     /**
1055      * GtkTreeView:fixed-height-mode:
1056      *
1057      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1058      * #GtkTreeView by assuming that all rows have the same height. 
1059      * Only enable this option if all rows are the same height.  
1060      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1061      * information on this option.
1062      *
1063      * Since: 2.4
1064      **/
1065     g_object_class_install_property (o_class,
1066                                      PROP_FIXED_HEIGHT_MODE,
1067                                      g_param_spec_boolean ("fixed-height-mode",
1068                                                            P_("Fixed Height Mode"),
1069                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1070                                                            FALSE,
1071                                                            GTK_PARAM_READWRITE));
1072     
1073     /**
1074      * GtkTreeView:hover-selection:
1075      * 
1076      * Enables or disables the hover selection mode of @tree_view.
1077      * Hover selection makes the selected row follow the pointer.
1078      * Currently, this works only for the selection modes 
1079      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1080      *
1081      * This mode is primarily intended for treeviews in popups, e.g.
1082      * in #GtkComboBox or #GtkEntryCompletion.
1083      *
1084      * Since: 2.6
1085      */
1086     g_object_class_install_property (o_class,
1087                                      PROP_HOVER_SELECTION,
1088                                      g_param_spec_boolean ("hover-selection",
1089                                                            P_("Hover Selection"),
1090                                                            P_("Whether the selection should follow the pointer"),
1091                                                            FALSE,
1092                                                            GTK_PARAM_READWRITE));
1093
1094     /**
1095      * GtkTreeView:hover-expand:
1096      * 
1097      * Enables or disables the hover expansion mode of @tree_view.
1098      * Hover expansion makes rows expand or collapse if the pointer moves 
1099      * over them.
1100      *
1101      * This mode is primarily intended for treeviews in popups, e.g.
1102      * in #GtkComboBox or #GtkEntryCompletion.
1103      *
1104      * Since: 2.6
1105      */
1106     g_object_class_install_property (o_class,
1107                                      PROP_HOVER_EXPAND,
1108                                      g_param_spec_boolean ("hover-expand",
1109                                                            P_("Hover Expand"),
1110                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1111                                                            FALSE,
1112                                                            GTK_PARAM_READWRITE));
1113
1114     /**
1115      * GtkTreeView:show-expanders:
1116      *
1117      * %TRUE if the view has expanders.
1118      *
1119      * Since: 2.12
1120      */
1121     g_object_class_install_property (o_class,
1122                                      PROP_SHOW_EXPANDERS,
1123                                      g_param_spec_boolean ("show-expanders",
1124                                                            P_("Show Expanders"),
1125                                                            P_("View has expanders"),
1126                                                            TRUE,
1127                                                            GTK_PARAM_READWRITE));
1128
1129     /**
1130      * GtkTreeView:level-indentation:
1131      *
1132      * Extra indentation for each level.
1133      *
1134      * Since: 2.12
1135      */
1136     g_object_class_install_property (o_class,
1137                                      PROP_LEVEL_INDENTATION,
1138                                      g_param_spec_int ("level-indentation",
1139                                                        P_("Level Indentation"),
1140                                                        P_("Extra indentation for each level"),
1141                                                        0,
1142                                                        G_MAXINT,
1143                                                        0,
1144                                                        GTK_PARAM_READWRITE));
1145
1146     g_object_class_install_property (o_class,
1147                                      PROP_RUBBER_BANDING,
1148                                      g_param_spec_boolean ("rubber-banding",
1149                                                            P_("Rubber Banding"),
1150                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1151                                                            FALSE,
1152                                                            GTK_PARAM_READWRITE));
1153
1154     g_object_class_install_property (o_class,
1155                                      PROP_ENABLE_GRID_LINES,
1156                                      g_param_spec_enum ("enable-grid-lines",
1157                                                         P_("Enable Grid Lines"),
1158                                                         P_("Whether grid lines should be drawn in the tree view"),
1159                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1160                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1161                                                         GTK_PARAM_READWRITE));
1162
1163     g_object_class_install_property (o_class,
1164                                      PROP_ENABLE_TREE_LINES,
1165                                      g_param_spec_boolean ("enable-tree-lines",
1166                                                            P_("Enable Tree Lines"),
1167                                                            P_("Whether tree lines should be drawn in the tree view"),
1168                                                            FALSE,
1169                                                            GTK_PARAM_READWRITE));
1170
1171     g_object_class_install_property (o_class,
1172                                      PROP_TOOLTIP_COLUMN,
1173                                      g_param_spec_int ("tooltip-column",
1174                                                        P_("Tooltip Column"),
1175                                                        P_("The column in the model containing the tooltip texts for the rows"),
1176                                                        -1,
1177                                                        G_MAXINT,
1178                                                        -1,
1179                                                        GTK_PARAM_READWRITE));
1180
1181   /* Style properties */
1182 #define _TREE_VIEW_EXPANDER_SIZE 12
1183 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1184 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1185
1186   gtk_widget_class_install_style_property (widget_class,
1187                                            g_param_spec_int ("expander-size",
1188                                                              P_("Expander Size"),
1189                                                              P_("Size of the expander arrow"),
1190                                                              0,
1191                                                              G_MAXINT,
1192                                                              _TREE_VIEW_EXPANDER_SIZE,
1193                                                              GTK_PARAM_READABLE));
1194
1195   gtk_widget_class_install_style_property (widget_class,
1196                                            g_param_spec_int ("vertical-separator",
1197                                                              P_("Vertical Separator Width"),
1198                                                              P_("Vertical space between cells.  Must be an even number"),
1199                                                              0,
1200                                                              G_MAXINT,
1201                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1202                                                              GTK_PARAM_READABLE));
1203
1204   gtk_widget_class_install_style_property (widget_class,
1205                                            g_param_spec_int ("horizontal-separator",
1206                                                              P_("Horizontal Separator Width"),
1207                                                              P_("Horizontal space between cells.  Must be an even number"),
1208                                                              0,
1209                                                              G_MAXINT,
1210                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1211                                                              GTK_PARAM_READABLE));
1212
1213   gtk_widget_class_install_style_property (widget_class,
1214                                            g_param_spec_boolean ("allow-rules",
1215                                                                  P_("Allow Rules"),
1216                                                                  P_("Allow drawing of alternating color rows"),
1217                                                                  TRUE,
1218                                                                  GTK_PARAM_READABLE));
1219
1220   gtk_widget_class_install_style_property (widget_class,
1221                                            g_param_spec_boolean ("indent-expanders",
1222                                                                  P_("Indent Expanders"),
1223                                                                  P_("Make the expanders indented"),
1224                                                                  TRUE,
1225                                                                  GTK_PARAM_READABLE));
1226
1227   gtk_widget_class_install_style_property (widget_class,
1228                                            g_param_spec_boxed ("even-row-color",
1229                                                                P_("Even Row Color"),
1230                                                                P_("Color to use for even rows"),
1231                                                                GDK_TYPE_COLOR,
1232                                                                GTK_PARAM_READABLE));
1233
1234   gtk_widget_class_install_style_property (widget_class,
1235                                            g_param_spec_boxed ("odd-row-color",
1236                                                                P_("Odd Row Color"),
1237                                                                P_("Color to use for odd rows"),
1238                                                                GDK_TYPE_COLOR,
1239                                                                GTK_PARAM_READABLE));
1240
1241   gtk_widget_class_install_style_property (widget_class,
1242                                            g_param_spec_int ("grid-line-width",
1243                                                              P_("Grid line width"),
1244                                                              P_("Width, in pixels, of the tree view grid lines"),
1245                                                              0, G_MAXINT, 1,
1246                                                              GTK_PARAM_READABLE));
1247
1248   gtk_widget_class_install_style_property (widget_class,
1249                                            g_param_spec_int ("tree-line-width",
1250                                                              P_("Tree line width"),
1251                                                              P_("Width, in pixels, of the tree view lines"),
1252                                                              0, G_MAXINT, 1,
1253                                                              GTK_PARAM_READABLE));
1254
1255   gtk_widget_class_install_style_property (widget_class,
1256                                            g_param_spec_string ("grid-line-pattern",
1257                                                                 P_("Grid line pattern"),
1258                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1259                                                                 "\1\1",
1260                                                                 GTK_PARAM_READABLE));
1261
1262   gtk_widget_class_install_style_property (widget_class,
1263                                            g_param_spec_string ("tree-line-pattern",
1264                                                                 P_("Tree line pattern"),
1265                                                                 P_("Dash pattern used to draw the tree view lines"),
1266                                                                 "\1\1",
1267                                                                 GTK_PARAM_READABLE));
1268
1269   /* Signals */
1270   /**
1271    * GtkTreeView::row-activated:
1272    * @tree_view: the object on which the signal is emitted
1273    * @path: the #GtkTreePath for the activated row
1274    * @column: the #GtkTreeViewColumn in which the activation occurred
1275    *
1276    * The "row-activated" signal is emitted when the method
1277    * gtk_tree_view_row_activated() is called or the user double clicks 
1278    * a treeview row. It is also emitted when a non-editable row is 
1279    * selected and one of the keys: Space, Shift+Space, Return or 
1280    * Enter is pressed.
1281    * 
1282    * For selection handling refer to the <link linkend="TreeWidget">tree 
1283    * widget conceptual overview</link> as well as #GtkTreeSelection.
1284    */
1285   tree_view_signals[ROW_ACTIVATED] =
1286     g_signal_new (I_("row-activated"),
1287                   G_TYPE_FROM_CLASS (o_class),
1288                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1289                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1290                   NULL, NULL,
1291                   _gtk_marshal_VOID__BOXED_OBJECT,
1292                   G_TYPE_NONE, 2,
1293                   GTK_TYPE_TREE_PATH,
1294                   GTK_TYPE_TREE_VIEW_COLUMN);
1295
1296   /**
1297    * GtkTreeView::test-expand-row:
1298    * @tree_view: the object on which the signal is emitted
1299    * @iter: the tree iter of the row to expand
1300    * @path: a tree path that points to the row 
1301    * 
1302    * The given row is about to be expanded (show its children nodes). Use this
1303    * signal if you need to control the expandability of individual rows.
1304    *
1305    * Returns: %FALSE to allow expansion, %TRUE to reject
1306    */
1307   tree_view_signals[TEST_EXPAND_ROW] =
1308     g_signal_new (I_("test-expand-row"),
1309                   G_TYPE_FROM_CLASS (o_class),
1310                   G_SIGNAL_RUN_LAST,
1311                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1312                   _gtk_boolean_handled_accumulator, NULL,
1313                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1314                   G_TYPE_BOOLEAN, 2,
1315                   GTK_TYPE_TREE_ITER,
1316                   GTK_TYPE_TREE_PATH);
1317
1318   /**
1319    * GtkTreeView::test-collapse-row:
1320    * @tree_view: the object on which the signal is emitted
1321    * @iter: the tree iter of the row to collapse
1322    * @path: a tree path that points to the row 
1323    * 
1324    * The given row is about to be collapsed (hide its children nodes). Use this
1325    * signal if you need to control the collapsibility of individual rows.
1326    *
1327    * Returns: %FALSE to allow collapsing, %TRUE to reject
1328    */
1329   tree_view_signals[TEST_COLLAPSE_ROW] =
1330     g_signal_new (I_("test-collapse-row"),
1331                   G_TYPE_FROM_CLASS (o_class),
1332                   G_SIGNAL_RUN_LAST,
1333                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1334                   _gtk_boolean_handled_accumulator, NULL,
1335                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1336                   G_TYPE_BOOLEAN, 2,
1337                   GTK_TYPE_TREE_ITER,
1338                   GTK_TYPE_TREE_PATH);
1339
1340   /**
1341    * GtkTreeView::row-expanded:
1342    * @tree_view: the object on which the signal is emitted
1343    * @iter: the tree iter of the expanded row
1344    * @path: a tree path that points to the row 
1345    * 
1346    * The given row has been expanded (child nodes are shown).
1347    */
1348   tree_view_signals[ROW_EXPANDED] =
1349     g_signal_new (I_("row-expanded"),
1350                   G_TYPE_FROM_CLASS (o_class),
1351                   G_SIGNAL_RUN_LAST,
1352                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1353                   NULL, NULL,
1354                   _gtk_marshal_VOID__BOXED_BOXED,
1355                   G_TYPE_NONE, 2,
1356                   GTK_TYPE_TREE_ITER,
1357                   GTK_TYPE_TREE_PATH);
1358
1359   /**
1360    * GtkTreeView::row-collapsed:
1361    * @tree_view: the object on which the signal is emitted
1362    * @iter: the tree iter of the collapsed row
1363    * @path: a tree path that points to the row 
1364    * 
1365    * The given row has been collapsed (child nodes are hidden).
1366    */
1367   tree_view_signals[ROW_COLLAPSED] =
1368     g_signal_new (I_("row-collapsed"),
1369                   G_TYPE_FROM_CLASS (o_class),
1370                   G_SIGNAL_RUN_LAST,
1371                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1372                   NULL, NULL,
1373                   _gtk_marshal_VOID__BOXED_BOXED,
1374                   G_TYPE_NONE, 2,
1375                   GTK_TYPE_TREE_ITER,
1376                   GTK_TYPE_TREE_PATH);
1377
1378   /**
1379    * GtkTreeView::columns-changed:
1380    * @tree_view: the object on which the signal is emitted 
1381    * 
1382    * The number of columns of the treeview has changed.
1383    */
1384   tree_view_signals[COLUMNS_CHANGED] =
1385     g_signal_new (I_("columns-changed"),
1386                   G_TYPE_FROM_CLASS (o_class),
1387                   G_SIGNAL_RUN_LAST,
1388                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1389                   NULL, NULL,
1390                   _gtk_marshal_VOID__VOID,
1391                   G_TYPE_NONE, 0);
1392
1393   /**
1394    * GtkTreeView::cursor-changed:
1395    * @tree_view: the object on which the signal is emitted
1396    * 
1397    * The position of the cursor (focused cell) has changed.
1398    */
1399   tree_view_signals[CURSOR_CHANGED] =
1400     g_signal_new (I_("cursor-changed"),
1401                   G_TYPE_FROM_CLASS (o_class),
1402                   G_SIGNAL_RUN_LAST,
1403                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1404                   NULL, NULL,
1405                   _gtk_marshal_VOID__VOID,
1406                   G_TYPE_NONE, 0);
1407
1408   tree_view_signals[MOVE_CURSOR] =
1409     g_signal_new (I_("move-cursor"),
1410                   G_TYPE_FROM_CLASS (o_class),
1411                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1412                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1413                   NULL, NULL,
1414                   _gtk_marshal_BOOLEAN__ENUM_INT,
1415                   G_TYPE_BOOLEAN, 2,
1416                   GTK_TYPE_MOVEMENT_STEP,
1417                   G_TYPE_INT);
1418
1419   tree_view_signals[SELECT_ALL] =
1420     g_signal_new (I_("select-all"),
1421                   G_TYPE_FROM_CLASS (o_class),
1422                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1423                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1424                   NULL, NULL,
1425                   _gtk_marshal_BOOLEAN__VOID,
1426                   G_TYPE_BOOLEAN, 0);
1427
1428   tree_view_signals[UNSELECT_ALL] =
1429     g_signal_new (I_("unselect-all"),
1430                   G_TYPE_FROM_CLASS (o_class),
1431                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1432                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1433                   NULL, NULL,
1434                   _gtk_marshal_BOOLEAN__VOID,
1435                   G_TYPE_BOOLEAN, 0);
1436
1437   tree_view_signals[SELECT_CURSOR_ROW] =
1438     g_signal_new (I_("select-cursor-row"),
1439                   G_TYPE_FROM_CLASS (o_class),
1440                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1441                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1442                   NULL, NULL,
1443                   _gtk_marshal_BOOLEAN__BOOLEAN,
1444                   G_TYPE_BOOLEAN, 1,
1445                   G_TYPE_BOOLEAN);
1446
1447   tree_view_signals[TOGGLE_CURSOR_ROW] =
1448     g_signal_new (I_("toggle-cursor-row"),
1449                   G_TYPE_FROM_CLASS (o_class),
1450                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1451                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1452                   NULL, NULL,
1453                   _gtk_marshal_BOOLEAN__VOID,
1454                   G_TYPE_BOOLEAN, 0);
1455
1456   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1457     g_signal_new (I_("expand-collapse-cursor-row"),
1458                   G_TYPE_FROM_CLASS (o_class),
1459                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1460                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1461                   NULL, NULL,
1462                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1463                   G_TYPE_BOOLEAN, 3,
1464                   G_TYPE_BOOLEAN,
1465                   G_TYPE_BOOLEAN,
1466                   G_TYPE_BOOLEAN);
1467
1468   tree_view_signals[SELECT_CURSOR_PARENT] =
1469     g_signal_new (I_("select-cursor-parent"),
1470                   G_TYPE_FROM_CLASS (o_class),
1471                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1472                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1473                   NULL, NULL,
1474                   _gtk_marshal_BOOLEAN__VOID,
1475                   G_TYPE_BOOLEAN, 0);
1476
1477   tree_view_signals[START_INTERACTIVE_SEARCH] =
1478     g_signal_new (I_("start-interactive-search"),
1479                   G_TYPE_FROM_CLASS (o_class),
1480                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1481                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1482                   NULL, NULL,
1483                   _gtk_marshal_BOOLEAN__VOID,
1484                   G_TYPE_BOOLEAN, 0);
1485
1486   /* Key bindings */
1487   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1488                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1489   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1490                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1491
1492   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1493                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1494   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1495                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1496
1497   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1498                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1499
1500   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1501                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1502
1503   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1504                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1505   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1506                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1507
1508   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1509                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1510   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1511                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1512
1513   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1514                                   GTK_MOVEMENT_PAGES, -1);
1515   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1516                                   GTK_MOVEMENT_PAGES, -1);
1517
1518   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1519                                   GTK_MOVEMENT_PAGES, 1);
1520   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1521                                   GTK_MOVEMENT_PAGES, 1);
1522
1523
1524   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1525                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1526                                 G_TYPE_INT, 1);
1527
1528   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1529                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1530                                 G_TYPE_INT, -1);
1531
1532   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1533                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1534                                 G_TYPE_INT, 1);
1535
1536   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1537                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1538                                 G_TYPE_INT, -1);
1539
1540   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1541                                 "move-cursor", 2,
1542                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1543                                 G_TYPE_INT, 1);
1544
1545   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1546                                 "move-cursor", 2,
1547                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1548                                 G_TYPE_INT, -1);
1549
1550   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1551                                 "move-cursor", 2,
1552                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1553                                 G_TYPE_INT, 1);
1554
1555   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1556                                 "move-cursor", 2,
1557                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1558                                 G_TYPE_INT, -1);
1559
1560   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1561   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1562
1563   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1564   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1565
1566   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1567   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1568
1569   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1570                                 G_TYPE_BOOLEAN, TRUE);
1571   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1572                                 G_TYPE_BOOLEAN, TRUE);
1573
1574   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1575                                 G_TYPE_BOOLEAN, TRUE);
1576   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1577                                 G_TYPE_BOOLEAN, TRUE);
1578   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1579                                 G_TYPE_BOOLEAN, TRUE);
1580   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1581                                 G_TYPE_BOOLEAN, TRUE);
1582   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1583                                 G_TYPE_BOOLEAN, TRUE);
1584
1585   /* expand and collapse rows */
1586   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1587                                 G_TYPE_BOOLEAN, TRUE,
1588                                 G_TYPE_BOOLEAN, TRUE,
1589                                 G_TYPE_BOOLEAN, FALSE);
1590
1591   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1592                                 "expand-collapse-cursor-row", 3,
1593                                 G_TYPE_BOOLEAN, TRUE,
1594                                 G_TYPE_BOOLEAN, TRUE,
1595                                 G_TYPE_BOOLEAN, TRUE);
1596   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1597                                 "expand-collapse-cursor-row", 3,
1598                                 G_TYPE_BOOLEAN, TRUE,
1599                                 G_TYPE_BOOLEAN, TRUE,
1600                                 G_TYPE_BOOLEAN, TRUE);
1601
1602   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1603                                 "expand-collapse-cursor-row", 3,
1604                                 G_TYPE_BOOLEAN, TRUE,
1605                                 G_TYPE_BOOLEAN, FALSE,
1606                                 G_TYPE_BOOLEAN, FALSE);
1607   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1608                                 "expand-collapse-cursor-row", 3,
1609                                 G_TYPE_BOOLEAN, TRUE,
1610                                 G_TYPE_BOOLEAN, FALSE,
1611                                 G_TYPE_BOOLEAN, FALSE);
1612
1613   /* Not doable on US keyboards */
1614   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1615                                 G_TYPE_BOOLEAN, TRUE,
1616                                 G_TYPE_BOOLEAN, TRUE,
1617                                 G_TYPE_BOOLEAN, TRUE);
1618   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1619                                 G_TYPE_BOOLEAN, TRUE,
1620                                 G_TYPE_BOOLEAN, TRUE,
1621                                 G_TYPE_BOOLEAN, FALSE);
1622   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1623                                 G_TYPE_BOOLEAN, TRUE,
1624                                 G_TYPE_BOOLEAN, TRUE,
1625                                 G_TYPE_BOOLEAN, TRUE);
1626   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1627                                 G_TYPE_BOOLEAN, TRUE,
1628                                 G_TYPE_BOOLEAN, TRUE,
1629                                 G_TYPE_BOOLEAN, TRUE);
1630   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1631                                 "expand-collapse-cursor-row", 3,
1632                                 G_TYPE_BOOLEAN, FALSE,
1633                                 G_TYPE_BOOLEAN, TRUE,
1634                                 G_TYPE_BOOLEAN, TRUE);
1635   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1636                                 "expand-collapse-cursor-row", 3,
1637                                 G_TYPE_BOOLEAN, FALSE,
1638                                 G_TYPE_BOOLEAN, TRUE,
1639                                 G_TYPE_BOOLEAN, TRUE);
1640   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1641                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1642                                 "expand-collapse-cursor-row", 3,
1643                                 G_TYPE_BOOLEAN, FALSE,
1644                                 G_TYPE_BOOLEAN, TRUE,
1645                                 G_TYPE_BOOLEAN, TRUE);
1646   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1647                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1648                                 "expand-collapse-cursor-row", 3,
1649                                 G_TYPE_BOOLEAN, FALSE,
1650                                 G_TYPE_BOOLEAN, TRUE,
1651                                 G_TYPE_BOOLEAN, TRUE);
1652
1653   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1654                                 G_TYPE_BOOLEAN, TRUE,
1655                                 G_TYPE_BOOLEAN, FALSE,
1656                                 G_TYPE_BOOLEAN, FALSE);
1657   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1658                                 G_TYPE_BOOLEAN, TRUE,
1659                                 G_TYPE_BOOLEAN, FALSE,
1660                                 G_TYPE_BOOLEAN, TRUE);
1661   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1662                                 G_TYPE_BOOLEAN, TRUE,
1663                                 G_TYPE_BOOLEAN, FALSE,
1664                                 G_TYPE_BOOLEAN, FALSE);
1665   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1666                                 G_TYPE_BOOLEAN, TRUE,
1667                                 G_TYPE_BOOLEAN, FALSE,
1668                                 G_TYPE_BOOLEAN, TRUE);
1669   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1670                                 "expand-collapse-cursor-row", 3,
1671                                 G_TYPE_BOOLEAN, FALSE,
1672                                 G_TYPE_BOOLEAN, FALSE,
1673                                 G_TYPE_BOOLEAN, TRUE);
1674   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1675                                 "expand-collapse-cursor-row", 3,
1676                                 G_TYPE_BOOLEAN, FALSE,
1677                                 G_TYPE_BOOLEAN, FALSE,
1678                                 G_TYPE_BOOLEAN, TRUE);
1679   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1680                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1681                                 "expand-collapse-cursor-row", 3,
1682                                 G_TYPE_BOOLEAN, FALSE,
1683                                 G_TYPE_BOOLEAN, FALSE,
1684                                 G_TYPE_BOOLEAN, TRUE);
1685   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1686                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1687                                 "expand-collapse-cursor-row", 3,
1688                                 G_TYPE_BOOLEAN, FALSE,
1689                                 G_TYPE_BOOLEAN, FALSE,
1690                                 G_TYPE_BOOLEAN, TRUE);
1691
1692   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1693   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1694
1695   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1696
1697   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1698
1699   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1700 }
1701
1702 static void
1703 gtk_tree_view_init (GtkTreeView *tree_view)
1704 {
1705   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1706
1707   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1708   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1709
1710   tree_view->priv->show_expanders = TRUE;
1711   tree_view->priv->draw_keyfocus = TRUE;
1712   tree_view->priv->headers_visible = TRUE;
1713
1714   /* We need some padding */
1715   tree_view->priv->dy = 0;
1716   tree_view->priv->cursor_offset = 0;
1717   tree_view->priv->n_columns = 0;
1718   tree_view->priv->header_height = 1;
1719   tree_view->priv->x_drag = 0;
1720   tree_view->priv->drag_pos = -1;
1721   tree_view->priv->header_has_focus = FALSE;
1722   tree_view->priv->pressed_button = -1;
1723   tree_view->priv->press_start_x = -1;
1724   tree_view->priv->press_start_y = -1;
1725   tree_view->priv->reorderable = FALSE;
1726   tree_view->priv->presize_handler_timer = 0;
1727   tree_view->priv->scroll_sync_timer = 0;
1728   tree_view->priv->fixed_height = -1;
1729   tree_view->priv->fixed_height_mode = FALSE;
1730   tree_view->priv->fixed_height_check = 0;
1731   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1732   tree_view->priv->enable_search = TRUE;
1733   tree_view->priv->search_column = -1;
1734   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1735   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1736   tree_view->priv->search_custom_entry_set = FALSE;
1737   tree_view->priv->typeselect_flush_timeout = 0;
1738   tree_view->priv->init_hadjust_value = TRUE;    
1739   tree_view->priv->width = 0;
1740           
1741   tree_view->priv->hover_selection = FALSE;
1742   tree_view->priv->hover_expand = FALSE;
1743
1744   tree_view->priv->level_indentation = 0;
1745
1746   tree_view->priv->rubber_banding_enable = FALSE;
1747
1748   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1749   tree_view->priv->tree_lines_enabled = FALSE;
1750
1751   tree_view->priv->tooltip_column = -1;
1752
1753   tree_view->priv->post_validation_flag = FALSE;
1754
1755   tree_view->priv->last_button_x = -1;
1756   tree_view->priv->last_button_y = -1;
1757
1758   tree_view->priv->event_last_x = -10000;
1759   tree_view->priv->event_last_y = -10000;
1760
1761   gtk_tree_view_set_vadjustment (tree_view, NULL);
1762   gtk_tree_view_set_hadjustment (tree_view, NULL);
1763 }
1764
1765 \f
1766
1767 /* GObject Methods
1768  */
1769
1770 static void
1771 gtk_tree_view_set_property (GObject         *object,
1772                             guint            prop_id,
1773                             const GValue    *value,
1774                             GParamSpec      *pspec)
1775 {
1776   GtkTreeView *tree_view;
1777
1778   tree_view = GTK_TREE_VIEW (object);
1779
1780   switch (prop_id)
1781     {
1782     case PROP_MODEL:
1783       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1784       break;
1785     case PROP_HADJUSTMENT:
1786       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1787       break;
1788     case PROP_VADJUSTMENT:
1789       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1790       break;
1791     case PROP_HSCROLL_POLICY:
1792       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1793       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1794       break;
1795     case PROP_VSCROLL_POLICY:
1796       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1797       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1798       break;
1799     case PROP_HEADERS_VISIBLE:
1800       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1801       break;
1802     case PROP_HEADERS_CLICKABLE:
1803       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1804       break;
1805     case PROP_EXPANDER_COLUMN:
1806       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1807       break;
1808     case PROP_REORDERABLE:
1809       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1810       break;
1811     case PROP_RULES_HINT:
1812       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1813       break;
1814     case PROP_ENABLE_SEARCH:
1815       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1816       break;
1817     case PROP_SEARCH_COLUMN:
1818       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1819       break;
1820     case PROP_FIXED_HEIGHT_MODE:
1821       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1822       break;
1823     case PROP_HOVER_SELECTION:
1824       tree_view->priv->hover_selection = g_value_get_boolean (value);
1825       break;
1826     case PROP_HOVER_EXPAND:
1827       tree_view->priv->hover_expand = g_value_get_boolean (value);
1828       break;
1829     case PROP_SHOW_EXPANDERS:
1830       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1831       break;
1832     case PROP_LEVEL_INDENTATION:
1833       tree_view->priv->level_indentation = g_value_get_int (value);
1834       break;
1835     case PROP_RUBBER_BANDING:
1836       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1837       break;
1838     case PROP_ENABLE_GRID_LINES:
1839       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1840       break;
1841     case PROP_ENABLE_TREE_LINES:
1842       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1843       break;
1844     case PROP_TOOLTIP_COLUMN:
1845       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1846       break;
1847     default:
1848       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1849       break;
1850     }
1851 }
1852
1853 static void
1854 gtk_tree_view_get_property (GObject    *object,
1855                             guint       prop_id,
1856                             GValue     *value,
1857                             GParamSpec *pspec)
1858 {
1859   GtkTreeView *tree_view;
1860
1861   tree_view = GTK_TREE_VIEW (object);
1862
1863   switch (prop_id)
1864     {
1865     case PROP_MODEL:
1866       g_value_set_object (value, tree_view->priv->model);
1867       break;
1868     case PROP_HADJUSTMENT:
1869       g_value_set_object (value, tree_view->priv->hadjustment);
1870       break;
1871     case PROP_VADJUSTMENT:
1872       g_value_set_object (value, tree_view->priv->vadjustment);
1873       break;
1874     case PROP_HSCROLL_POLICY:
1875       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1876       break;
1877     case PROP_VSCROLL_POLICY:
1878       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1879       break;
1880     case PROP_HEADERS_VISIBLE:
1881       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1882       break;
1883     case PROP_HEADERS_CLICKABLE:
1884       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1885       break;
1886     case PROP_EXPANDER_COLUMN:
1887       g_value_set_object (value, tree_view->priv->expander_column);
1888       break;
1889     case PROP_REORDERABLE:
1890       g_value_set_boolean (value, tree_view->priv->reorderable);
1891       break;
1892     case PROP_RULES_HINT:
1893       g_value_set_boolean (value, tree_view->priv->has_rules);
1894       break;
1895     case PROP_ENABLE_SEARCH:
1896       g_value_set_boolean (value, tree_view->priv->enable_search);
1897       break;
1898     case PROP_SEARCH_COLUMN:
1899       g_value_set_int (value, tree_view->priv->search_column);
1900       break;
1901     case PROP_FIXED_HEIGHT_MODE:
1902       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1903       break;
1904     case PROP_HOVER_SELECTION:
1905       g_value_set_boolean (value, tree_view->priv->hover_selection);
1906       break;
1907     case PROP_HOVER_EXPAND:
1908       g_value_set_boolean (value, tree_view->priv->hover_expand);
1909       break;
1910     case PROP_SHOW_EXPANDERS:
1911       g_value_set_boolean (value, tree_view->priv->show_expanders);
1912       break;
1913     case PROP_LEVEL_INDENTATION:
1914       g_value_set_int (value, tree_view->priv->level_indentation);
1915       break;
1916     case PROP_RUBBER_BANDING:
1917       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1918       break;
1919     case PROP_ENABLE_GRID_LINES:
1920       g_value_set_enum (value, tree_view->priv->grid_lines);
1921       break;
1922     case PROP_ENABLE_TREE_LINES:
1923       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1924       break;
1925     case PROP_TOOLTIP_COLUMN:
1926       g_value_set_int (value, tree_view->priv->tooltip_column);
1927       break;
1928     default:
1929       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1930       break;
1931     }
1932 }
1933
1934 static void
1935 gtk_tree_view_finalize (GObject *object)
1936 {
1937   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1938 }
1939
1940
1941 static GtkBuildableIface *parent_buildable_iface;
1942
1943 static void
1944 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1945 {
1946   parent_buildable_iface = g_type_interface_peek_parent (iface);
1947   iface->add_child = gtk_tree_view_buildable_add_child;
1948   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1949 }
1950
1951 static void
1952 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1953                                    GtkBuilder  *builder,
1954                                    GObject     *child,
1955                                    const gchar *type)
1956 {
1957   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1958 }
1959
1960 static GObject *
1961 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1962                                             GtkBuilder        *builder,
1963                                             const gchar       *childname)
1964 {
1965     if (strcmp (childname, "selection") == 0)
1966       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1967     
1968     return parent_buildable_iface->get_internal_child (buildable,
1969                                                        builder,
1970                                                        childname);
1971 }
1972
1973 /* GtkWidget Methods
1974  */
1975
1976 static void
1977 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1978 {
1979   _gtk_rbtree_free (tree_view->priv->tree);
1980   
1981   tree_view->priv->tree = NULL;
1982   tree_view->priv->button_pressed_node = NULL;
1983   tree_view->priv->button_pressed_tree = NULL;
1984   tree_view->priv->prelight_tree = NULL;
1985   tree_view->priv->prelight_node = NULL;
1986   tree_view->priv->expanded_collapsed_node = NULL;
1987   tree_view->priv->expanded_collapsed_tree = NULL;
1988 }
1989
1990 static void
1991 gtk_tree_view_destroy (GtkWidget *widget)
1992 {
1993   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1994   GList *list;
1995
1996   gtk_tree_view_stop_editing (tree_view, TRUE);
1997
1998   if (tree_view->priv->columns != NULL)
1999     {
2000       list = tree_view->priv->columns;
2001       while (list)
2002         {
2003           GtkTreeViewColumn *column;
2004           column = GTK_TREE_VIEW_COLUMN (list->data);
2005           list = list->next;
2006           gtk_tree_view_remove_column (tree_view, column);
2007         }
2008       tree_view->priv->columns = NULL;
2009     }
2010
2011   if (tree_view->priv->tree != NULL)
2012     {
2013       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2014
2015       gtk_tree_view_free_rbtree (tree_view);
2016     }
2017
2018   if (tree_view->priv->selection != NULL)
2019     {
2020       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2021       g_object_unref (tree_view->priv->selection);
2022       tree_view->priv->selection = NULL;
2023     }
2024
2025   if (tree_view->priv->scroll_to_path != NULL)
2026     {
2027       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2028       tree_view->priv->scroll_to_path = NULL;
2029     }
2030
2031   if (tree_view->priv->drag_dest_row != NULL)
2032     {
2033       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2034       tree_view->priv->drag_dest_row = NULL;
2035     }
2036
2037   if (tree_view->priv->top_row != NULL)
2038     {
2039       gtk_tree_row_reference_free (tree_view->priv->top_row);
2040       tree_view->priv->top_row = NULL;
2041     }
2042
2043   if (tree_view->priv->column_drop_func_data &&
2044       tree_view->priv->column_drop_func_data_destroy)
2045     {
2046       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2047       tree_view->priv->column_drop_func_data = NULL;
2048     }
2049
2050   if (tree_view->priv->destroy_count_destroy &&
2051       tree_view->priv->destroy_count_data)
2052     {
2053       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2054       tree_view->priv->destroy_count_data = NULL;
2055     }
2056
2057   gtk_tree_row_reference_free (tree_view->priv->cursor);
2058   tree_view->priv->cursor = NULL;
2059
2060   gtk_tree_row_reference_free (tree_view->priv->anchor);
2061   tree_view->priv->anchor = NULL;
2062
2063   /* destroy interactive search dialog */
2064   if (tree_view->priv->search_window)
2065     {
2066       gtk_widget_destroy (tree_view->priv->search_window);
2067       tree_view->priv->search_window = NULL;
2068       tree_view->priv->search_entry = NULL;
2069       if (tree_view->priv->typeselect_flush_timeout)
2070         {
2071           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2072           tree_view->priv->typeselect_flush_timeout = 0;
2073         }
2074     }
2075
2076   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2077     {
2078       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2079       tree_view->priv->search_user_data = NULL;
2080     }
2081
2082   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2083     {
2084       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2085       tree_view->priv->search_position_user_data = NULL;
2086     }
2087
2088   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2089     {
2090       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2091       tree_view->priv->row_separator_data = NULL;
2092     }
2093   
2094   gtk_tree_view_set_model (tree_view, NULL);
2095
2096   if (tree_view->priv->hadjustment)
2097     {
2098       g_object_unref (tree_view->priv->hadjustment);
2099       tree_view->priv->hadjustment = NULL;
2100     }
2101   if (tree_view->priv->vadjustment)
2102     {
2103       g_object_unref (tree_view->priv->vadjustment);
2104       tree_view->priv->vadjustment = NULL;
2105     }
2106
2107   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2108 }
2109
2110 /* GtkWidget::map helper */
2111 static void
2112 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2113 {
2114   GList *list;
2115
2116   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2117
2118   if (tree_view->priv->headers_visible)
2119     {
2120       GtkTreeViewColumn *column;
2121       GtkWidget         *button;
2122       GdkWindow         *window;
2123
2124       for (list = tree_view->priv->columns; list; list = list->next)
2125         {
2126           column = list->data;
2127           button = gtk_tree_view_column_get_button (column);
2128
2129           if (gtk_widget_get_visible (button) &&
2130               !gtk_widget_get_mapped (button))
2131             gtk_widget_map (button);
2132         }
2133       for (list = tree_view->priv->columns; list; list = list->next)
2134         {
2135           column = list->data;
2136           if (gtk_tree_view_column_get_visible (column) == FALSE)
2137             continue;
2138
2139           window = _gtk_tree_view_column_get_window (column);
2140           if (gtk_tree_view_column_get_resizable (column))
2141             {
2142               gdk_window_raise (window);
2143               gdk_window_show (window);
2144             }
2145           else
2146             gdk_window_hide (window);
2147         }
2148       gdk_window_show (tree_view->priv->header_window);
2149     }
2150 }
2151
2152 static void
2153 gtk_tree_view_map (GtkWidget *widget)
2154 {
2155   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2156   GList *tmp_list;
2157
2158   gtk_widget_set_mapped (widget, TRUE);
2159
2160   tmp_list = tree_view->priv->children;
2161   while (tmp_list)
2162     {
2163       GtkTreeViewChild *child = tmp_list->data;
2164       tmp_list = tmp_list->next;
2165
2166       if (gtk_widget_get_visible (child->widget))
2167         {
2168           if (!gtk_widget_get_mapped (child->widget))
2169             gtk_widget_map (child->widget);
2170         }
2171     }
2172   gdk_window_show (tree_view->priv->bin_window);
2173
2174   gtk_tree_view_map_buttons (tree_view);
2175
2176   gdk_window_show (gtk_widget_get_window (widget));
2177 }
2178
2179 static void
2180 gtk_tree_view_realize (GtkWidget *widget)
2181 {
2182   GtkAllocation allocation;
2183   GtkStyle *style;
2184   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2185   GdkWindow *window;
2186   GdkWindowAttr attributes;
2187   GList *tmp_list;
2188   gint attributes_mask;
2189
2190   gtk_widget_set_realized (widget, TRUE);
2191
2192   gtk_widget_get_allocation (widget, &allocation);
2193
2194   /* Make the main, clipping window */
2195   attributes.window_type = GDK_WINDOW_CHILD;
2196   attributes.x = allocation.x;
2197   attributes.y = allocation.y;
2198   attributes.width = allocation.width;
2199   attributes.height = allocation.height;
2200   attributes.wclass = GDK_INPUT_OUTPUT;
2201   attributes.visual = gtk_widget_get_visual (widget);
2202   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2203
2204   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2205
2206   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2207                            &attributes, attributes_mask);
2208   gtk_widget_set_window (widget, window);
2209   gdk_window_set_user_data (window, widget);
2210
2211   gtk_widget_get_allocation (widget, &allocation);
2212
2213   /* Make the window for the tree */
2214   attributes.x = 0;
2215   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2216   attributes.width = MAX (tree_view->priv->width, allocation.width);
2217   attributes.height = allocation.height;
2218   attributes.event_mask = (GDK_EXPOSURE_MASK |
2219                            GDK_SCROLL_MASK |
2220                            GDK_POINTER_MOTION_MASK |
2221                            GDK_ENTER_NOTIFY_MASK |
2222                            GDK_LEAVE_NOTIFY_MASK |
2223                            GDK_BUTTON_PRESS_MASK |
2224                            GDK_BUTTON_RELEASE_MASK |
2225                            gtk_widget_get_events (widget));
2226
2227   tree_view->priv->bin_window = gdk_window_new (window,
2228                                                 &attributes, attributes_mask);
2229   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2230
2231   gtk_widget_get_allocation (widget, &allocation);
2232
2233   /* Make the column header window */
2234   attributes.x = 0;
2235   attributes.y = 0;
2236   attributes.width = MAX (tree_view->priv->width, allocation.width);
2237   attributes.height = tree_view->priv->header_height;
2238   attributes.event_mask = (GDK_EXPOSURE_MASK |
2239                            GDK_SCROLL_MASK |
2240                            GDK_ENTER_NOTIFY_MASK |
2241                            GDK_LEAVE_NOTIFY_MASK |
2242                            GDK_BUTTON_PRESS_MASK |
2243                            GDK_BUTTON_RELEASE_MASK |
2244                            GDK_KEY_PRESS_MASK |
2245                            GDK_KEY_RELEASE_MASK |
2246                            gtk_widget_get_events (widget));
2247
2248   tree_view->priv->header_window = gdk_window_new (window,
2249                                                    &attributes, attributes_mask);
2250   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2251
2252   /* Add them all up. */
2253   gtk_widget_style_attach (widget);
2254   style = gtk_widget_get_style (widget);
2255   gdk_window_set_background (tree_view->priv->bin_window,
2256                              &style->base[gtk_widget_get_state (widget)]);
2257   gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
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   GList *list;
2284
2285   if (priv->scroll_timeout != 0)
2286     {
2287       g_source_remove (priv->scroll_timeout);
2288       priv->scroll_timeout = 0;
2289     }
2290
2291   if (priv->auto_expand_timeout != 0)
2292     {
2293       g_source_remove (priv->auto_expand_timeout);
2294       priv->auto_expand_timeout = 0;
2295     }
2296
2297   if (priv->open_dest_timeout != 0)
2298     {
2299       g_source_remove (priv->open_dest_timeout);
2300       priv->open_dest_timeout = 0;
2301     }
2302
2303   remove_expand_collapse_timeout (tree_view);
2304   
2305   if (priv->presize_handler_timer != 0)
2306     {
2307       g_source_remove (priv->presize_handler_timer);
2308       priv->presize_handler_timer = 0;
2309     }
2310
2311   if (priv->validate_rows_timer != 0)
2312     {
2313       g_source_remove (priv->validate_rows_timer);
2314       priv->validate_rows_timer = 0;
2315     }
2316
2317   if (priv->scroll_sync_timer != 0)
2318     {
2319       g_source_remove (priv->scroll_sync_timer);
2320       priv->scroll_sync_timer = 0;
2321     }
2322
2323   if (priv->typeselect_flush_timeout)
2324     {
2325       g_source_remove (priv->typeselect_flush_timeout);
2326       priv->typeselect_flush_timeout = 0;
2327     }
2328   
2329   for (list = priv->columns; list; list = list->next)
2330     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2331
2332   gdk_window_set_user_data (priv->bin_window, NULL);
2333   gdk_window_destroy (priv->bin_window);
2334   priv->bin_window = NULL;
2335
2336   gdk_window_set_user_data (priv->header_window, NULL);
2337   gdk_window_destroy (priv->header_window);
2338   priv->header_window = NULL;
2339
2340   if (priv->drag_window)
2341     {
2342       gdk_window_set_user_data (priv->drag_window, NULL);
2343       gdk_window_destroy (priv->drag_window);
2344       priv->drag_window = NULL;
2345     }
2346
2347   if (priv->drag_highlight_window)
2348     {
2349       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2350       gdk_window_destroy (priv->drag_highlight_window);
2351       priv->drag_highlight_window = NULL;
2352     }
2353
2354   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2355 }
2356
2357 /* GtkWidget::size_request helper */
2358 static void
2359 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2360 {
2361   GList *list;
2362
2363   tree_view->priv->header_height = 0;
2364
2365   if (tree_view->priv->model)
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           column = list->data;
2377
2378           gtk_widget_get_preferred_size (button, &requisition, NULL);
2379           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2380         }
2381     }
2382 }
2383
2384
2385 /* Called only by ::size_request */
2386 static void
2387 gtk_tree_view_update_size (GtkTreeView *tree_view)
2388 {
2389   GList *list;
2390   GtkTreeViewColumn *column;
2391   gint i;
2392
2393   if (tree_view->priv->model == NULL)
2394     {
2395       tree_view->priv->width = 0;
2396       tree_view->priv->prev_width = 0;                   
2397       tree_view->priv->height = 0;
2398       return;
2399     }
2400
2401   tree_view->priv->prev_width = tree_view->priv->width;  
2402   tree_view->priv->width = 0;
2403
2404   /* keep this in sync with size_allocate below */
2405   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2406     {
2407       column = list->data;
2408       if (!gtk_tree_view_column_get_visible (column))
2409         continue;
2410
2411       tree_view->priv->width += _gtk_tree_view_column_request_width (column);
2412     }
2413
2414   if (tree_view->priv->tree == NULL)
2415     tree_view->priv->height = 0;
2416   else
2417     tree_view->priv->height = tree_view->priv->tree->root->offset;
2418 }
2419
2420 static void
2421 gtk_tree_view_size_request (GtkWidget      *widget,
2422                             GtkRequisition *requisition)
2423 {
2424   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2425   GList *tmp_list;
2426
2427   /* we validate some rows initially just to make sure we have some size. 
2428    * In practice, with a lot of static lists, this should get a good width.
2429    */
2430   do_validate_rows (tree_view, FALSE);
2431   gtk_tree_view_size_request_columns (tree_view);
2432   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2433
2434   requisition->width = tree_view->priv->width;
2435   requisition->height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2436
2437   tmp_list = tree_view->priv->children;
2438 }
2439
2440 static void
2441 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2442                                    gint      *minimum,
2443                                    gint      *natural)
2444 {
2445   GtkRequisition requisition;
2446
2447   gtk_tree_view_size_request (widget, &requisition);
2448
2449   *minimum = *natural = requisition.width;
2450 }
2451
2452 static void
2453 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2454                                     gint      *minimum,
2455                                     gint      *natural)
2456 {
2457   GtkRequisition requisition;
2458
2459   gtk_tree_view_size_request (widget, &requisition);
2460
2461   *minimum = *natural = requisition.height;
2462 }
2463
2464 static int
2465 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2466 {
2467   int width = 0;
2468   GList *list;
2469   gboolean rtl;
2470
2471   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2472   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2473        list->data != tree_view->priv->expander_column;
2474        list = (rtl ? list->prev : list->next))
2475     {
2476       GtkTreeViewColumn *column = list->data;
2477
2478       width += gtk_tree_view_column_get_width (column);
2479     }
2480
2481   return width;
2482 }
2483
2484 static void
2485 invalidate_column (GtkTreeView       *tree_view,
2486                    GtkTreeViewColumn *column)
2487 {
2488   gint column_offset = 0;
2489   GList *list;
2490   GtkWidget *widget = GTK_WIDGET (tree_view);
2491   gboolean rtl;
2492
2493   if (!gtk_widget_get_realized (widget))
2494     return;
2495
2496   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2497   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2498        list;
2499        list = (rtl ? list->prev : list->next))
2500     {
2501       GtkTreeViewColumn *tmpcolumn = list->data;
2502       if (tmpcolumn == column)
2503         {
2504           GtkAllocation allocation;
2505           GdkRectangle invalid_rect;
2506
2507           gtk_widget_get_allocation (widget, &allocation);
2508           invalid_rect.x = column_offset;
2509           invalid_rect.y = 0;
2510           invalid_rect.width = gtk_tree_view_column_get_width (column);
2511           invalid_rect.height = allocation.height;
2512
2513           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2514           break;
2515         }
2516
2517       column_offset += gtk_tree_view_column_get_width (tmpcolumn);
2518     }
2519 }
2520
2521 static void
2522 invalidate_last_column (GtkTreeView *tree_view)
2523 {
2524   GList *last_column;
2525   gboolean rtl;
2526
2527   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2528
2529   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2530        last_column;
2531        last_column = (rtl ? last_column->next : last_column->prev))
2532     {
2533       if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)))
2534         {
2535           invalidate_column (tree_view, last_column->data);
2536           return;
2537         }
2538     }
2539 }
2540
2541 /* GtkWidget::size_allocate helper */
2542 static void
2543 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2544                                      gboolean  *width_changed)
2545 {
2546   GtkTreeView *tree_view;
2547   GList *list, *first_column, *last_column;
2548   GtkTreeViewColumn *column;
2549   GtkAllocation widget_allocation;
2550   gint width = 0;
2551   gint extra, extra_per_column, extra_for_last;
2552   gint full_requested_width = 0;
2553   gint number_of_expand_columns = 0;
2554   gboolean column_changed = FALSE;
2555   gboolean rtl;
2556   gboolean update_expand;
2557   
2558   tree_view = GTK_TREE_VIEW (widget);
2559
2560   for (last_column = g_list_last (tree_view->priv->columns);
2561        last_column &&
2562        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2563        last_column = last_column->prev)
2564     ;
2565   if (last_column == NULL)
2566     return;
2567
2568   for (first_column = g_list_first (tree_view->priv->columns);
2569        first_column &&
2570        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2571        first_column = first_column->next)
2572     ;
2573
2574   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2575
2576   /* find out how many extra space and expandable columns we have */
2577   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2578     {
2579       column = (GtkTreeViewColumn *)list->data;
2580
2581       if (!gtk_tree_view_column_get_visible (column))
2582         continue;
2583
2584       full_requested_width += _gtk_tree_view_column_request_width (column);
2585
2586       if (gtk_tree_view_column_get_expand (column))
2587         number_of_expand_columns++;
2588     }
2589
2590   /* Only update the expand value if the width of the widget has changed,
2591    * or the number of expand columns has changed, or if there are no expand
2592    * columns, or if we didn't have an size-allocation yet after the
2593    * last validated node.
2594    */
2595   update_expand = (width_changed && *width_changed == TRUE)
2596       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2597       || number_of_expand_columns == 0
2598       || tree_view->priv->post_validation_flag == TRUE;
2599
2600   tree_view->priv->post_validation_flag = FALSE;
2601
2602   gtk_widget_get_allocation (widget, &widget_allocation);
2603   if (!update_expand)
2604     {
2605       extra = tree_view->priv->last_extra_space;
2606       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2607     }
2608   else
2609     {
2610       extra = MAX (widget_allocation.width - full_requested_width, 0);
2611       extra_for_last = 0;
2612
2613       tree_view->priv->last_extra_space = extra;
2614     }
2615
2616   if (number_of_expand_columns > 0)
2617     extra_per_column = extra/number_of_expand_columns;
2618   else
2619     extra_per_column = 0;
2620
2621   if (update_expand)
2622     {
2623       tree_view->priv->last_extra_space_per_column = extra_per_column;
2624       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2625     }
2626
2627   for (list = (rtl ? last_column : first_column); 
2628        list != (rtl ? first_column->prev : last_column->next);
2629        list = (rtl ? list->prev : list->next)) 
2630     {
2631       gint old_width, column_width;
2632
2633       column = list->data;
2634       old_width = gtk_tree_view_column_get_width (column);
2635
2636       if (!gtk_tree_view_column_get_visible (column))
2637         continue;
2638
2639       /* We need to handle the dragged button specially.
2640        */
2641       if (column == tree_view->priv->drag_column)
2642         {
2643           GtkAllocation drag_allocation;
2644           GtkWidget    *button;
2645
2646           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2647
2648           drag_allocation.x = 0;
2649           drag_allocation.y = 0;
2650           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2651           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2652           gtk_widget_size_allocate (button, &drag_allocation);
2653           width += drag_allocation.width;
2654           continue;
2655         }
2656
2657       column_width = _gtk_tree_view_column_request_width (column);
2658
2659       if (gtk_tree_view_column_get_expand (column))
2660         {
2661           if (number_of_expand_columns == 1)
2662             {
2663               /* We add the remander to the last column as
2664                * */
2665               column_width += extra;
2666             }
2667           else
2668             {
2669               column_width += extra_per_column;
2670               extra -= extra_per_column;
2671               number_of_expand_columns --;
2672             }
2673         }
2674       else if (number_of_expand_columns == 0 &&
2675                list == last_column)
2676         {
2677           column_width += extra;
2678         }
2679
2680       /* In addition to expand, the last column can get even more
2681        * extra space so all available space is filled up.
2682        */
2683       if (extra_for_last > 0 && list == last_column)
2684         column_width += extra_for_last;
2685
2686       _gtk_tree_view_column_allocate (column, width, column_width);
2687
2688       width += column_width;
2689
2690       if (column_width > old_width)
2691         column_changed = TRUE;
2692     }
2693
2694   /* We change the width here.  The user might have been resizing columns,
2695    * so the total width of the tree view changes.
2696    */
2697   tree_view->priv->width = width;
2698   if (width_changed)
2699     *width_changed = TRUE;
2700
2701   if (column_changed)
2702     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2703 }
2704
2705
2706 static void
2707 gtk_tree_view_size_allocate (GtkWidget     *widget,
2708                              GtkAllocation *allocation)
2709 {
2710   GtkAllocation widget_allocation;
2711   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2712   GList *tmp_list;
2713   gboolean width_changed = FALSE;
2714   gint old_width;
2715
2716   gtk_widget_get_allocation (widget, &widget_allocation);
2717   old_width = widget_allocation.width;
2718   if (allocation->width != widget_allocation.width)
2719     width_changed = TRUE;
2720
2721   gtk_widget_set_allocation (widget, allocation);
2722
2723   tmp_list = tree_view->priv->children;
2724
2725   while (tmp_list)
2726     {
2727       GtkAllocation allocation;
2728
2729       GtkTreeViewChild *child = tmp_list->data;
2730       tmp_list = tmp_list->next;
2731
2732       /* totally ignore our child's requisition */
2733       allocation.x = child->x;
2734       allocation.y = child->y;
2735       allocation.width = child->width;
2736       allocation.height = child->height;
2737       gtk_widget_size_allocate (child->widget, &allocation);
2738     }
2739
2740   /* We size-allocate the columns first because the width of the
2741    * tree view (used in updating the adjustments below) might change.
2742    */
2743   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2744
2745   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2746   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2747                                 allocation->width);
2748   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2749                                      allocation->width * 0.9);
2750   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2751                                      allocation->width * 0.1);
2752   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2753   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2754                             MAX (tree_view->priv->hadjustment->page_size,
2755                                  tree_view->priv->width));
2756   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2757
2758   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2759     {
2760       if (allocation->width < tree_view->priv->width)
2761         {
2762           if (tree_view->priv->init_hadjust_value)
2763             {
2764               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2765                                         MAX (tree_view->priv->width -
2766                                              allocation->width, 0));
2767               tree_view->priv->init_hadjust_value = FALSE;
2768             }
2769           else if (allocation->width != old_width)
2770             {
2771               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2772                                         CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width,
2773                                                0,
2774                                                tree_view->priv->width - allocation->width));
2775             }
2776           else
2777             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2778                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value),
2779                                              0,
2780                                              tree_view->priv->width - allocation->width));
2781         }
2782       else
2783         {
2784           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2785           tree_view->priv->init_hadjust_value = TRUE;
2786         }
2787     }
2788   else
2789     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2790       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2791                                 MAX (tree_view->priv->width -
2792                                      allocation->width, 0));
2793
2794   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2795   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2796                                 allocation->height -
2797                                 gtk_tree_view_get_effective_header_height (tree_view));
2798   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2799                                      tree_view->priv->vadjustment->page_size * 0.1);
2800   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2801                                      tree_view->priv->vadjustment->page_size * 0.9);
2802   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2803   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2804                             MAX (tree_view->priv->vadjustment->page_size,
2805                                  tree_view->priv->height));
2806   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2807
2808   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2809   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2810     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2811   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2812     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2813                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2814   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2815     gtk_tree_view_top_row_to_dy (tree_view);
2816   else
2817     gtk_tree_view_dy_to_top_row (tree_view);
2818   
2819   if (gtk_widget_get_realized (widget))
2820     {
2821       gdk_window_move_resize (gtk_widget_get_window (widget),
2822                               allocation->x, allocation->y,
2823                               allocation->width, allocation->height);
2824       gdk_window_move_resize (tree_view->priv->header_window,
2825                               - (gint) tree_view->priv->hadjustment->value,
2826                               0,
2827                               MAX (tree_view->priv->width, allocation->width),
2828                               tree_view->priv->header_height);
2829       gdk_window_move_resize (tree_view->priv->bin_window,
2830                               - (gint) tree_view->priv->hadjustment->value,
2831                               gtk_tree_view_get_effective_header_height (tree_view),
2832                               MAX (tree_view->priv->width, allocation->width),
2833                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2834     }
2835
2836   if (tree_view->priv->tree == NULL)
2837     invalidate_empty_focus (tree_view);
2838
2839   if (gtk_widget_get_realized (widget))
2840     {
2841       gboolean has_expand_column = FALSE;
2842       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2843         {
2844           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2845             {
2846               has_expand_column = TRUE;
2847               break;
2848             }
2849         }
2850
2851       if (width_changed && tree_view->priv->expander_column)
2852         {
2853           /* Might seem awkward, but is the best heuristic I could come up
2854            * with.  Only if the width of the columns before the expander
2855            * changes, we will update the prelight status.  It is this
2856            * width that makes the expander move vertically.  Always updating
2857            * prelight status causes trouble with hover selections.
2858            */
2859           gint width_before_expander;
2860
2861           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2862
2863           if (tree_view->priv->prev_width_before_expander
2864               != width_before_expander)
2865               update_prelight (tree_view,
2866                                tree_view->priv->event_last_x,
2867                                tree_view->priv->event_last_y);
2868
2869           tree_view->priv->prev_width_before_expander = width_before_expander;
2870         }
2871
2872       /* This little hack only works if we have an LTR locale, and no column has the  */
2873       if (width_changed)
2874         {
2875           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2876               ! has_expand_column)
2877             invalidate_last_column (tree_view);
2878           else
2879             gtk_widget_queue_draw (widget);
2880         }
2881     }
2882 }
2883
2884 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2885 static void
2886 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2887 {
2888   GtkWidget *widget = GTK_WIDGET (tree_view);
2889
2890   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2891     gtk_widget_grab_focus (widget);
2892   tree_view->priv->draw_keyfocus = 0;
2893 }
2894
2895 static inline gboolean
2896 row_is_separator (GtkTreeView *tree_view,
2897                   GtkTreeIter *iter,
2898                   GtkTreePath *path)
2899 {
2900   gboolean is_separator = FALSE;
2901
2902   if (tree_view->priv->row_separator_func)
2903     {
2904       GtkTreeIter tmpiter;
2905
2906       if (iter)
2907         tmpiter = *iter;
2908       else
2909         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2910
2911       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2912                                                           &tmpiter,
2913                                                           tree_view->priv->row_separator_data);
2914     }
2915
2916   return is_separator;
2917 }
2918
2919 static gboolean
2920 gtk_tree_view_button_press (GtkWidget      *widget,
2921                             GdkEventButton *event)
2922 {
2923   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2924   GList *list;
2925   GtkTreeViewColumn *column = NULL;
2926   gint i;
2927   GdkRectangle background_area;
2928   GdkRectangle cell_area;
2929   gint vertical_separator;
2930   gint horizontal_separator;
2931   gboolean path_is_selectable;
2932   gboolean rtl;
2933
2934   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2935   gtk_tree_view_stop_editing (tree_view, FALSE);
2936   gtk_widget_style_get (widget,
2937                         "vertical-separator", &vertical_separator,
2938                         "horizontal-separator", &horizontal_separator,
2939                         NULL);
2940
2941
2942   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2943    * we're done handling the button press.
2944    */
2945
2946   if (event->window == tree_view->priv->bin_window)
2947     {
2948       GtkRBNode *node;
2949       GtkRBTree *tree;
2950       GtkTreePath *path;
2951       gint depth;
2952       gint new_y;
2953       gint y_offset;
2954       gint dval;
2955       gint pre_val, aft_val;
2956       GtkTreeViewColumn *column = NULL;
2957       gint column_handled_click = FALSE;
2958       gboolean row_double_click = FALSE;
2959       gboolean rtl;
2960       gboolean node_selected;
2961
2962       /* Empty tree? */
2963       if (tree_view->priv->tree == NULL)
2964         {
2965           grab_focus_and_unset_draw_keyfocus (tree_view);
2966           return TRUE;
2967         }
2968
2969       /* are we in an arrow? */
2970       if (tree_view->priv->prelight_node &&
2971           tree_view->priv->arrow_prelit &&
2972           gtk_tree_view_draw_expanders (tree_view))
2973         {
2974           if (event->button == 1)
2975             {
2976               gtk_grab_add (widget);
2977               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2978               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2979               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2980                                               tree_view->priv->prelight_tree,
2981                                               tree_view->priv->prelight_node);
2982             }
2983
2984           grab_focus_and_unset_draw_keyfocus (tree_view);
2985           return TRUE;
2986         }
2987
2988       /* find the node that was clicked */
2989       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2990       if (new_y < 0)
2991         new_y = 0;
2992       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2993
2994       if (node == NULL)
2995         {
2996           /* We clicked in dead space */
2997           grab_focus_and_unset_draw_keyfocus (tree_view);
2998           return TRUE;
2999         }
3000
3001       /* Get the path and the node */
3002       path = _gtk_tree_view_find_path (tree_view, tree, node);
3003       path_is_selectable = !row_is_separator (tree_view, NULL, path);
3004
3005       if (!path_is_selectable)
3006         {
3007           gtk_tree_path_free (path);
3008           grab_focus_and_unset_draw_keyfocus (tree_view);
3009           return TRUE;
3010         }
3011
3012       depth = gtk_tree_path_get_depth (path);
3013       background_area.y = y_offset + event->y;
3014       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
3015       background_area.x = 0;
3016
3017
3018       /* Let the column have a chance at selecting it. */
3019       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
3020       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
3021            list; list = (rtl ? list->prev : list->next))
3022         {
3023           GtkTreeViewColumn *candidate = list->data;
3024
3025           if (!gtk_tree_view_column_get_visible (candidate))
3026             continue;
3027
3028           background_area.width = gtk_tree_view_column_get_width (candidate);
3029           if ((background_area.x > (gint) event->x) ||
3030               (background_area.x + background_area.width <= (gint) event->x))
3031             {
3032               background_area.x += background_area.width;
3033               continue;
3034             }
3035
3036           /* we found the focus column */
3037           column = candidate;
3038           cell_area = background_area;
3039           cell_area.width -= horizontal_separator;
3040           cell_area.height -= vertical_separator;
3041           cell_area.x += horizontal_separator/2;
3042           cell_area.y += vertical_separator/2;
3043           if (gtk_tree_view_is_expander_column (tree_view, column))
3044             {
3045               if (!rtl)
3046                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
3047               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
3048
3049               if (gtk_tree_view_draw_expanders (tree_view))
3050                 {
3051                   if (!rtl)
3052                     cell_area.x += depth * tree_view->priv->expander_size;
3053                   cell_area.width -= depth * tree_view->priv->expander_size;
3054                 }
3055             }
3056           break;
3057         }
3058
3059       if (column == NULL)
3060         {
3061           gtk_tree_path_free (path);
3062           grab_focus_and_unset_draw_keyfocus (tree_view);
3063           return FALSE;
3064         }
3065
3066       tree_view->priv->focus_column = column;
3067
3068       /* decide if we edit */
3069       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
3070           !(event->state & gtk_accelerator_get_default_mod_mask ()))
3071         {
3072           GtkTreePath *anchor;
3073           GtkTreeIter iter;
3074
3075           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3076           gtk_tree_view_column_cell_set_cell_data (column,
3077                                                    tree_view->priv->model,
3078                                                    &iter,
3079                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3080                                                    node->children?TRUE:FALSE);
3081
3082           if (tree_view->priv->anchor)
3083             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3084           else
3085             anchor = NULL;
3086
3087           if ((anchor && !gtk_tree_path_compare (anchor, path))
3088               || !_gtk_tree_view_column_has_editable_cell (column))
3089             {
3090               GtkCellEditable *cell_editable = NULL;
3091
3092               /* FIXME: get the right flags */
3093               guint flags = 0;
3094
3095               if (_gtk_tree_view_column_cell_event (column,
3096                                                     (GdkEvent *)event,
3097                                                     &cell_area, flags))
3098                 {
3099                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3100                   cell_editable = gtk_cell_area_get_edit_widget (area);
3101
3102                   if (cell_editable != NULL)
3103                     {
3104                       gtk_tree_path_free (path);
3105                       gtk_tree_path_free (anchor);
3106                       return TRUE;
3107                     }
3108                   column_handled_click = TRUE;
3109                 }
3110             }
3111           if (anchor)
3112             gtk_tree_path_free (anchor);
3113         }
3114
3115       /* select */
3116       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3117       pre_val = tree_view->priv->vadjustment->value;
3118
3119       /* we only handle selection modifications on the first button press
3120        */
3121       if (event->type == GDK_BUTTON_PRESS)
3122         {
3123           GtkCellRenderer *focus_cell;
3124
3125           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3126             tree_view->priv->ctrl_pressed = TRUE;
3127           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3128             tree_view->priv->shift_pressed = TRUE;
3129
3130
3131           /* This needs an x and a y ! */
3132           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
3133
3134           if (focus_cell)
3135             gtk_tree_view_column_focus_cell (column, focus_cell);
3136
3137           if (event->state & GDK_CONTROL_MASK)
3138             {
3139               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3140               gtk_tree_view_real_toggle_cursor_row (tree_view);
3141             }
3142           else if (event->state & GDK_SHIFT_MASK)
3143             {
3144               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3145               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3146             }
3147           else
3148             {
3149               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
3150             }
3151
3152           tree_view->priv->ctrl_pressed = FALSE;
3153           tree_view->priv->shift_pressed = FALSE;
3154         }
3155
3156       /* the treeview may have been scrolled because of _set_cursor,
3157        * correct here
3158        */
3159
3160       aft_val = tree_view->priv->vadjustment->value;
3161       dval = pre_val - aft_val;
3162
3163       cell_area.y += dval;
3164       background_area.y += dval;
3165
3166       /* Save press to possibly begin a drag
3167        */
3168       if (!column_handled_click &&
3169           !tree_view->priv->in_grab &&
3170           tree_view->priv->pressed_button < 0)
3171         {
3172           tree_view->priv->pressed_button = event->button;
3173           tree_view->priv->press_start_x = event->x;
3174           tree_view->priv->press_start_y = event->y;
3175
3176           if (tree_view->priv->rubber_banding_enable
3177               && !node_selected
3178               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
3179             {
3180               tree_view->priv->press_start_y += tree_view->priv->dy;
3181               tree_view->priv->rubber_band_x = event->x;
3182               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3183               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3184
3185               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3186                 tree_view->priv->rubber_band_ctrl = TRUE;
3187               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3188                 tree_view->priv->rubber_band_shift = TRUE;
3189             }
3190         }
3191
3192       /* Test if a double click happened on the same row. */
3193       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
3194         {
3195           int double_click_time, double_click_distance;
3196
3197           g_object_get (gtk_settings_get_default (),
3198                         "gtk-double-click-time", &double_click_time,
3199                         "gtk-double-click-distance", &double_click_distance,
3200                         NULL);
3201
3202           /* Same conditions as _gdk_event_button_generate */
3203           if (tree_view->priv->last_button_x != -1 &&
3204               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3205               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3206               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3207             {
3208               /* We do no longer compare paths of this row and the
3209                * row clicked previously.  We use the double click
3210                * distance to decide whether this is a valid click,
3211                * allowing the mouse to slightly move over another row.
3212                */
3213               row_double_click = TRUE;
3214
3215               tree_view->priv->last_button_time = 0;
3216               tree_view->priv->last_button_x = -1;
3217               tree_view->priv->last_button_y = -1;
3218             }
3219           else
3220             {
3221               tree_view->priv->last_button_time = event->time;
3222               tree_view->priv->last_button_x = event->x;
3223               tree_view->priv->last_button_y = event->y;
3224             }
3225         }
3226
3227       if (row_double_click)
3228         {
3229           gtk_grab_remove (widget);
3230           gtk_tree_view_row_activated (tree_view, path, column);
3231
3232           if (tree_view->priv->pressed_button == event->button)
3233             tree_view->priv->pressed_button = -1;
3234         }
3235
3236       gtk_tree_path_free (path);
3237
3238       /* If we activated the row through a double click we don't want to grab
3239        * focus back, as moving focus to another widget is pretty common.
3240        */
3241       if (!row_double_click)
3242         grab_focus_and_unset_draw_keyfocus (tree_view);
3243
3244       return TRUE;
3245     }
3246
3247   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3248    */
3249   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3250     {
3251       column = list->data;
3252       if (event->window == _gtk_tree_view_column_get_window (column) &&
3253           gtk_tree_view_column_get_resizable (column) &&
3254           _gtk_tree_view_column_get_window (column))
3255         {
3256           GtkWidget *button;
3257           GtkAllocation button_allocation;
3258           gpointer drag_data;
3259
3260           if (event->type == GDK_2BUTTON_PRESS &&
3261               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3262             {
3263               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3264               _gtk_tree_view_column_autosize (tree_view, column);
3265               return TRUE;
3266             }
3267
3268           if (gdk_pointer_grab (_gtk_tree_view_column_get_window (column), FALSE,
3269                                 GDK_POINTER_MOTION_HINT_MASK |
3270                                 GDK_BUTTON1_MOTION_MASK |
3271                                 GDK_BUTTON_RELEASE_MASK,
3272                                 NULL, NULL, event->time))
3273             return FALSE;
3274
3275           gtk_grab_add (widget);
3276           tree_view->priv->in_column_resize = TRUE;
3277
3278           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3279                                                    tree_view->priv->last_extra_space_per_column);
3280
3281           /* block attached dnd signal handler */
3282           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3283           if (drag_data)
3284             g_signal_handlers_block_matched (widget,
3285                                              G_SIGNAL_MATCH_DATA,
3286                                              0, 0, NULL, NULL,
3287                                              drag_data);
3288
3289           button = gtk_tree_view_column_get_button (column);
3290           gtk_widget_get_allocation (button, &button_allocation);
3291           tree_view->priv->drag_pos = i;
3292           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
3293
3294           if (!gtk_widget_has_focus (widget))
3295             gtk_widget_grab_focus (widget);
3296
3297           return TRUE;
3298         }
3299     }
3300   return FALSE;
3301 }
3302
3303 /* GtkWidget::button_release_event helper */
3304 static gboolean
3305 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3306                                           GdkEventButton *event)
3307 {
3308   GtkTreeView *tree_view;
3309   GtkWidget *button;
3310   GList *l;
3311   gboolean rtl;
3312
3313   tree_view = GTK_TREE_VIEW (widget);
3314
3315   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3316   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
3317   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
3318
3319   /* Move the button back */
3320   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3321   g_object_ref (button);
3322   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3323   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3324   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3325   g_object_unref (button);
3326   gtk_widget_queue_resize (widget);
3327   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3328     {
3329       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3330       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3331     }
3332   else
3333     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3334
3335   gtk_widget_grab_focus (button);
3336
3337   if (rtl)
3338     {
3339       if (tree_view->priv->cur_reorder &&
3340           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3341         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3342                                          tree_view->priv->cur_reorder->right_column);
3343     }
3344   else
3345     {
3346       if (tree_view->priv->cur_reorder &&
3347           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3348         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3349                                          tree_view->priv->cur_reorder->left_column);
3350     }
3351   tree_view->priv->drag_column = NULL;
3352   gdk_window_hide (tree_view->priv->drag_window);
3353
3354   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3355     g_slice_free (GtkTreeViewColumnReorder, l->data);
3356   g_list_free (tree_view->priv->column_drag_info);
3357   tree_view->priv->column_drag_info = NULL;
3358   tree_view->priv->cur_reorder = NULL;
3359
3360   if (tree_view->priv->drag_highlight_window)
3361     gdk_window_hide (tree_view->priv->drag_highlight_window);
3362
3363   /* Reset our flags */
3364   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3365   tree_view->priv->in_column_drag = FALSE;
3366
3367   return TRUE;
3368 }
3369
3370 /* GtkWidget::button_release_event helper */
3371 static gboolean
3372 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3373                                             GdkEventButton *event)
3374 {
3375   GtkTreeView *tree_view;
3376   gpointer drag_data;
3377
3378   tree_view = GTK_TREE_VIEW (widget);
3379
3380   tree_view->priv->drag_pos = -1;
3381
3382   /* unblock attached dnd signal handler */
3383   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3384   if (drag_data)
3385     g_signal_handlers_unblock_matched (widget,
3386                                        G_SIGNAL_MATCH_DATA,
3387                                        0, 0, NULL, NULL,
3388                                        drag_data);
3389
3390   tree_view->priv->in_column_resize = FALSE;
3391   gtk_grab_remove (widget);
3392   gdk_display_pointer_ungrab (gdk_window_get_display (event->window),
3393                               event->time);
3394   return TRUE;
3395 }
3396
3397 static gboolean
3398 gtk_tree_view_button_release (GtkWidget      *widget,
3399                               GdkEventButton *event)
3400 {
3401   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3402
3403   if (tree_view->priv->in_column_drag)
3404     return gtk_tree_view_button_release_drag_column (widget, event);
3405
3406   if (tree_view->priv->rubber_band_status)
3407     gtk_tree_view_stop_rubber_band (tree_view);
3408
3409   if (tree_view->priv->pressed_button == event->button)
3410     tree_view->priv->pressed_button = -1;
3411
3412   if (tree_view->priv->in_column_resize)
3413     return gtk_tree_view_button_release_column_resize (widget, event);
3414
3415   if (tree_view->priv->button_pressed_node == NULL)
3416     return FALSE;
3417
3418   if (event->button == 1)
3419     {
3420       gtk_grab_remove (widget);
3421       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3422           tree_view->priv->arrow_prelit)
3423         {
3424           GtkTreePath *path = NULL;
3425
3426           path = _gtk_tree_view_find_path (tree_view,
3427                                            tree_view->priv->button_pressed_tree,
3428                                            tree_view->priv->button_pressed_node);
3429           /* Actually activate the node */
3430           if (tree_view->priv->button_pressed_node->children == NULL)
3431             gtk_tree_view_real_expand_row (tree_view, path,
3432                                            tree_view->priv->button_pressed_tree,
3433                                            tree_view->priv->button_pressed_node,
3434                                            FALSE, TRUE);
3435           else
3436             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3437                                              tree_view->priv->button_pressed_tree,
3438                                              tree_view->priv->button_pressed_node, TRUE);
3439           gtk_tree_path_free (path);
3440         }
3441
3442       tree_view->priv->button_pressed_tree = NULL;
3443       tree_view->priv->button_pressed_node = NULL;
3444     }
3445
3446   return TRUE;
3447 }
3448
3449 static gboolean
3450 gtk_tree_view_grab_broken (GtkWidget          *widget,
3451                            GdkEventGrabBroken *event)
3452 {
3453   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3454
3455   if (tree_view->priv->in_column_drag)
3456     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3457
3458   if (tree_view->priv->in_column_resize)
3459     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3460
3461   return TRUE;
3462 }
3463
3464 #if 0
3465 static gboolean
3466 gtk_tree_view_configure (GtkWidget *widget,
3467                          GdkEventConfigure *event)
3468 {
3469   GtkTreeView *tree_view;
3470
3471   tree_view = GTK_TREE_VIEW (widget);
3472   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3473
3474   return FALSE;
3475 }
3476 #endif
3477
3478 /* GtkWidget::motion_event function set.
3479  */
3480
3481 static gboolean
3482 coords_are_over_arrow (GtkTreeView *tree_view,
3483                        GtkRBTree   *tree,
3484                        GtkRBNode   *node,
3485                        /* these are in bin window coords */
3486                        gint         x,
3487                        gint         y)
3488 {
3489   GdkRectangle arrow;
3490   gint x2;
3491
3492   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3493     return FALSE;
3494
3495   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3496     return FALSE;
3497
3498   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3499   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3500
3501   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3502
3503   arrow.width = x2 - arrow.x;
3504
3505   return (x >= arrow.x &&
3506           x < (arrow.x + arrow.width) &&
3507           y >= arrow.y &&
3508           y < (arrow.y + arrow.height));
3509 }
3510
3511 static gboolean
3512 auto_expand_timeout (gpointer data)
3513 {
3514   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3515   GtkTreePath *path;
3516
3517   if (tree_view->priv->prelight_node)
3518     {
3519       path = _gtk_tree_view_find_path (tree_view,
3520                                        tree_view->priv->prelight_tree,
3521                                        tree_view->priv->prelight_node);   
3522
3523       if (tree_view->priv->prelight_node->children)
3524         gtk_tree_view_collapse_row (tree_view, path);
3525       else
3526         gtk_tree_view_expand_row (tree_view, path, FALSE);
3527
3528       gtk_tree_path_free (path);
3529     }
3530
3531   tree_view->priv->auto_expand_timeout = 0;
3532
3533   return FALSE;
3534 }
3535
3536 static void
3537 remove_auto_expand_timeout (GtkTreeView *tree_view)
3538 {
3539   if (tree_view->priv->auto_expand_timeout != 0)
3540     {
3541       g_source_remove (tree_view->priv->auto_expand_timeout);
3542       tree_view->priv->auto_expand_timeout = 0;
3543     }
3544 }
3545
3546 static void
3547 do_prelight (GtkTreeView *tree_view,
3548              GtkRBTree   *tree,
3549              GtkRBNode   *node,
3550              /* these are in bin_window coords */
3551              gint         x,
3552              gint         y)
3553 {
3554   if (tree_view->priv->prelight_tree == tree &&
3555       tree_view->priv->prelight_node == node)
3556     {
3557       /*  We are still on the same node,
3558           but we might need to take care of the arrow  */
3559
3560       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3561         {
3562           gboolean over_arrow;
3563
3564           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3565
3566           if (over_arrow != tree_view->priv->arrow_prelit)
3567             {
3568               if (over_arrow)
3569                 tree_view->priv->arrow_prelit = TRUE;
3570               else
3571                 tree_view->priv->arrow_prelit = FALSE;
3572
3573               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3574             }
3575         }
3576
3577       return;
3578     }
3579
3580   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3581     {
3582       /*  Unprelight the old node and arrow  */
3583
3584       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3585                              GTK_RBNODE_IS_PRELIT);
3586
3587       if (tree_view->priv->arrow_prelit
3588           && gtk_tree_view_draw_expanders (tree_view))
3589         {
3590           tree_view->priv->arrow_prelit = FALSE;
3591           
3592           gtk_tree_view_queue_draw_arrow (tree_view,
3593                                           tree_view->priv->prelight_tree,
3594                                           tree_view->priv->prelight_node);
3595         }
3596
3597       _gtk_tree_view_queue_draw_node (tree_view,
3598                                       tree_view->priv->prelight_tree,
3599                                       tree_view->priv->prelight_node,
3600                                       NULL);
3601     }
3602
3603
3604   if (tree_view->priv->hover_expand)
3605     remove_auto_expand_timeout (tree_view);
3606
3607   /*  Set the new prelight values  */
3608   tree_view->priv->prelight_node = node;
3609   tree_view->priv->prelight_tree = tree;
3610
3611   if (!node || !tree)
3612     return;
3613
3614   /*  Prelight the new node and arrow  */
3615
3616   if (gtk_tree_view_draw_expanders (tree_view)
3617       && coords_are_over_arrow (tree_view, tree, node, x, y))
3618     {
3619       tree_view->priv->arrow_prelit = TRUE;
3620
3621       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3622     }
3623
3624   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3625
3626   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3627
3628   if (tree_view->priv->hover_expand)
3629     {
3630       tree_view->priv->auto_expand_timeout = 
3631         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3632     }
3633 }
3634
3635 static void
3636 prelight_or_select (GtkTreeView *tree_view,
3637                     GtkRBTree   *tree,
3638                     GtkRBNode   *node,
3639                     /* these are in bin_window coords */
3640                     gint         x,
3641                     gint         y)
3642 {
3643   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3644   
3645   if (tree_view->priv->hover_selection &&
3646       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3647       !(tree_view->priv->edited_column &&
3648         gtk_cell_area_get_edit_widget 
3649         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3650     {
3651       if (node)
3652         {
3653           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3654             {
3655               GtkTreePath *path;
3656               
3657               path = _gtk_tree_view_find_path (tree_view, tree, node);
3658               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3659               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3660                 {
3661                   tree_view->priv->draw_keyfocus = FALSE;
3662                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3663                 }
3664               gtk_tree_path_free (path);
3665             }
3666         }
3667
3668       else if (mode == GTK_SELECTION_SINGLE)
3669         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3670     }
3671
3672     do_prelight (tree_view, tree, node, x, y);
3673 }
3674
3675 static void
3676 ensure_unprelighted (GtkTreeView *tree_view)
3677 {
3678   do_prelight (tree_view,
3679                NULL, NULL,
3680                -1000, -1000); /* coords not possibly over an arrow */
3681
3682   g_assert (tree_view->priv->prelight_node == NULL);
3683 }
3684
3685 static void
3686 update_prelight (GtkTreeView *tree_view,
3687                  gint         x,
3688                  gint         y)
3689 {
3690   int new_y;
3691   GtkRBTree *tree;
3692   GtkRBNode *node;
3693
3694   if (tree_view->priv->tree == NULL)
3695     return;
3696
3697   if (x == -10000)
3698     {
3699       ensure_unprelighted (tree_view);
3700       return;
3701     }
3702
3703   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3704   if (new_y < 0)
3705     new_y = 0;
3706
3707   _gtk_rbtree_find_offset (tree_view->priv->tree,
3708                            new_y, &tree, &node);
3709
3710   if (node)
3711     prelight_or_select (tree_view, tree, node, x, y);
3712 }
3713
3714
3715
3716
3717 /* Our motion arrow is either a box (in the case of the original spot)
3718  * or an arrow.  It is expander_size wide.
3719  */
3720 /*
3721  * 11111111111111
3722  * 01111111111110
3723  * 00111111111100
3724  * 00011111111000
3725  * 00001111110000
3726  * 00000111100000
3727  * 00000111100000
3728  * 00000111100000
3729  * ~ ~ ~ ~ ~ ~ ~
3730  * 00000111100000
3731  * 00000111100000
3732  * 00000111100000
3733  * 00001111110000
3734  * 00011111111000
3735  * 00111111111100
3736  * 01111111111110
3737  * 11111111111111
3738  */
3739
3740 static void
3741 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3742 {
3743   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3744   GtkWidget *widget = GTK_WIDGET (tree_view);
3745   cairo_surface_t *mask_image;
3746   cairo_region_t *mask_region;
3747   gint x;
3748   gint y;
3749   gint width;
3750   gint height;
3751   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3752   GdkWindowAttr attributes;
3753   guint attributes_mask;
3754   cairo_t *cr;
3755
3756   if (!reorder ||
3757       reorder->left_column == tree_view->priv->drag_column ||
3758       reorder->right_column == tree_view->priv->drag_column)
3759     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3760   else if (reorder->left_column || reorder->right_column)
3761     {
3762       GtkAllocation left_allocation, right_allocation;
3763       GdkRectangle visible_rect;
3764       GtkWidget *button;
3765
3766       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3767       if (reorder->left_column)
3768         {
3769           button = gtk_tree_view_column_get_button (reorder->left_column);
3770           gtk_widget_get_allocation (button, &left_allocation);
3771           x = left_allocation.x + left_allocation.width;
3772         }
3773       else
3774         {
3775           button = gtk_tree_view_column_get_button (reorder->right_column);
3776           gtk_widget_get_allocation (button, &right_allocation);
3777           x = right_allocation.x;
3778         }
3779
3780       if (x < visible_rect.x)
3781         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3782       else if (x > visible_rect.x + visible_rect.width)
3783         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3784       else
3785         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3786     }
3787
3788   /* We want to draw the rectangle over the initial location. */
3789   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3790     {
3791       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3792         {
3793           GtkAllocation drag_allocation;
3794           GtkWidget    *button;
3795
3796           if (tree_view->priv->drag_highlight_window)
3797             {
3798               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3799                                         NULL);
3800               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3801             }
3802
3803           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3804           attributes.window_type = GDK_WINDOW_CHILD;
3805           attributes.wclass = GDK_INPUT_OUTPUT;
3806           attributes.x = tree_view->priv->drag_column_x;
3807           attributes.y = 0;
3808           gtk_widget_get_allocation (button, &drag_allocation);
3809           width = attributes.width = drag_allocation.width;
3810           height = attributes.height = drag_allocation.height;
3811           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3812           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3813           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3814           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &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           cr = cairo_create (mask_image);
3819
3820           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3821           cairo_stroke (cr);
3822           cairo_destroy (cr);
3823
3824           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3825           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3826                                            mask_region, 0, 0);
3827
3828           cairo_region_destroy (mask_region);
3829           cairo_surface_destroy (mask_image);
3830
3831           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3832         }
3833     }
3834   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3835     {
3836       GtkAllocation button_allocation;
3837       GtkWidget    *button;
3838
3839       width = tree_view->priv->expander_size;
3840
3841       /* Get x, y, width, height of arrow */
3842       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3843       if (reorder->left_column)
3844         {
3845           button = gtk_tree_view_column_get_button (reorder->left_column);
3846           gtk_widget_get_allocation (button, &button_allocation);
3847           x += button_allocation.x + button_allocation.width - width/2;
3848           height = button_allocation.height;
3849         }
3850       else
3851         {
3852           button = gtk_tree_view_column_get_button (reorder->right_column);
3853           gtk_widget_get_allocation (button, &button_allocation);
3854           x += button_allocation.x - width/2;
3855           height = button_allocation.height;
3856         }
3857       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3858       height += tree_view->priv->expander_size;
3859
3860       /* Create the new window */
3861       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3862         {
3863           if (tree_view->priv->drag_highlight_window)
3864             {
3865               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3866                                         NULL);
3867               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3868             }
3869
3870           attributes.window_type = GDK_WINDOW_TEMP;
3871           attributes.wclass = GDK_INPUT_OUTPUT;
3872           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3873           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3874           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3875           attributes.x = x;
3876           attributes.y = y;
3877           attributes.width = width;
3878           attributes.height = height;
3879           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3880                                                                    &attributes, attributes_mask);
3881           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3882
3883           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3884
3885           cr = cairo_create (mask_image);
3886           cairo_move_to (cr, 0, 0);
3887           cairo_line_to (cr, width, 0);
3888           cairo_line_to (cr, width / 2., width / 2);
3889           cairo_move_to (cr, 0, height);
3890           cairo_line_to (cr, width, height);
3891           cairo_line_to (cr, width / 2., height - width / 2.);
3892           cairo_fill (cr);
3893           cairo_destroy (cr);
3894
3895           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3896           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3897                                            mask_region, 0, 0);
3898
3899           cairo_region_destroy (mask_region);
3900           cairo_surface_destroy (mask_image);
3901         }
3902
3903       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3904       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3905     }
3906   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3907            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3908     {
3909       GtkAllocation allocation;
3910       GtkWidget    *button;
3911
3912       width = tree_view->priv->expander_size;
3913
3914       /* Get x, y, width, height of arrow */
3915       width = width/2; /* remember, the arrow only takes half the available width */
3916       gdk_window_get_origin (gtk_widget_get_window (widget),
3917                              &x, &y);
3918       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3919         {
3920           gtk_widget_get_allocation (widget, &allocation);
3921           x += allocation.width - width;
3922         }
3923
3924       if (reorder->left_column)
3925         {
3926           button = gtk_tree_view_column_get_button (reorder->left_column);
3927           gtk_widget_get_allocation (button, &allocation);
3928           height = allocation.height;
3929         }
3930       else
3931         {
3932           button = gtk_tree_view_column_get_button (reorder->right_column);
3933           gtk_widget_get_allocation (button, &allocation);
3934           height = allocation.height;
3935         }
3936
3937       y -= tree_view->priv->expander_size;
3938       height += 2*tree_view->priv->expander_size;
3939
3940       /* Create the new window */
3941       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3942           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3943         {
3944           if (tree_view->priv->drag_highlight_window)
3945             {
3946               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3947                                         NULL);
3948               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3949             }
3950
3951           attributes.window_type = GDK_WINDOW_TEMP;
3952           attributes.wclass = GDK_INPUT_OUTPUT;
3953           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3954           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3955           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3956           attributes.x = x;
3957           attributes.y = y;
3958           attributes.width = width;
3959           attributes.height = height;
3960           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3961           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3962
3963           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3964
3965           cr = cairo_create (mask_image);
3966           /* mirror if we're on the left */
3967           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3968             {
3969               cairo_translate (cr, width, 0);
3970               cairo_scale (cr, -1, 1);
3971             }
3972           cairo_move_to (cr, 0, 0);
3973           cairo_line_to (cr, width, width);
3974           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3975           cairo_move_to (cr, 0, height);
3976           cairo_line_to (cr, width, height - width);
3977           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3978           cairo_fill (cr);
3979           cairo_destroy (cr);
3980
3981           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3982           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3983                                            mask_region, 0, 0);
3984
3985           cairo_region_destroy (mask_region);
3986           cairo_surface_destroy (mask_image);
3987         }
3988
3989       tree_view->priv->drag_column_window_state = arrow_type;
3990       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3991    }
3992   else
3993     {
3994       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3995       gdk_window_hide (tree_view->priv->drag_highlight_window);
3996       return;
3997     }
3998
3999   gdk_window_show (tree_view->priv->drag_highlight_window);
4000   gdk_window_raise (tree_view->priv->drag_highlight_window);
4001 }
4002
4003 static gboolean
4004 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
4005                                     GdkEventMotion *event)
4006 {
4007   gint x;
4008   gint new_width;
4009   GtkTreeViewColumn *column;
4010   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4011
4012   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
4013
4014   if (event->is_hint || event->window != gtk_widget_get_window (widget))
4015     gtk_widget_get_pointer (widget, &x, NULL);
4016   else
4017     x = event->x;
4018
4019   if (tree_view->priv->hadjustment)
4020     x += tree_view->priv->hadjustment->value;
4021
4022   new_width = gtk_tree_view_new_column_width (tree_view,
4023                                               tree_view->priv->drag_pos, &x);
4024   if (x != tree_view->priv->x_drag &&
4025       (new_width != gtk_tree_view_column_get_fixed_width (column)))
4026     {
4027       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
4028
4029       if (gtk_tree_view_column_get_expand (column))
4030         new_width -= tree_view->priv->last_extra_space_per_column;
4031
4032       _gtk_tree_view_column_set_resized_width (column, new_width);
4033
4034
4035       gtk_widget_queue_resize (widget);
4036     }
4037
4038   return FALSE;
4039 }
4040
4041
4042 static void
4043 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
4044 {
4045   GtkTreeViewColumnReorder *reorder = NULL;
4046   GList *list;
4047   gint mouse_x;
4048
4049   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
4050   for (list = tree_view->priv->column_drag_info; list; list = list->next)
4051     {
4052       reorder = (GtkTreeViewColumnReorder *) list->data;
4053       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
4054         break;
4055       reorder = NULL;
4056     }
4057
4058   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
4059       return;*/
4060
4061   tree_view->priv->cur_reorder = reorder;
4062   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
4063 }
4064
4065 static void
4066 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4067 {
4068   GdkRectangle visible_rect;
4069   gint y;
4070   gint offset;
4071
4072   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
4073   y += tree_view->priv->dy;
4074
4075   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4076
4077   /* see if we are near the edge. */
4078   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4079   if (offset > 0)
4080     {
4081       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4082       if (offset < 0)
4083         return;
4084     }
4085
4086   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4087                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
4088 }
4089
4090 static gboolean
4091 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
4092 {
4093   GdkRectangle visible_rect;
4094   gint x;
4095   gint offset;
4096
4097   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
4098
4099   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4100
4101   /* See if we are near the edge. */
4102   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4103   if (offset > 0)
4104     {
4105       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4106       if (offset < 0)
4107         return TRUE;
4108     }
4109   offset = offset/3;
4110
4111   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4112                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
4113
4114   return TRUE;
4115
4116 }
4117
4118 static gboolean
4119 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4120                                   GdkEventMotion *event)
4121 {
4122   GtkAllocation allocation, button_allocation;
4123   GtkTreeView *tree_view = (GtkTreeView *) widget;
4124   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4125   GtkWidget *button;
4126   gint x, y;
4127
4128   /* Sanity Check */
4129   if ((column == NULL) ||
4130       (event->window != tree_view->priv->drag_window))
4131     return FALSE;
4132
4133   button = gtk_tree_view_column_get_button (column);
4134
4135   /* Handle moving the header */
4136   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4137   gtk_widget_get_allocation (widget, &allocation);
4138   gtk_widget_get_allocation (button, &button_allocation);
4139   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4140              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4141   gdk_window_move (tree_view->priv->drag_window, x, y);
4142   
4143   /* autoscroll, if needed */
4144   gtk_tree_view_horizontal_autoscroll (tree_view);
4145   /* Update the current reorder position and arrow; */
4146   gtk_tree_view_update_current_reorder (tree_view);
4147
4148   return TRUE;
4149 }
4150
4151 static void
4152 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4153 {
4154   remove_scroll_timeout (tree_view);
4155   gtk_grab_remove (GTK_WIDGET (tree_view));
4156
4157   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4158     {
4159       GtkTreePath *tmp_path;
4160
4161       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4162
4163       /* The anchor path should be set to the start path */
4164       tmp_path = _gtk_tree_view_find_path (tree_view,
4165                                            tree_view->priv->rubber_band_start_tree,
4166                                            tree_view->priv->rubber_band_start_node);
4167
4168       if (tree_view->priv->anchor)
4169         gtk_tree_row_reference_free (tree_view->priv->anchor);
4170
4171       tree_view->priv->anchor =
4172         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4173                                           tree_view->priv->model,
4174                                           tmp_path);
4175
4176       gtk_tree_path_free (tmp_path);
4177
4178       /* ... and the cursor to the end path */
4179       tmp_path = _gtk_tree_view_find_path (tree_view,
4180                                            tree_view->priv->rubber_band_end_tree,
4181                                            tree_view->priv->rubber_band_end_node);
4182       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
4183       gtk_tree_path_free (tmp_path);
4184
4185       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4186     }
4187
4188   /* Clear status variables */
4189   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4190   tree_view->priv->rubber_band_shift = 0;
4191   tree_view->priv->rubber_band_ctrl = 0;
4192
4193   tree_view->priv->rubber_band_start_node = NULL;
4194   tree_view->priv->rubber_band_start_tree = NULL;
4195   tree_view->priv->rubber_band_end_node = NULL;
4196   tree_view->priv->rubber_band_end_tree = NULL;
4197 }
4198
4199 static void
4200 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4201                                                  GtkRBTree   *start_tree,
4202                                                  GtkRBNode   *start_node,
4203                                                  GtkRBTree   *end_tree,
4204                                                  GtkRBNode   *end_node,
4205                                                  gboolean     select,
4206                                                  gboolean     skip_start,
4207                                                  gboolean     skip_end)
4208 {
4209   if (start_node == end_node)
4210     return;
4211
4212   /* We skip the first node and jump inside the loop */
4213   if (skip_start)
4214     goto skip_first;
4215
4216   do
4217     {
4218       /* Small optimization by assuming insensitive nodes are never
4219        * selected.
4220        */
4221       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4222         {
4223           GtkTreePath *path;
4224           gboolean selectable;
4225
4226           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
4227           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4228           gtk_tree_path_free (path);
4229
4230           if (!selectable)
4231             goto node_not_selectable;
4232         }
4233
4234       if (select)
4235         {
4236           if (tree_view->priv->rubber_band_shift)
4237             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4238           else if (tree_view->priv->rubber_band_ctrl)
4239             {
4240               /* Toggle the selection state */
4241               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4242                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4243               else
4244                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4245             }
4246           else
4247             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4248         }
4249       else
4250         {
4251           /* Mirror the above */
4252           if (tree_view->priv->rubber_band_shift)
4253             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4254           else if (tree_view->priv->rubber_band_ctrl)
4255             {
4256               /* Toggle the selection state */
4257               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4258                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4259               else
4260                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4261             }
4262           else
4263             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4264         }
4265
4266       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4267
4268 node_not_selectable:
4269       if (start_node == end_node)
4270         break;
4271
4272 skip_first:
4273
4274       if (start_node->children)
4275         {
4276           start_tree = start_node->children;
4277           start_node = start_tree->root;
4278           while (start_node->left != start_tree->nil)
4279             start_node = start_node->left;
4280         }
4281       else
4282         {
4283           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4284
4285           if (!start_tree)
4286             /* Ran out of tree */
4287             break;
4288         }
4289
4290       if (skip_end && start_node == end_node)
4291         break;
4292     }
4293   while (TRUE);
4294 }
4295
4296 static void
4297 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4298 {
4299   GtkRBTree *start_tree, *end_tree;
4300   GtkRBNode *start_node, *end_node;
4301
4302   _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);
4303   _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);
4304
4305   /* Handle the start area first */
4306   if (!tree_view->priv->rubber_band_start_node)
4307     {
4308       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4309                                                        start_tree,
4310                                                        start_node,
4311                                                        end_tree,
4312                                                        end_node,
4313                                                        TRUE,
4314                                                        FALSE,
4315                                                        FALSE);
4316     }
4317   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4318            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4319     {
4320       /* New node is above the old one; selection became bigger */
4321       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4322                                                        start_tree,
4323                                                        start_node,
4324                                                        tree_view->priv->rubber_band_start_tree,
4325                                                        tree_view->priv->rubber_band_start_node,
4326                                                        TRUE,
4327                                                        FALSE,
4328                                                        TRUE);
4329     }
4330   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4331            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4332     {
4333       /* New node is below the old one; selection became smaller */
4334       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4335                                                        tree_view->priv->rubber_band_start_tree,
4336                                                        tree_view->priv->rubber_band_start_node,
4337                                                        start_tree,
4338                                                        start_node,
4339                                                        FALSE,
4340                                                        FALSE,
4341                                                        TRUE);
4342     }
4343
4344   tree_view->priv->rubber_band_start_tree = start_tree;
4345   tree_view->priv->rubber_band_start_node = start_node;
4346
4347   /* Next, handle the end area */
4348   if (!tree_view->priv->rubber_band_end_node)
4349     {
4350       /* In the event this happens, start_node was also NULL; this case is
4351        * handled above.
4352        */
4353     }
4354   else if (!end_node)
4355     {
4356       /* Find the last node in the tree */
4357       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4358                                &end_tree, &end_node);
4359
4360       /* Selection reached end of the tree */
4361       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4362                                                        tree_view->priv->rubber_band_end_tree,
4363                                                        tree_view->priv->rubber_band_end_node,
4364                                                        end_tree,
4365                                                        end_node,
4366                                                        TRUE,
4367                                                        TRUE,
4368                                                        FALSE);
4369     }
4370   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4371            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4372     {
4373       /* New node is below the old one; selection became bigger */
4374       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4375                                                        tree_view->priv->rubber_band_end_tree,
4376                                                        tree_view->priv->rubber_band_end_node,
4377                                                        end_tree,
4378                                                        end_node,
4379                                                        TRUE,
4380                                                        TRUE,
4381                                                        FALSE);
4382     }
4383   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4384            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4385     {
4386       /* New node is above the old one; selection became smaller */
4387       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4388                                                        end_tree,
4389                                                        end_node,
4390                                                        tree_view->priv->rubber_band_end_tree,
4391                                                        tree_view->priv->rubber_band_end_node,
4392                                                        FALSE,
4393                                                        TRUE,
4394                                                        FALSE);
4395     }
4396
4397   tree_view->priv->rubber_band_end_tree = end_tree;
4398   tree_view->priv->rubber_band_end_node = end_node;
4399 }
4400
4401 static void
4402 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4403 {
4404   gint x, y;
4405   GdkRectangle old_area;
4406   GdkRectangle new_area;
4407   GdkRectangle common;
4408   cairo_region_t *invalid_region;
4409
4410   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4411   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4412   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4413   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4414
4415   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4416
4417   x = MAX (x, 0);
4418   y = MAX (y, 0) + tree_view->priv->dy;
4419
4420   new_area.x = MIN (tree_view->priv->press_start_x, x);
4421   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4422   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4423   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4424
4425   invalid_region = cairo_region_create_rectangle (&old_area);
4426   cairo_region_union_rectangle (invalid_region, &new_area);
4427
4428   gdk_rectangle_intersect (&old_area, &new_area, &common);
4429   if (common.width > 2 && common.height > 2)
4430     {
4431       cairo_region_t *common_region;
4432
4433       /* make sure the border is invalidated */
4434       common.x += 1;
4435       common.y += 1;
4436       common.width -= 2;
4437       common.height -= 2;
4438
4439       common_region = cairo_region_create_rectangle (&common);
4440
4441       cairo_region_subtract (invalid_region, common_region);
4442       cairo_region_destroy (common_region);
4443     }
4444
4445   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4446
4447   cairo_region_destroy (invalid_region);
4448
4449   tree_view->priv->rubber_band_x = x;
4450   tree_view->priv->rubber_band_y = y;
4451
4452   gtk_tree_view_update_rubber_band_selection (tree_view);
4453 }
4454
4455 static void
4456 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4457                                  cairo_t      *cr)
4458 {
4459   GdkRectangle rect;
4460   GtkStyle *style;
4461
4462   cairo_save (cr);
4463
4464   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4465   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4466   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4467   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4468
4469   cairo_set_line_width (cr, 1.0);
4470
4471   style = gtk_widget_get_style (GTK_WIDGET (tree_view));
4472
4473   gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
4474
4475   gdk_cairo_rectangle (cr, &rect);
4476   cairo_clip (cr);
4477   cairo_paint_with_alpha (cr, 0.25);
4478
4479   cairo_rectangle (cr,
4480                    rect.x + 0.5, rect.y + 0.5,
4481                    rect.width - 1, rect.height - 1);
4482   cairo_stroke (cr);
4483
4484   cairo_restore (cr);
4485 }
4486
4487 static gboolean
4488 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4489                                  GdkEventMotion *event)
4490 {
4491   GtkTreeView *tree_view;
4492   GtkRBTree *tree;
4493   GtkRBNode *node;
4494   gint new_y;
4495
4496   tree_view = (GtkTreeView *) widget;
4497
4498   if (tree_view->priv->tree == NULL)
4499     return FALSE;
4500
4501   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4502     {
4503       gtk_grab_add (GTK_WIDGET (tree_view));
4504       gtk_tree_view_update_rubber_band (tree_view);
4505
4506       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4507     }
4508   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4509     {
4510       gtk_tree_view_update_rubber_band (tree_view);
4511
4512       add_scroll_timeout (tree_view);
4513     }
4514
4515   /* only check for an initiated drag when a button is pressed */
4516   if (tree_view->priv->pressed_button >= 0
4517       && !tree_view->priv->rubber_band_status)
4518     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4519
4520   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4521   if (new_y < 0)
4522     new_y = 0;
4523
4524   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4525
4526   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4527   if ((tree_view->priv->button_pressed_node != NULL) &&
4528       (tree_view->priv->button_pressed_node != node))
4529     node = NULL;
4530
4531   tree_view->priv->event_last_x = event->x;
4532   tree_view->priv->event_last_y = event->y;
4533
4534   prelight_or_select (tree_view, tree, node, event->x, event->y);
4535
4536   return TRUE;
4537 }
4538
4539 static gboolean
4540 gtk_tree_view_motion (GtkWidget      *widget,
4541                       GdkEventMotion *event)
4542 {
4543   GtkTreeView *tree_view;
4544
4545   tree_view = (GtkTreeView *) widget;
4546
4547   /* Resizing a column */
4548   if (tree_view->priv->in_column_resize)
4549     return gtk_tree_view_motion_resize_column (widget, event);
4550
4551   /* Drag column */
4552   if (tree_view->priv->in_column_drag)
4553     return gtk_tree_view_motion_drag_column (widget, event);
4554
4555   /* Sanity check it */
4556   if (event->window == tree_view->priv->bin_window)
4557     return gtk_tree_view_motion_bin_window (widget, event);
4558
4559   return FALSE;
4560 }
4561
4562 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4563  * the tree is empty.
4564  */
4565 static void
4566 invalidate_empty_focus (GtkTreeView *tree_view)
4567 {
4568   GdkRectangle area;
4569
4570   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4571     return;
4572
4573   area.x = 0;
4574   area.y = 0;
4575   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4576   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4577   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4578 }
4579
4580 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4581  * is empty.
4582  */
4583 static void
4584 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4585 {
4586   GtkWidget *widget = GTK_WIDGET (tree_view);
4587   gint w, h;
4588
4589   if (!gtk_widget_has_focus (widget))
4590     return;
4591
4592   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4593   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4594
4595   if (w > 0 && h > 0)
4596     gtk_paint_focus (gtk_widget_get_style (widget),
4597                      cr,
4598                      gtk_widget_get_state (widget),
4599                      widget,
4600                      NULL,
4601                      1, 1, w, h);
4602 }
4603
4604 typedef enum {
4605   GTK_TREE_VIEW_GRID_LINE,
4606   GTK_TREE_VIEW_TREE_LINE,
4607   GTK_TREE_VIEW_FOREGROUND_LINE
4608 } GtkTreeViewLineType;
4609
4610 static void
4611 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4612                          cairo_t             *cr,
4613                          GtkTreeViewLineType  type,
4614                          int                  x1,
4615                          int                  y1,
4616                          int                  x2,
4617                          int                  y2)
4618 {
4619   cairo_save (cr);
4620
4621   switch (type)
4622     {
4623     case GTK_TREE_VIEW_TREE_LINE:
4624       cairo_set_source_rgb (cr, 0, 0, 0);
4625       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4626       if (tree_view->priv->tree_line_dashes[0])
4627         cairo_set_dash (cr, 
4628                         tree_view->priv->tree_line_dashes,
4629                         2, 0.5);
4630       break;
4631     case GTK_TREE_VIEW_GRID_LINE:
4632       cairo_set_source_rgb (cr, 0, 0, 0);
4633       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4634       if (tree_view->priv->grid_line_dashes[0])
4635         cairo_set_dash (cr, 
4636                         tree_view->priv->grid_line_dashes,
4637                         2, 0.5);
4638       break;
4639     default:
4640       g_assert_not_reached ();
4641       /* fall through */
4642     case GTK_TREE_VIEW_FOREGROUND_LINE:
4643       cairo_set_line_width (cr, 1.0);
4644       gdk_cairo_set_source_color (cr,
4645                                   &gtk_widget_get_style (GTK_WIDGET (tree_view))->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4646       break;
4647     }
4648
4649   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4650   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4651   cairo_stroke (cr);
4652
4653   cairo_restore (cr);
4654 }
4655                          
4656 static void
4657 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4658                                cairo_t        *cr,
4659                                gint            n_visible_columns)
4660 {
4661   GList *list = tree_view->priv->columns;
4662   gint i = 0;
4663   gint current_x = 0;
4664
4665   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4666       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4667     return;
4668
4669   /* Only draw the lines for visible rows and columns */
4670   for (list = tree_view->priv->columns; list; list = list->next, i++)
4671     {
4672       GtkTreeViewColumn *column = list->data;
4673
4674       /* We don't want a line for the last column */
4675       if (i == n_visible_columns - 1)
4676         break;
4677
4678       if (!gtk_tree_view_column_get_visible (column))
4679         continue;
4680
4681       current_x += gtk_tree_view_column_get_width (column);
4682
4683       gtk_tree_view_draw_line (tree_view, cr,
4684                                GTK_TREE_VIEW_GRID_LINE,
4685                                current_x - 1, 0,
4686                                current_x - 1, tree_view->priv->height);
4687     }
4688 }
4689
4690 /* Warning: Very scary function.
4691  * Modify at your own risk
4692  *
4693  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4694  * FIXME: It's not...
4695  */
4696 static gboolean
4697 gtk_tree_view_bin_draw (GtkWidget      *widget,
4698                         cairo_t        *cr)
4699 {
4700   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4701   GtkTreePath *path;
4702   GtkStyle *style;
4703   GtkRBTree *tree;
4704   GList *list;
4705   GtkRBNode *node;
4706   GtkRBNode *cursor = NULL;
4707   GtkRBTree *cursor_tree = NULL;
4708   GtkRBNode *drag_highlight = NULL;
4709   GtkRBTree *drag_highlight_tree = NULL;
4710   GtkTreeIter iter;
4711   gint new_y;
4712   gint y_offset, cell_offset;
4713   gint max_height;
4714   gint depth;
4715   GdkRectangle background_area;
4716   GdkRectangle cell_area;
4717   GdkRectangle clip;
4718   guint flags;
4719   gint highlight_x;
4720   gint expander_cell_width;
4721   gint bin_window_width;
4722   gint bin_window_height;
4723   GtkTreePath *cursor_path;
4724   GtkTreePath *drag_dest_path;
4725   GList *first_column, *last_column;
4726   gint vertical_separator;
4727   gint horizontal_separator;
4728   gint focus_line_width;
4729   gboolean allow_rules;
4730   gboolean has_can_focus_cell;
4731   gboolean rtl;
4732   gint n_visible_columns;
4733   gint pointer_x, pointer_y;
4734   gint grid_line_width;
4735   gboolean got_pointer = FALSE;
4736   gboolean draw_vgrid_lines, draw_hgrid_lines;
4737
4738   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4739
4740   gtk_widget_style_get (widget,
4741                         "horizontal-separator", &horizontal_separator,
4742                         "vertical-separator", &vertical_separator,
4743                         "allow-rules", &allow_rules,
4744                         "focus-line-width", &focus_line_width,
4745                         NULL);
4746
4747   if (tree_view->priv->tree == NULL)
4748     {
4749       draw_empty_focus (tree_view, cr);
4750       return TRUE;
4751     }
4752
4753   style = gtk_widget_get_style (widget);
4754
4755   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4756   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4757   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4758   cairo_clip (cr);
4759   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4760     return TRUE;
4761
4762   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4763
4764   if (new_y < 0)
4765     new_y = 0;
4766   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4767
4768   if (tree_view->priv->height < bin_window_height)
4769     {
4770       gtk_paint_flat_box (style,
4771                           cr,
4772                           gtk_widget_get_state (widget),
4773                           GTK_SHADOW_NONE,
4774                           widget,
4775                           "cell_even",
4776                           0, tree_view->priv->height,
4777                           bin_window_width,
4778                           bin_window_height - tree_view->priv->height);
4779     }
4780
4781   if (node == NULL)
4782     return TRUE;
4783
4784   /* find the path for the node */
4785   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4786                                    tree,
4787                                    node);
4788   gtk_tree_model_get_iter (tree_view->priv->model,
4789                            &iter,
4790                            path);
4791   depth = gtk_tree_path_get_depth (path);
4792   gtk_tree_path_free (path);
4793   
4794   cursor_path = NULL;
4795   drag_dest_path = NULL;
4796
4797   if (tree_view->priv->cursor)
4798     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4799
4800   if (cursor_path)
4801     _gtk_tree_view_find_node (tree_view, cursor_path,
4802                               &cursor_tree, &cursor);
4803
4804   if (tree_view->priv->drag_dest_row)
4805     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4806
4807   if (drag_dest_path)
4808     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4809                               &drag_highlight_tree, &drag_highlight);
4810
4811   draw_vgrid_lines =
4812     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4813     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4814   draw_hgrid_lines =
4815     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4816     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4817
4818   if (draw_vgrid_lines || draw_hgrid_lines)
4819     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4820   
4821   n_visible_columns = 0;
4822   for (list = tree_view->priv->columns; list; list = list->next)
4823     {
4824       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4825         continue;
4826       n_visible_columns ++;
4827     }
4828
4829   /* Find the last column */
4830   for (last_column = g_list_last (tree_view->priv->columns);
4831        last_column &&
4832        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4833        last_column = last_column->prev)
4834     ;
4835
4836   /* and the first */
4837   for (first_column = g_list_first (tree_view->priv->columns);
4838        first_column &&
4839        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4840        first_column = first_column->next)
4841     ;
4842
4843   /* Actually process the expose event.  To do this, we want to
4844    * start at the first node of the event, and walk the tree in
4845    * order, drawing each successive node.
4846    */
4847
4848   do
4849     {
4850       gboolean parity;
4851       gboolean is_separator = FALSE;
4852       gboolean is_first = FALSE;
4853       gboolean is_last = FALSE;
4854       
4855       is_separator = row_is_separator (tree_view, &iter, NULL);
4856
4857       max_height = gtk_tree_view_get_row_height (tree_view, node);
4858
4859       cell_offset = 0;
4860       highlight_x = 0; /* should match x coord of first cell */
4861       expander_cell_width = 0;
4862
4863       background_area.y = y_offset + clip.y;
4864       background_area.height = max_height;
4865
4866       flags = 0;
4867
4868       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4869         flags |= GTK_CELL_RENDERER_PRELIT;
4870
4871       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4872         flags |= GTK_CELL_RENDERER_SELECTED;
4873
4874       parity = _gtk_rbtree_node_find_parity (tree, node);
4875
4876       /* we *need* to set cell data on all cells before the call
4877        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4878        * return a correct value.
4879        */
4880       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4881            list;
4882            list = (rtl ? list->prev : list->next))
4883         {
4884           GtkTreeViewColumn *column = list->data;
4885           gtk_tree_view_column_cell_set_cell_data (column,
4886                                                    tree_view->priv->model,
4887                                                    &iter,
4888                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4889                                                    node->children?TRUE:FALSE);
4890         }
4891
4892       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4893
4894       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4895            list;
4896            list = (rtl ? list->prev : list->next))
4897         {
4898           GtkTreeViewColumn *column = list->data;
4899           const gchar *detail = NULL;
4900           gchar new_detail[128];
4901           gint width;
4902           GtkStateType state;
4903           gboolean draw_focus;
4904
4905           if (!gtk_tree_view_column_get_visible (column))
4906             continue;
4907
4908           width = gtk_tree_view_column_get_width (column);
4909
4910           if (cell_offset > clip.x + clip.width ||
4911               cell_offset + width < clip.x)
4912             {
4913               cell_offset += width;
4914               continue;
4915             }
4916
4917           if (gtk_tree_view_column_get_sort_indicator (column))
4918             flags |= GTK_CELL_RENDERER_SORTED;
4919           else
4920             flags &= ~GTK_CELL_RENDERER_SORTED;
4921
4922           if (cursor == node)
4923             flags |= GTK_CELL_RENDERER_FOCUSED;
4924           else
4925             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4926
4927           background_area.x = cell_offset;
4928           background_area.width = width;
4929
4930           cell_area = background_area;
4931           cell_area.y += vertical_separator / 2;
4932           cell_area.x += horizontal_separator / 2;
4933           cell_area.height -= vertical_separator;
4934           cell_area.width -= horizontal_separator;
4935
4936           if (draw_vgrid_lines)
4937             {
4938               if (list == first_column)
4939                 {
4940                   cell_area.width -= grid_line_width / 2;
4941                 }
4942               else if (list == last_column)
4943                 {
4944                   cell_area.x += grid_line_width / 2;
4945                   cell_area.width -= grid_line_width / 2;
4946                 }
4947               else
4948                 {
4949                   cell_area.x += grid_line_width / 2;
4950                   cell_area.width -= grid_line_width;
4951                 }
4952             }
4953
4954           if (draw_hgrid_lines)
4955             {
4956               cell_area.y += grid_line_width / 2;
4957               cell_area.height -= grid_line_width;
4958             }
4959
4960           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4961             {
4962               cell_offset += gtk_tree_view_column_get_width (column);
4963               continue;
4964             }
4965
4966           gtk_tree_view_column_cell_set_cell_data (column,
4967                                                    tree_view->priv->model,
4968                                                    &iter,
4969                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4970                                                    node->children?TRUE:FALSE);
4971
4972           /* Select the detail for drawing the cell.  relevant
4973            * factors are parity, sortedness, and whether to
4974            * display rules.
4975            */
4976           if (allow_rules && tree_view->priv->has_rules)
4977             {
4978               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4979                   n_visible_columns >= 3)
4980                 {
4981                   if (parity)
4982                     detail = "cell_odd_ruled_sorted";
4983                   else
4984                     detail = "cell_even_ruled_sorted";
4985                 }
4986               else
4987                 {
4988                   if (parity)
4989                     detail = "cell_odd_ruled";
4990                   else
4991                     detail = "cell_even_ruled";
4992                 }
4993             }
4994           else
4995             {
4996               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4997                   n_visible_columns >= 3)
4998                 {
4999                   if (parity)
5000                     detail = "cell_odd_sorted";
5001                   else
5002                     detail = "cell_even_sorted";
5003                 }
5004               else
5005                 {
5006                   if (parity)
5007                     detail = "cell_odd";
5008                   else
5009                     detail = "cell_even";
5010                 }
5011             }
5012
5013           g_assert (detail);
5014
5015           if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
5016             state = GTK_STATE_INSENSITIVE;          
5017           else if (flags & GTK_CELL_RENDERER_SELECTED)
5018             state = GTK_STATE_SELECTED;
5019           else
5020             state = GTK_STATE_NORMAL;
5021
5022           if (node == cursor && has_can_focus_cell
5023               && ((column == tree_view->priv->focus_column
5024                    && tree_view->priv->draw_keyfocus &&
5025                    gtk_widget_has_focus (widget))
5026                   || (column == tree_view->priv->edited_column)))
5027             draw_focus = TRUE;
5028           else
5029             draw_focus = FALSE;
5030
5031           /* Draw background */
5032           is_first = (rtl ? !list->next : !list->prev);
5033           is_last = (rtl ? !list->prev : !list->next);
5034
5035           /* (I don't like the snprintfs either, but couldn't find a
5036            * less messy way).
5037            */
5038           if (is_first && is_last)
5039             g_snprintf (new_detail, 127, "%s", detail);
5040           else if (is_first)
5041             g_snprintf (new_detail, 127, "%s_start", detail);
5042           else if (is_last)
5043             g_snprintf (new_detail, 127, "%s_end", detail);
5044           else
5045             g_snprintf (new_detail, 127, "%s_middle", detail);
5046
5047           gtk_paint_flat_box (style,
5048                               cr,
5049                               state,
5050                               GTK_SHADOW_NONE,
5051                               widget,
5052                               new_detail,
5053                               background_area.x,
5054                               background_area.y,
5055                               background_area.width,
5056                               background_area.height);
5057
5058           if (gtk_tree_view_is_expander_column (tree_view, column))
5059             {
5060               if (!rtl)
5061                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
5062               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
5063
5064               if (gtk_tree_view_draw_expanders (tree_view))
5065                 {
5066                   if (!rtl)
5067                     cell_area.x += depth * tree_view->priv->expander_size;
5068                   cell_area.width -= depth * tree_view->priv->expander_size;
5069                 }
5070
5071               /* If we have an expander column, the highlight underline
5072                * starts with that column, so that it indicates which
5073                * level of the tree we're dropping at.
5074                */
5075               highlight_x = cell_area.x;
5076               expander_cell_width = cell_area.width;
5077
5078               if (is_separator)
5079                 gtk_paint_hline (style,
5080                                  cr,
5081                                  state,
5082                                  widget,
5083                                  NULL,
5084                                  cell_area.x,
5085                                  cell_area.x + cell_area.width,
5086                                  cell_area.y + cell_area.height / 2);
5087               else
5088                 _gtk_tree_view_column_cell_render (column,
5089                                                    cr,
5090                                                    &background_area,
5091                                                    &cell_area,
5092                                                    flags,
5093                                                    draw_focus);
5094               if (gtk_tree_view_draw_expanders (tree_view)
5095                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5096                 {
5097                   if (!got_pointer)
5098                     {
5099                       gdk_window_get_pointer (tree_view->priv->bin_window, 
5100                                               &pointer_x, &pointer_y, NULL);
5101                       got_pointer = TRUE;
5102                     }
5103
5104                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5105                                             cr,
5106                                             tree,
5107                                             node,
5108                                             pointer_x, pointer_y);
5109                 }
5110             }
5111           else
5112             {
5113               if (is_separator)
5114                 gtk_paint_hline (style,
5115                                  cr,
5116                                  state,
5117                                  widget,
5118                                  NULL,
5119                                  cell_area.x,
5120                                  cell_area.x + cell_area.width,
5121                                  cell_area.y + cell_area.height / 2);
5122               else
5123                 _gtk_tree_view_column_cell_render (column,
5124                                                    cr,
5125                                                    &background_area,
5126                                                    &cell_area,
5127                                                    flags,
5128                                                    draw_focus);
5129             }
5130
5131           if (draw_hgrid_lines)
5132             {
5133               if (background_area.y > 0)
5134                 gtk_tree_view_draw_line (tree_view, cr,
5135                                          GTK_TREE_VIEW_GRID_LINE,
5136                                          background_area.x, background_area.y,
5137                                          background_area.x + background_area.width,
5138                                          background_area.y);
5139
5140               if (y_offset + max_height >= clip.height)
5141                 gtk_tree_view_draw_line (tree_view, cr,
5142                                          GTK_TREE_VIEW_GRID_LINE,
5143                                          background_area.x, background_area.y + max_height,
5144                                          background_area.x + background_area.width,
5145                                          background_area.y + max_height);
5146             }
5147
5148           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5149               tree_view->priv->tree_lines_enabled)
5150             {
5151               gint x = background_area.x;
5152               gint mult = rtl ? -1 : 1;
5153               gint y0 = background_area.y;
5154               gint y1 = background_area.y + background_area.height/2;
5155               gint y2 = background_area.y + background_area.height;
5156
5157               if (rtl)
5158                 x += background_area.width - 1;
5159
5160               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5161                   && depth > 1)
5162                 {
5163                   gtk_tree_view_draw_line (tree_view, cr,
5164                                            GTK_TREE_VIEW_TREE_LINE,
5165                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5166                                            y1,
5167                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
5168                                            y1);
5169                 }
5170               else if (depth > 1)
5171                 {
5172                   gtk_tree_view_draw_line (tree_view, cr,
5173                                            GTK_TREE_VIEW_TREE_LINE,
5174                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5175                                            y1,
5176                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
5177                                            y1);
5178                 }
5179
5180               if (depth > 1)
5181                 {
5182                   gint i;
5183                   GtkRBNode *tmp_node;
5184                   GtkRBTree *tmp_tree;
5185
5186                   if (!_gtk_rbtree_next (tree, node))
5187                     gtk_tree_view_draw_line (tree_view, cr,
5188                                              GTK_TREE_VIEW_TREE_LINE,
5189                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5190                                              y0,
5191                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5192                                              y1);
5193                   else
5194                     gtk_tree_view_draw_line (tree_view, cr,
5195                                              GTK_TREE_VIEW_TREE_LINE,
5196                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5197                                              y0,
5198                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5199                                              y2);
5200
5201                   tmp_node = tree->parent_node;
5202                   tmp_tree = tree->parent_tree;
5203
5204                   for (i = depth - 2; i > 0; i--)
5205                     {
5206                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5207                         gtk_tree_view_draw_line (tree_view, cr,
5208                                                  GTK_TREE_VIEW_TREE_LINE,
5209                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5210                                                  y0,
5211                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5212                                                  y2);
5213
5214                       tmp_node = tmp_tree->parent_node;
5215                       tmp_tree = tmp_tree->parent_tree;
5216                     }
5217                 }
5218             }
5219
5220           cell_offset += gtk_tree_view_column_get_width (column);
5221         }
5222
5223       if (node == drag_highlight)
5224         {
5225           /* Draw indicator for the drop
5226            */
5227           gint highlight_y = -1;
5228           GtkRBTree *tree = NULL;
5229           GtkRBNode *node = NULL;
5230
5231           switch (tree_view->priv->drag_dest_pos)
5232             {
5233             case GTK_TREE_VIEW_DROP_BEFORE:
5234               highlight_y = background_area.y - 1;
5235               if (highlight_y < 0)
5236                       highlight_y = 0;
5237               break;
5238
5239             case GTK_TREE_VIEW_DROP_AFTER:
5240               highlight_y = background_area.y + background_area.height - 1;
5241               break;
5242
5243             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5244             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5245               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5246
5247               if (tree == NULL)
5248                 break;
5249
5250               gtk_paint_focus (style,
5251                                cr,
5252                                gtk_widget_get_state (widget),
5253                                widget,
5254                                (is_first
5255                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
5256                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
5257                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node)
5258                                    - focus_line_width / 2,
5259                                 gdk_window_get_width (tree_view->priv->bin_window),
5260                                 gtk_tree_view_get_row_height (tree_view, node)
5261                                    - focus_line_width + 1);
5262               break;
5263             }
5264
5265           if (highlight_y >= 0)
5266             {
5267               gtk_tree_view_draw_line (tree_view, cr,
5268                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5269                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5270                                        highlight_y,
5271                                        rtl ? 0 : bin_window_width,
5272                                        highlight_y);
5273             }
5274         }
5275
5276       /* draw the big row-spanning focus rectangle, if needed */
5277       if (!has_can_focus_cell && node == cursor &&
5278           tree_view->priv->draw_keyfocus &&
5279           gtk_widget_has_focus (widget))
5280         {
5281           gint tmp_y, tmp_height;
5282           GtkStateType focus_rect_state;
5283
5284           focus_rect_state =
5285             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
5286             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
5287              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
5288               GTK_STATE_NORMAL));
5289
5290           if (draw_hgrid_lines)
5291             {
5292               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5293               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5294             }
5295           else
5296             {
5297               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5298               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5299             }
5300
5301           gtk_paint_focus (style,
5302                            cr,
5303                            focus_rect_state,
5304                            widget,
5305                            (is_first
5306                             ? (is_last ? "treeview" : "treeview-left" )
5307                             : (is_last ? "treeview-right" : "treeview-middle" )),
5308                            0, tmp_y,
5309                            gdk_window_get_width (tree_view->priv->bin_window),
5310                            tmp_height);
5311         }
5312
5313       y_offset += max_height;
5314       if (node->children)
5315         {
5316           GtkTreeIter parent = iter;
5317           gboolean has_child;
5318
5319           tree = node->children;
5320           node = tree->root;
5321
5322           g_assert (node != tree->nil);
5323
5324           while (node->left != tree->nil)
5325             node = node->left;
5326           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5327                                                     &iter,
5328                                                     &parent);
5329           depth++;
5330
5331           /* Sanity Check! */
5332           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5333         }
5334       else
5335         {
5336           gboolean done = FALSE;
5337
5338           do
5339             {
5340               node = _gtk_rbtree_next (tree, node);
5341               if (node != NULL)
5342                 {
5343                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5344                   done = TRUE;
5345
5346                   /* Sanity Check! */
5347                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5348                 }
5349               else
5350                 {
5351                   GtkTreeIter parent_iter = iter;
5352                   gboolean has_parent;
5353
5354                   node = tree->parent_node;
5355                   tree = tree->parent_tree;
5356                   if (tree == NULL)
5357                     /* we should go to done to free some memory */
5358                     goto done;
5359                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5360                                                            &iter,
5361                                                            &parent_iter);
5362                   depth--;
5363
5364                   /* Sanity check */
5365                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5366                 }
5367             }
5368           while (!done);
5369         }
5370     }
5371   while (y_offset < clip.height);
5372
5373 done:
5374   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5375
5376   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5377     gtk_tree_view_paint_rubber_band (tree_view, cr);
5378
5379   if (cursor_path)
5380     gtk_tree_path_free (cursor_path);
5381
5382   if (drag_dest_path)
5383     gtk_tree_path_free (drag_dest_path);
5384
5385   return FALSE;
5386 }
5387
5388 static gboolean
5389 gtk_tree_view_draw (GtkWidget *widget,
5390                     cairo_t   *cr)
5391 {
5392   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5393   GtkWidget   *button;
5394
5395   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5396     {
5397       GList *tmp_list;
5398
5399       cairo_save (cr);
5400
5401       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5402
5403       gtk_tree_view_bin_draw (widget, cr);
5404
5405       cairo_restore (cr);
5406
5407       /* We can't just chain up to Container::draw as it will try to send the
5408        * event to the headers, so we handle propagating it to our children
5409        * (eg. widgets being edited) ourselves.
5410        */
5411       tmp_list = tree_view->priv->children;
5412       while (tmp_list)
5413         {
5414           GtkTreeViewChild *child = tmp_list->data;
5415           tmp_list = tmp_list->next;
5416
5417           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5418         }
5419     }
5420
5421   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5422     {
5423       GList *list;
5424       
5425       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5426         {
5427           GtkTreeViewColumn *column = list->data;
5428
5429           if (column == tree_view->priv->drag_column)
5430             continue;
5431
5432           if (gtk_tree_view_column_get_visible (column))
5433             {
5434               button = gtk_tree_view_column_get_button (column);
5435               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5436                                             button, cr);
5437             }
5438         }
5439     }
5440   
5441   if (tree_view->priv->drag_window &&
5442       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5443     {
5444       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5445       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5446                                     button, cr);
5447     }
5448
5449   return TRUE;
5450 }
5451
5452 enum
5453 {
5454   DROP_HOME,
5455   DROP_RIGHT,
5456   DROP_LEFT,
5457   DROP_END
5458 };
5459
5460 /* returns 0x1 when no column has been found -- yes it's hackish */
5461 static GtkTreeViewColumn *
5462 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5463                                GtkTreeViewColumn *column,
5464                                gint               drop_position)
5465 {
5466   GtkTreeViewColumn *left_column = NULL;
5467   GtkTreeViewColumn *cur_column = NULL;
5468   GList *tmp_list;
5469
5470   if (!gtk_tree_view_column_get_reorderable (column))
5471     return (GtkTreeViewColumn *)0x1;
5472
5473   switch (drop_position)
5474     {
5475       case DROP_HOME:
5476         /* find first column where we can drop */
5477         tmp_list = tree_view->priv->columns;
5478         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5479           return (GtkTreeViewColumn *)0x1;
5480
5481         while (tmp_list)
5482           {
5483             g_assert (tmp_list);
5484
5485             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5486             tmp_list = tmp_list->next;
5487
5488             if (left_column &&
5489                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5490               continue;
5491
5492             if (!tree_view->priv->column_drop_func)
5493               return left_column;
5494
5495             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5496               {
5497                 left_column = cur_column;
5498                 continue;
5499               }
5500
5501             return left_column;
5502           }
5503
5504         if (!tree_view->priv->column_drop_func)
5505           return left_column;
5506
5507         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5508           return left_column;
5509         else
5510           return (GtkTreeViewColumn *)0x1;
5511         break;
5512
5513       case DROP_RIGHT:
5514         /* find first column after column where we can drop */
5515         tmp_list = tree_view->priv->columns;
5516
5517         for (; tmp_list; tmp_list = tmp_list->next)
5518           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5519             break;
5520
5521         if (!tmp_list || !tmp_list->next)
5522           return (GtkTreeViewColumn *)0x1;
5523
5524         tmp_list = tmp_list->next;
5525         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5526         tmp_list = tmp_list->next;
5527
5528         while (tmp_list)
5529           {
5530             g_assert (tmp_list);
5531
5532             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5533             tmp_list = tmp_list->next;
5534
5535             if (left_column &&
5536                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5537               {
5538                 left_column = cur_column;
5539                 if (tmp_list)
5540                   tmp_list = tmp_list->next;
5541                 continue;
5542               }
5543
5544             if (!tree_view->priv->column_drop_func)
5545               return left_column;
5546
5547             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5548               {
5549                 left_column = cur_column;
5550                 continue;
5551               }
5552
5553             return left_column;
5554           }
5555
5556         if (!tree_view->priv->column_drop_func)
5557           return left_column;
5558
5559         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5560           return left_column;
5561         else
5562           return (GtkTreeViewColumn *)0x1;
5563         break;
5564
5565       case DROP_LEFT:
5566         /* find first column before column where we can drop */
5567         tmp_list = tree_view->priv->columns;
5568
5569         for (; tmp_list; tmp_list = tmp_list->next)
5570           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5571             break;
5572
5573         if (!tmp_list || !tmp_list->prev)
5574           return (GtkTreeViewColumn *)0x1;
5575
5576         tmp_list = tmp_list->prev;
5577         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5578         tmp_list = tmp_list->prev;
5579
5580         while (tmp_list)
5581           {
5582             g_assert (tmp_list);
5583
5584             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5585
5586             if (left_column &&
5587                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5588               {
5589                 /*if (!tmp_list->prev)
5590                   return (GtkTreeViewColumn *)0x1;
5591                   */
5592 /*
5593                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5594                 tmp_list = tmp_list->prev->prev;
5595                 continue;*/
5596
5597                 cur_column = left_column;
5598                 if (tmp_list)
5599                   tmp_list = tmp_list->prev;
5600                 continue;
5601               }
5602
5603             if (!tree_view->priv->column_drop_func)
5604               return left_column;
5605
5606             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5607               return left_column;
5608
5609             cur_column = left_column;
5610             tmp_list = tmp_list->prev;
5611           }
5612
5613         if (!tree_view->priv->column_drop_func)
5614           return NULL;
5615
5616         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5617           return NULL;
5618         else
5619           return (GtkTreeViewColumn *)0x1;
5620         break;
5621
5622       case DROP_END:
5623         /* same as DROP_HOME case, but doing it backwards */
5624         tmp_list = g_list_last (tree_view->priv->columns);
5625         cur_column = NULL;
5626
5627         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5628           return (GtkTreeViewColumn *)0x1;
5629
5630         while (tmp_list)
5631           {
5632             g_assert (tmp_list);
5633
5634             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5635
5636             if (left_column &&
5637                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5638               {
5639                 cur_column = left_column;
5640                 tmp_list = tmp_list->prev;
5641               }
5642
5643             if (!tree_view->priv->column_drop_func)
5644               return left_column;
5645
5646             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5647               return left_column;
5648
5649             cur_column = left_column;
5650             tmp_list = tmp_list->prev;
5651           }
5652
5653         if (!tree_view->priv->column_drop_func)
5654           return NULL;
5655
5656         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5657           return NULL;
5658         else
5659           return (GtkTreeViewColumn *)0x1;
5660         break;
5661     }
5662
5663   return (GtkTreeViewColumn *)0x1;
5664 }
5665
5666 static gboolean
5667 gtk_tree_view_key_press (GtkWidget   *widget,
5668                          GdkEventKey *event)
5669 {
5670   GtkTreeView *tree_view = (GtkTreeView *) widget;
5671   GtkWidget   *button;
5672
5673   if (tree_view->priv->rubber_band_status)
5674     {
5675       if (event->keyval == GDK_KEY_Escape)
5676         gtk_tree_view_stop_rubber_band (tree_view);
5677
5678       return TRUE;
5679     }
5680
5681   if (tree_view->priv->in_column_drag)
5682     {
5683       if (event->keyval == GDK_KEY_Escape)
5684         {
5685           tree_view->priv->cur_reorder = NULL;
5686           gtk_tree_view_button_release_drag_column (widget, NULL);
5687         }
5688       return TRUE;
5689     }
5690
5691   if (tree_view->priv->headers_visible)
5692     {
5693       GList *focus_column;
5694       gboolean rtl;
5695
5696       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5697
5698       for (focus_column = tree_view->priv->columns;
5699            focus_column;
5700            focus_column = focus_column->next)
5701         {
5702           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5703           
5704           button = gtk_tree_view_column_get_button (column);
5705           if (gtk_widget_has_focus (button))
5706             break;
5707         }
5708
5709       if (focus_column &&
5710           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5711           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5712            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5713         {
5714           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5715           gint max_width, min_width;
5716
5717           if (!gtk_tree_view_column_get_resizable (column))
5718             {
5719               gtk_widget_error_bell (widget);
5720               return TRUE;
5721             }
5722
5723           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5724               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5725             {
5726               GtkRequisition button_req;
5727               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5728               gint new_width;
5729
5730               button = gtk_tree_view_column_get_button (column);
5731
5732               gtk_widget_get_preferred_size (button, &button_req, NULL);
5733
5734               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5735               new_width -= 2;
5736               if (new_width < 0)
5737                 new_width = 0;
5738
5739               _gtk_tree_view_column_set_resized_width (column, new_width);
5740
5741               min_width = gtk_tree_view_column_get_min_width (column);
5742               if (min_width == -1)
5743                 new_width = MAX (button_req.width, new_width);
5744               else
5745                 {
5746                   new_width = MAX (min_width, new_width);
5747                 }
5748
5749               max_width = gtk_tree_view_column_get_max_width (column);
5750               if (max_width != -1)
5751                 new_width = MIN (new_width, max_width);
5752
5753               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5754
5755               if (new_width != old_width)
5756                 {
5757                   _gtk_tree_view_column_set_resized_width (column, new_width);
5758                   gtk_widget_queue_resize (widget);
5759                 }
5760               else
5761                 gtk_widget_error_bell (widget);
5762             }
5763           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5764                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5765             {
5766               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5767               gint new_width;
5768
5769               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5770               new_width += 2;
5771
5772               max_width = gtk_tree_view_column_get_max_width (column);
5773               if (max_width != -1)
5774                 new_width = MIN (new_width, max_width);
5775
5776               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5777
5778               if (new_width != old_width)
5779                 {
5780                   _gtk_tree_view_column_set_resized_width (column, new_width);
5781                   gtk_widget_queue_resize (widget);
5782                 }
5783               else
5784                 gtk_widget_error_bell (widget);
5785             }
5786
5787           return TRUE;
5788         }
5789
5790       if (focus_column &&
5791           (event->state & GDK_MOD1_MASK) &&
5792           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5793            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5794            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5795            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5796         {
5797           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5798
5799           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5800               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5801             {
5802               GtkTreeViewColumn *col;
5803               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5804               if (col != (GtkTreeViewColumn *)0x1)
5805                 gtk_tree_view_move_column_after (tree_view, column, col);
5806               else
5807                 gtk_widget_error_bell (widget);
5808             }
5809           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5810                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5811             {
5812               GtkTreeViewColumn *col;
5813               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5814               if (col != (GtkTreeViewColumn *)0x1)
5815                 gtk_tree_view_move_column_after (tree_view, column, col);
5816               else
5817                 gtk_widget_error_bell (widget);
5818             }
5819           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5820             {
5821               GtkTreeViewColumn *col;
5822               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5823               if (col != (GtkTreeViewColumn *)0x1)
5824                 gtk_tree_view_move_column_after (tree_view, column, col);
5825               else
5826                 gtk_widget_error_bell (widget);
5827             }
5828           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5829             {
5830               GtkTreeViewColumn *col;
5831               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5832               if (col != (GtkTreeViewColumn *)0x1)
5833                 gtk_tree_view_move_column_after (tree_view, column, col);
5834               else
5835                 gtk_widget_error_bell (widget);
5836             }
5837
5838           return TRUE;
5839         }
5840     }
5841
5842   /* Chain up to the parent class.  It handles the keybindings. */
5843   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5844     return TRUE;
5845
5846   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5847     {
5848       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5849       return FALSE;
5850     }
5851
5852   /* We pass the event to the search_entry.  If its text changes, then we start
5853    * the typeahead find capabilities. */
5854   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5855       && tree_view->priv->enable_search
5856       && !tree_view->priv->search_custom_entry_set)
5857     {
5858       GdkEvent *new_event;
5859       char *old_text;
5860       const char *new_text;
5861       gboolean retval;
5862       GdkScreen *screen;
5863       gboolean text_modified;
5864       gulong popup_menu_id;
5865
5866       gtk_tree_view_ensure_interactive_directory (tree_view);
5867
5868       /* Make a copy of the current text */
5869       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5870       new_event = gdk_event_copy ((GdkEvent *) event);
5871       g_object_unref (((GdkEventKey *) new_event)->window);
5872       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5873       gtk_widget_realize (tree_view->priv->search_window);
5874
5875       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5876                                         "popup-menu", G_CALLBACK (gtk_true),
5877                                         NULL);
5878
5879       /* Move the entry off screen */
5880       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5881       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5882                        gdk_screen_get_width (screen) + 1,
5883                        gdk_screen_get_height (screen) + 1);
5884       gtk_widget_show (tree_view->priv->search_window);
5885
5886       /* Send the event to the window.  If the preedit_changed signal is emitted
5887        * during this event, we will set priv->imcontext_changed  */
5888       tree_view->priv->imcontext_changed = FALSE;
5889       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5890       gdk_event_free (new_event);
5891       gtk_widget_hide (tree_view->priv->search_window);
5892
5893       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5894                                    popup_menu_id);
5895
5896       /* We check to make sure that the entry tried to handle the text, and that
5897        * the text has changed.
5898        */
5899       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5900       text_modified = strcmp (old_text, new_text) != 0;
5901       g_free (old_text);
5902       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5903           (retval && text_modified))               /* ...or the text was modified */
5904         {
5905           if (gtk_tree_view_real_start_interactive_search (tree_view,
5906                                                            gdk_event_get_device ((GdkEvent *) event),
5907                                                            FALSE))
5908             {
5909               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5910               return TRUE;
5911             }
5912           else
5913             {
5914               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5915               return FALSE;
5916             }
5917         }
5918     }
5919
5920   return FALSE;
5921 }
5922
5923 static gboolean
5924 gtk_tree_view_key_release (GtkWidget   *widget,
5925                            GdkEventKey *event)
5926 {
5927   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5928
5929   if (tree_view->priv->rubber_band_status)
5930     return TRUE;
5931
5932   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5933 }
5934
5935 /* FIXME Is this function necessary? Can I get an enter_notify event
5936  * w/o either an expose event or a mouse motion event?
5937  */
5938 static gboolean
5939 gtk_tree_view_enter_notify (GtkWidget        *widget,
5940                             GdkEventCrossing *event)
5941 {
5942   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5943   GtkRBTree *tree;
5944   GtkRBNode *node;
5945   gint new_y;
5946
5947   /* Sanity check it */
5948   if (event->window != tree_view->priv->bin_window)
5949     return FALSE;
5950
5951   if (tree_view->priv->tree == NULL)
5952     return FALSE;
5953
5954   if (event->mode == GDK_CROSSING_GRAB ||
5955       event->mode == GDK_CROSSING_GTK_GRAB ||
5956       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5957       event->mode == GDK_CROSSING_STATE_CHANGED)
5958     return TRUE;
5959
5960   /* find the node internally */
5961   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5962   if (new_y < 0)
5963     new_y = 0;
5964   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5965
5966   tree_view->priv->event_last_x = event->x;
5967   tree_view->priv->event_last_y = event->y;
5968
5969   if ((tree_view->priv->button_pressed_node == NULL) ||
5970       (tree_view->priv->button_pressed_node == node))
5971     prelight_or_select (tree_view, tree, node, event->x, event->y);
5972
5973   return TRUE;
5974 }
5975
5976 static gboolean
5977 gtk_tree_view_leave_notify (GtkWidget        *widget,
5978                             GdkEventCrossing *event)
5979 {
5980   GtkTreeView *tree_view;
5981
5982   if (event->mode == GDK_CROSSING_GRAB)
5983     return TRUE;
5984
5985   tree_view = GTK_TREE_VIEW (widget);
5986
5987   if (tree_view->priv->prelight_node)
5988     _gtk_tree_view_queue_draw_node (tree_view,
5989                                    tree_view->priv->prelight_tree,
5990                                    tree_view->priv->prelight_node,
5991                                    NULL);
5992
5993   tree_view->priv->event_last_x = -10000;
5994   tree_view->priv->event_last_y = -10000;
5995
5996   prelight_or_select (tree_view,
5997                       NULL, NULL,
5998                       -1000, -1000); /* coords not possibly over an arrow */
5999
6000   return TRUE;
6001 }
6002
6003
6004 static gint
6005 gtk_tree_view_focus_out (GtkWidget     *widget,
6006                          GdkEventFocus *event)
6007 {
6008   GtkTreeView *tree_view;
6009
6010   tree_view = GTK_TREE_VIEW (widget);
6011
6012   gtk_widget_queue_draw (widget);
6013
6014   /* destroy interactive search dialog */
6015   if (tree_view->priv->search_window)
6016     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
6017                                       gdk_event_get_device ((GdkEvent *) event));
6018
6019   return FALSE;
6020 }
6021
6022
6023 /* Incremental Reflow
6024  */
6025
6026 static void
6027 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
6028                                  GtkRBTree   *tree,
6029                                  GtkRBNode   *node)
6030 {
6031   GtkAllocation allocation;
6032   gint y;
6033
6034   y = _gtk_rbtree_node_find_offset (tree, node)
6035     - tree_view->priv->vadjustment->value
6036     + gtk_tree_view_get_effective_header_height (tree_view);
6037
6038   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6039   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
6040                               0, y,
6041                               allocation.width,
6042                               GTK_RBNODE_GET_HEIGHT (node));
6043 }
6044
6045 static gboolean
6046 node_is_visible (GtkTreeView *tree_view,
6047                  GtkRBTree   *tree,
6048                  GtkRBNode   *node)
6049 {
6050   int y;
6051   int height;
6052
6053   y = _gtk_rbtree_node_find_offset (tree, node);
6054   height = gtk_tree_view_get_row_height (tree_view, node);
6055
6056   if (y >= tree_view->priv->vadjustment->value &&
6057       y + height <= (tree_view->priv->vadjustment->value
6058                      + tree_view->priv->vadjustment->page_size))
6059     return TRUE;
6060
6061   return FALSE;
6062 }
6063
6064 /* Returns TRUE if it updated the size
6065  */
6066 static gboolean
6067 validate_row (GtkTreeView *tree_view,
6068               GtkRBTree   *tree,
6069               GtkRBNode   *node,
6070               GtkTreeIter *iter,
6071               GtkTreePath *path)
6072 {
6073   GtkTreeViewColumn *column;
6074   GList *list, *first_column, *last_column;
6075   gint height = 0;
6076   gint horizontal_separator;
6077   gint vertical_separator;
6078   gint depth = gtk_tree_path_get_depth (path);
6079   gboolean retval = FALSE;
6080   gboolean is_separator = FALSE;
6081   gboolean draw_vgrid_lines, draw_hgrid_lines;
6082   gint focus_pad;
6083   gint grid_line_width;
6084   gboolean wide_separators;
6085   gint separator_height;
6086
6087   /* double check the row needs validating */
6088   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6089       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6090     return FALSE;
6091
6092   is_separator = row_is_separator (tree_view, iter, NULL);
6093
6094   gtk_widget_style_get (GTK_WIDGET (tree_view),
6095                         "focus-padding", &focus_pad,
6096                         "horizontal-separator", &horizontal_separator,
6097                         "vertical-separator", &vertical_separator,
6098                         "grid-line-width", &grid_line_width,
6099                         "wide-separators",  &wide_separators,
6100                         "separator-height", &separator_height,
6101                         NULL);
6102   
6103   draw_vgrid_lines =
6104     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6105     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6106   draw_hgrid_lines =
6107     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6108     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6109
6110   for (last_column = g_list_last (tree_view->priv->columns);
6111        last_column &&
6112        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6113        last_column = last_column->prev)
6114     ;
6115
6116   for (first_column = g_list_first (tree_view->priv->columns);
6117        first_column &&
6118        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6119        first_column = first_column->next)
6120     ;
6121
6122   for (list = tree_view->priv->columns; list; list = list->next)
6123     {
6124       gint padding = 0;
6125       gint original_width;
6126       gint new_width;
6127       gint row_height;
6128
6129       column = list->data;
6130
6131       if (!gtk_tree_view_column_get_visible (column))
6132         continue;
6133
6134       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6135           !_gtk_tree_view_column_cell_get_dirty (column))
6136         continue;
6137
6138       original_width = _gtk_tree_view_column_get_requested_width (column);
6139
6140       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6141                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6142                                                node->children?TRUE:FALSE);
6143       gtk_tree_view_column_cell_get_size (column,
6144                                           NULL, NULL, NULL,
6145                                           NULL, &row_height);
6146
6147       if (!is_separator)
6148         {
6149           row_height += vertical_separator;
6150           height = MAX (height, row_height);
6151           height = MAX (height, tree_view->priv->expander_size);
6152         }
6153       else
6154         {
6155           if (wide_separators)
6156             height = separator_height + 2 * focus_pad;
6157           else
6158             height = 2 + 2 * focus_pad;
6159         }
6160
6161       if (gtk_tree_view_is_expander_column (tree_view, column))
6162         {
6163           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6164
6165           if (gtk_tree_view_draw_expanders (tree_view))
6166             padding += depth * tree_view->priv->expander_size;
6167         }
6168       else
6169         padding += horizontal_separator;
6170
6171       if (draw_vgrid_lines)
6172         {
6173           if (list->data == first_column || list->data == last_column)
6174             padding += grid_line_width / 2.0;
6175           else
6176             padding += grid_line_width;
6177         }
6178
6179       /* Update the padding for the column */
6180       _gtk_tree_view_column_push_padding (column, padding);
6181       new_width = _gtk_tree_view_column_get_requested_width (column);
6182
6183       if (new_width > original_width)
6184         retval = TRUE;
6185     }
6186
6187   if (draw_hgrid_lines)
6188     height += grid_line_width;
6189
6190   if (height != GTK_RBNODE_GET_HEIGHT (node))
6191     {
6192       retval = TRUE;
6193       _gtk_rbtree_node_set_height (tree, node, height);
6194     }
6195   _gtk_rbtree_node_mark_valid (tree, node);
6196   tree_view->priv->post_validation_flag = TRUE;
6197
6198   return retval;
6199 }
6200
6201
6202 static void
6203 validate_visible_area (GtkTreeView *tree_view)
6204 {
6205   GtkAllocation allocation;
6206   GtkTreePath *path = NULL;
6207   GtkTreePath *above_path = NULL;
6208   GtkTreeIter iter;
6209   GtkRBTree *tree = NULL;
6210   GtkRBNode *node = NULL;
6211   gboolean need_redraw = FALSE;
6212   gboolean size_changed = FALSE;
6213   gint total_height;
6214   gint area_above = 0;
6215   gint area_below = 0;
6216
6217   if (tree_view->priv->tree == NULL)
6218     return;
6219
6220   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6221       tree_view->priv->scroll_to_path == NULL)
6222     return;
6223
6224   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6225   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6226
6227   if (total_height == 0)
6228     return;
6229
6230   /* First, we check to see if we need to scroll anywhere
6231    */
6232   if (tree_view->priv->scroll_to_path)
6233     {
6234       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6235       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6236         {
6237           /* we are going to scroll, and will update dy */
6238           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6239           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6240               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6241             {
6242               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6243               if (validate_row (tree_view, tree, node, &iter, path))
6244                 size_changed = TRUE;
6245             }
6246
6247           if (tree_view->priv->scroll_to_use_align)
6248             {
6249               gint height = gtk_tree_view_get_row_height (tree_view, node);
6250               area_above = (total_height - height) *
6251                 tree_view->priv->scroll_to_row_align;
6252               area_below = total_height - area_above - height;
6253               area_above = MAX (area_above, 0);
6254               area_below = MAX (area_below, 0);
6255             }
6256           else
6257             {
6258               /* two cases:
6259                * 1) row not visible
6260                * 2) row visible
6261                */
6262               gint dy;
6263               gint height = gtk_tree_view_get_row_height (tree_view, node);
6264
6265               dy = _gtk_rbtree_node_find_offset (tree, node);
6266
6267               if (dy >= tree_view->priv->vadjustment->value &&
6268                   dy + height <= (tree_view->priv->vadjustment->value
6269                                   + tree_view->priv->vadjustment->page_size))
6270                 {
6271                   /* row visible: keep the row at the same position */
6272                   area_above = dy - tree_view->priv->vadjustment->value;
6273                   area_below = (tree_view->priv->vadjustment->value +
6274                                 tree_view->priv->vadjustment->page_size)
6275                                - dy - height;
6276                 }
6277               else
6278                 {
6279                   /* row not visible */
6280                   if (dy >= 0
6281                       && dy + height <= tree_view->priv->vadjustment->page_size)
6282                     {
6283                       /* row at the beginning -- fixed */
6284                       area_above = dy;
6285                       area_below = tree_view->priv->vadjustment->page_size
6286                                    - area_above - height;
6287                     }
6288                   else if (dy >= (tree_view->priv->vadjustment->upper -
6289                                   tree_view->priv->vadjustment->page_size))
6290                     {
6291                       /* row at the end -- fixed */
6292                       area_above = dy - (tree_view->priv->vadjustment->upper -
6293                                    tree_view->priv->vadjustment->page_size);
6294                       area_below = tree_view->priv->vadjustment->page_size -
6295                                    area_above - height;
6296
6297                       if (area_below < 0)
6298                         {
6299                           area_above = tree_view->priv->vadjustment->page_size - height;
6300                           area_below = 0;
6301                         }
6302                     }
6303                   else
6304                     {
6305                       /* row somewhere in the middle, bring it to the top
6306                        * of the view
6307                        */
6308                       area_above = 0;
6309                       area_below = total_height - height;
6310                     }
6311                 }
6312             }
6313         }
6314       else
6315         /* the scroll to isn't valid; ignore it.
6316          */
6317         {
6318           if (tree_view->priv->scroll_to_path && !path)
6319             {
6320               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6321               tree_view->priv->scroll_to_path = NULL;
6322             }
6323           if (path)
6324             gtk_tree_path_free (path);
6325           path = NULL;
6326         }      
6327     }
6328
6329   /* We didn't have a scroll_to set, so we just handle things normally
6330    */
6331   if (path == NULL)
6332     {
6333       gint offset;
6334
6335       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6336                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6337                                         &tree, &node);
6338       if (node == NULL)
6339         {
6340           /* In this case, nothing has been validated */
6341           path = gtk_tree_path_new_first ();
6342           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6343         }
6344       else
6345         {
6346           path = _gtk_tree_view_find_path (tree_view, tree, node);
6347           total_height += offset;
6348         }
6349
6350       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6351
6352       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6353           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6354         {
6355           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6356           if (validate_row (tree_view, tree, node, &iter, path))
6357             size_changed = TRUE;
6358         }
6359       area_above = 0;
6360       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6361     }
6362
6363   above_path = gtk_tree_path_copy (path);
6364
6365   /* if we do not validate any row above the new top_row, we will make sure
6366    * that the row immediately above top_row has been validated. (if we do not
6367    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6368    * when invalidated that row's height will be zero. and this will mess up
6369    * scrolling).
6370    */
6371   if (area_above == 0)
6372     {
6373       GtkRBTree *tmptree;
6374       GtkRBNode *tmpnode;
6375
6376       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6377       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6378
6379       if (tmpnode)
6380         {
6381           GtkTreePath *tmppath;
6382           GtkTreeIter tmpiter;
6383
6384           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6385           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6386
6387           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6388               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6389             {
6390               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6391               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6392                 size_changed = TRUE;
6393             }
6394
6395           gtk_tree_path_free (tmppath);
6396         }
6397     }
6398
6399   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6400    * backwards is much slower then forward, as there is no iter_prev function.
6401    * We go forwards first in case we run out of tree.  Then we go backwards to
6402    * fill out the top.
6403    */
6404   while (node && area_below > 0)
6405     {
6406       if (node->children)
6407         {
6408           GtkTreeIter parent = iter;
6409           gboolean has_child;
6410
6411           tree = node->children;
6412           node = tree->root;
6413
6414           g_assert (node != tree->nil);
6415
6416           while (node->left != tree->nil)
6417             node = node->left;
6418           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6419                                                     &iter,
6420                                                     &parent);
6421           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6422           gtk_tree_path_down (path);
6423         }
6424       else
6425         {
6426           gboolean done = FALSE;
6427           do
6428             {
6429               node = _gtk_rbtree_next (tree, node);
6430               if (node != NULL)
6431                 {
6432                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6433                   done = TRUE;
6434                   gtk_tree_path_next (path);
6435
6436                   /* Sanity Check! */
6437                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6438                 }
6439               else
6440                 {
6441                   GtkTreeIter parent_iter = iter;
6442                   gboolean has_parent;
6443
6444                   node = tree->parent_node;
6445                   tree = tree->parent_tree;
6446                   if (tree == NULL)
6447                     break;
6448                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6449                                                            &iter,
6450                                                            &parent_iter);
6451                   gtk_tree_path_up (path);
6452
6453                   /* Sanity check */
6454                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6455                 }
6456             }
6457           while (!done);
6458         }
6459
6460       if (!node)
6461         break;
6462
6463       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6464           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6465         {
6466           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6467           if (validate_row (tree_view, tree, node, &iter, path))
6468               size_changed = TRUE;
6469         }
6470
6471       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6472     }
6473   gtk_tree_path_free (path);
6474
6475   /* If we ran out of tree, and have extra area_below left, we need to add it
6476    * to area_above */
6477   if (area_below > 0)
6478     area_above += area_below;
6479
6480   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6481
6482   /* We walk backwards */
6483   while (area_above > 0)
6484     {
6485       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6486
6487       /* Always find the new path in the tree.  We cannot just assume
6488        * a gtk_tree_path_prev() is enough here, as there might be children
6489        * in between this node and the previous sibling node.  If this
6490        * appears to be a performance hotspot in profiles, we can look into
6491        * intrigate logic for keeping path, node and iter in sync like
6492        * we do for forward walks.  (Which will be hard because of the lacking
6493        * iter_prev).
6494        */
6495
6496       if (node == NULL)
6497         break;
6498
6499       gtk_tree_path_free (above_path);
6500       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6501
6502       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6503
6504       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6505           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6506         {
6507           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6508           if (validate_row (tree_view, tree, node, &iter, above_path))
6509             size_changed = TRUE;
6510         }
6511       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6512     }
6513
6514   /* if we scrolled to a path, we need to set the dy here,
6515    * and sync the top row accordingly
6516    */
6517   if (tree_view->priv->scroll_to_path)
6518     {
6519       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6520       gtk_tree_view_top_row_to_dy (tree_view);
6521
6522       need_redraw = TRUE;
6523     }
6524   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6525     {
6526       /* when we are not scrolling, we should never set dy to something
6527        * else than zero. we update top_row to be in sync with dy = 0.
6528        */
6529       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6530       gtk_tree_view_dy_to_top_row (tree_view);
6531     }
6532   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6533     {
6534       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6535       gtk_tree_view_dy_to_top_row (tree_view);
6536     }
6537   else
6538     gtk_tree_view_top_row_to_dy (tree_view);
6539
6540   /* update width/height and queue a resize */
6541   if (size_changed)
6542     {
6543       GtkRequisition requisition;
6544
6545       /* We temporarily guess a size, under the assumption that it will be the
6546        * same when we get our next size_allocate.  If we don't do this, we'll be
6547        * in an inconsistent state if we call top_row_to_dy. */
6548
6549       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6550                                      &requisition, NULL);
6551       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6552       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6553       gtk_adjustment_changed (tree_view->priv->hadjustment);
6554       gtk_adjustment_changed (tree_view->priv->vadjustment);
6555       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6556     }
6557
6558   if (tree_view->priv->scroll_to_path)
6559     {
6560       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6561       tree_view->priv->scroll_to_path = NULL;
6562     }
6563
6564   if (above_path)
6565     gtk_tree_path_free (above_path);
6566
6567   if (tree_view->priv->scroll_to_column)
6568     {
6569       tree_view->priv->scroll_to_column = NULL;
6570     }
6571   if (need_redraw)
6572     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6573 }
6574
6575 static void
6576 initialize_fixed_height_mode (GtkTreeView *tree_view)
6577 {
6578   if (!tree_view->priv->tree)
6579     return;
6580
6581   if (tree_view->priv->fixed_height < 0)
6582     {
6583       GtkTreeIter iter;
6584       GtkTreePath *path;
6585
6586       GtkRBTree *tree = NULL;
6587       GtkRBNode *node = NULL;
6588
6589       tree = tree_view->priv->tree;
6590       node = tree->root;
6591
6592       path = _gtk_tree_view_find_path (tree_view, tree, node);
6593       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6594
6595       validate_row (tree_view, tree, node, &iter, path);
6596
6597       gtk_tree_path_free (path);
6598
6599       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6600     }
6601
6602    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6603                                  tree_view->priv->fixed_height, TRUE);
6604 }
6605
6606 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6607  * the left-most uninvalidated node.  We then try walking right, validating
6608  * nodes.  Once we find a valid node, we repeat the previous process of finding
6609  * the first invalid node.
6610  */
6611
6612 static gboolean
6613 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6614 {
6615   GtkRBTree *tree = NULL;
6616   GtkRBNode *node = NULL;
6617   gboolean validated_area = FALSE;
6618   gint retval = TRUE;
6619   GtkTreePath *path = NULL;
6620   GtkTreeIter iter;
6621   GTimer *timer;
6622   gint i = 0;
6623
6624   gint prev_height = -1;
6625   gboolean fixed_height = TRUE;
6626
6627   g_assert (tree_view);
6628
6629   if (tree_view->priv->tree == NULL)
6630       return FALSE;
6631
6632   if (tree_view->priv->fixed_height_mode)
6633     {
6634       if (tree_view->priv->fixed_height < 0)
6635         initialize_fixed_height_mode (tree_view);
6636
6637       return FALSE;
6638     }
6639
6640   timer = g_timer_new ();
6641   g_timer_start (timer);
6642
6643   do
6644     {
6645       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6646         {
6647           retval = FALSE;
6648           goto done;
6649         }
6650
6651       if (path != NULL)
6652         {
6653           node = _gtk_rbtree_next (tree, node);
6654           if (node != NULL)
6655             {
6656               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6657               gtk_tree_path_next (path);
6658             }
6659           else
6660             {
6661               gtk_tree_path_free (path);
6662               path = NULL;
6663             }
6664         }
6665
6666       if (path == NULL)
6667         {
6668           tree = tree_view->priv->tree;
6669           node = tree_view->priv->tree->root;
6670
6671           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6672
6673           do
6674             {
6675               if (node->left != tree->nil &&
6676                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6677                 {
6678                   node = node->left;
6679                 }
6680               else if (node->right != tree->nil &&
6681                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6682                 {
6683                   node = node->right;
6684                 }
6685               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6686                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6687                 {
6688                   break;
6689                 }
6690               else if (node->children != NULL)
6691                 {
6692                   tree = node->children;
6693                   node = tree->root;
6694                 }
6695               else
6696                 /* RBTree corruption!  All bad */
6697                 g_assert_not_reached ();
6698             }
6699           while (TRUE);
6700           path = _gtk_tree_view_find_path (tree_view, tree, node);
6701           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6702         }
6703
6704       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6705                        validated_area;
6706
6707       if (!tree_view->priv->fixed_height_check)
6708         {
6709           gint height;
6710
6711           height = gtk_tree_view_get_row_height (tree_view, node);
6712           if (prev_height < 0)
6713             prev_height = height;
6714           else if (prev_height != height)
6715             fixed_height = FALSE;
6716         }
6717
6718       i++;
6719     }
6720   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6721
6722   if (!tree_view->priv->fixed_height_check)
6723    {
6724      if (fixed_height)
6725        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6726
6727      tree_view->priv->fixed_height_check = 1;
6728    }
6729   
6730  done:
6731   if (validated_area)
6732     {
6733       GtkRequisition requisition;
6734
6735       /* We temporarily guess a size, under the assumption that it will be the
6736        * same when we get our next size_allocate.  If we don't do this, we'll be
6737        * in an inconsistent state when we call top_row_to_dy. */
6738
6739       /* FIXME: This is called from size_request, for some reason it is not infinitely
6740        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6741        * not allowed (from inside ->get_preferred_width/height() implementations, one
6742        * should call the vfuncs directly). However what is desired here is the full
6743        * size including any margins and limited by any alignment (i.e. after 
6744        * GtkWidget:adjust_size_request() is called).
6745        *
6746        * Currently bypassing this but the real solution is to not update the scroll adjustments
6747        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6748        */
6749       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition);
6750
6751       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6752       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6753       gtk_adjustment_changed (tree_view->priv->hadjustment);
6754       gtk_adjustment_changed (tree_view->priv->vadjustment);
6755
6756       if (queue_resize)
6757         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6758     }
6759
6760   if (path) gtk_tree_path_free (path);
6761   g_timer_destroy (timer);
6762
6763   return retval;
6764 }
6765
6766 static gboolean
6767 validate_rows (GtkTreeView *tree_view)
6768 {
6769   gboolean retval;
6770   
6771   retval = do_validate_rows (tree_view, TRUE);
6772   
6773   if (! retval && tree_view->priv->validate_rows_timer)
6774     {
6775       g_source_remove (tree_view->priv->validate_rows_timer);
6776       tree_view->priv->validate_rows_timer = 0;
6777     }
6778
6779   return retval;
6780 }
6781
6782 static gboolean
6783 validate_rows_handler (GtkTreeView *tree_view)
6784 {
6785   gboolean retval;
6786
6787   retval = do_validate_rows (tree_view, TRUE);
6788   if (! retval && tree_view->priv->validate_rows_timer)
6789     {
6790       g_source_remove (tree_view->priv->validate_rows_timer);
6791       tree_view->priv->validate_rows_timer = 0;
6792     }
6793
6794   return retval;
6795 }
6796
6797 static gboolean
6798 do_presize_handler (GtkTreeView *tree_view)
6799 {
6800   if (tree_view->priv->mark_rows_col_dirty)
6801     {
6802       if (tree_view->priv->tree)
6803         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6804       tree_view->priv->mark_rows_col_dirty = FALSE;
6805     }
6806   validate_visible_area (tree_view);
6807   tree_view->priv->presize_handler_timer = 0;
6808
6809   if (tree_view->priv->fixed_height_mode)
6810     {
6811       GtkRequisition requisition;
6812
6813       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6814                                      &requisition, NULL);
6815
6816       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6817       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6818       gtk_adjustment_changed (tree_view->priv->hadjustment);
6819       gtk_adjustment_changed (tree_view->priv->vadjustment);
6820       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6821     }
6822                    
6823   return FALSE;
6824 }
6825
6826 static gboolean
6827 presize_handler_callback (gpointer data)
6828 {
6829   do_presize_handler (GTK_TREE_VIEW (data));
6830                    
6831   return FALSE;
6832 }
6833
6834 static void
6835 install_presize_handler (GtkTreeView *tree_view)
6836 {
6837   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6838     return;
6839
6840   if (! tree_view->priv->presize_handler_timer)
6841     {
6842       tree_view->priv->presize_handler_timer =
6843         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6844     }
6845   if (! tree_view->priv->validate_rows_timer)
6846     {
6847       tree_view->priv->validate_rows_timer =
6848         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6849     }
6850 }
6851
6852 static void
6853 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6854 {
6855   /* Prior to drawing, we make sure the visible area is validated. */
6856   if (tree_view->priv->presize_handler_timer)
6857     {
6858       g_source_remove (tree_view->priv->presize_handler_timer);
6859       tree_view->priv->presize_handler_timer = 0;
6860
6861       do_presize_handler (tree_view);
6862     }
6863
6864   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6865 }
6866
6867 static gboolean
6868 scroll_sync_handler (GtkTreeView *tree_view)
6869 {
6870   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6871     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6872   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6873     gtk_tree_view_top_row_to_dy (tree_view);
6874   else
6875     gtk_tree_view_dy_to_top_row (tree_view);
6876
6877   tree_view->priv->scroll_sync_timer = 0;
6878
6879   return FALSE;
6880 }
6881
6882 static void
6883 install_scroll_sync_handler (GtkTreeView *tree_view)
6884 {
6885   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6886     return;
6887
6888   if (!tree_view->priv->scroll_sync_timer)
6889     {
6890       tree_view->priv->scroll_sync_timer =
6891         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6892     }
6893 }
6894
6895 static void
6896 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6897                            GtkTreePath *path,
6898                            gint         offset)
6899 {
6900   gtk_tree_row_reference_free (tree_view->priv->top_row);
6901
6902   if (!path)
6903     {
6904       tree_view->priv->top_row = NULL;
6905       tree_view->priv->top_row_dy = 0;
6906     }
6907   else
6908     {
6909       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6910       tree_view->priv->top_row_dy = offset;
6911     }
6912 }
6913
6914 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6915  * it's set to be NULL, and top_row_dy is 0;
6916  */
6917 static void
6918 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6919 {
6920   gint offset;
6921   GtkTreePath *path;
6922   GtkRBTree *tree;
6923   GtkRBNode *node;
6924
6925   if (tree_view->priv->tree == NULL)
6926     {
6927       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6928     }
6929   else
6930     {
6931       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6932                                         tree_view->priv->dy,
6933                                         &tree, &node);
6934
6935       if (tree == NULL)
6936         {
6937           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6938         }
6939       else
6940         {
6941           path = _gtk_tree_view_find_path (tree_view, tree, node);
6942           gtk_tree_view_set_top_row (tree_view, path, offset);
6943           gtk_tree_path_free (path);
6944         }
6945     }
6946 }
6947
6948 static void
6949 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6950 {
6951   GtkTreePath *path;
6952   GtkRBTree *tree;
6953   GtkRBNode *node;
6954   int new_dy;
6955
6956   /* Avoid recursive calls */
6957   if (tree_view->priv->in_top_row_to_dy)
6958     return;
6959
6960   if (tree_view->priv->top_row)
6961     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6962   else
6963     path = NULL;
6964
6965   if (!path)
6966     tree = NULL;
6967   else
6968     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6969
6970   if (path)
6971     gtk_tree_path_free (path);
6972
6973   if (tree == NULL)
6974     {
6975       /* keep dy and set new toprow */
6976       gtk_tree_row_reference_free (tree_view->priv->top_row);
6977       tree_view->priv->top_row = NULL;
6978       tree_view->priv->top_row_dy = 0;
6979       /* DO NOT install the idle handler */
6980       gtk_tree_view_dy_to_top_row (tree_view);
6981       return;
6982     }
6983
6984   if (gtk_tree_view_get_row_height (tree_view, node)
6985       < tree_view->priv->top_row_dy)
6986     {
6987       /* new top row -- do NOT install the idle handler */
6988       gtk_tree_view_dy_to_top_row (tree_view);
6989       return;
6990     }
6991
6992   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6993   new_dy += tree_view->priv->top_row_dy;
6994
6995   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6996     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6997
6998   new_dy = MAX (0, new_dy);
6999
7000   tree_view->priv->in_top_row_to_dy = TRUE;
7001   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
7002   tree_view->priv->in_top_row_to_dy = FALSE;
7003 }
7004
7005
7006 void
7007 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
7008                                             gboolean     install_handler)
7009 {
7010   tree_view->priv->mark_rows_col_dirty = TRUE;
7011
7012   if (install_handler)
7013     install_presize_handler (tree_view);
7014 }
7015
7016 /*
7017  * This function works synchronously (due to the while (validate_rows...)
7018  * loop).
7019  *
7020  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
7021  * here. You now need to check that yourself.
7022  */
7023 void
7024 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
7025                                 GtkTreeViewColumn *column)
7026 {
7027   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7028   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
7029
7030   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
7031
7032   do_presize_handler (tree_view);
7033   while (validate_rows (tree_view));
7034
7035   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7036 }
7037
7038 /* Drag-and-drop */
7039
7040 static void
7041 set_source_row (GdkDragContext *context,
7042                 GtkTreeModel   *model,
7043                 GtkTreePath    *source_row)
7044 {
7045   g_object_set_data_full (G_OBJECT (context),
7046                           I_("gtk-tree-view-source-row"),
7047                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7048                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7049 }
7050
7051 static GtkTreePath*
7052 get_source_row (GdkDragContext *context)
7053 {
7054   GtkTreeRowReference *ref =
7055     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7056
7057   if (ref)
7058     return gtk_tree_row_reference_get_path (ref);
7059   else
7060     return NULL;
7061 }
7062
7063 typedef struct
7064 {
7065   GtkTreeRowReference *dest_row;
7066   guint                path_down_mode   : 1;
7067   guint                empty_view_drop  : 1;
7068   guint                drop_append_mode : 1;
7069 }
7070 DestRow;
7071
7072 static void
7073 dest_row_free (gpointer data)
7074 {
7075   DestRow *dr = (DestRow *)data;
7076
7077   gtk_tree_row_reference_free (dr->dest_row);
7078   g_slice_free (DestRow, dr);
7079 }
7080
7081 static void
7082 set_dest_row (GdkDragContext *context,
7083               GtkTreeModel   *model,
7084               GtkTreePath    *dest_row,
7085               gboolean        path_down_mode,
7086               gboolean        empty_view_drop,
7087               gboolean        drop_append_mode)
7088 {
7089   DestRow *dr;
7090
7091   if (!dest_row)
7092     {
7093       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7094                               NULL, NULL);
7095       return;
7096     }
7097
7098   dr = g_slice_new (DestRow);
7099
7100   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7101   dr->path_down_mode = path_down_mode != FALSE;
7102   dr->empty_view_drop = empty_view_drop != FALSE;
7103   dr->drop_append_mode = drop_append_mode != FALSE;
7104
7105   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7106                           dr, (GDestroyNotify) dest_row_free);
7107 }
7108
7109 static GtkTreePath*
7110 get_dest_row (GdkDragContext *context,
7111               gboolean       *path_down_mode)
7112 {
7113   DestRow *dr =
7114     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7115
7116   if (dr)
7117     {
7118       GtkTreePath *path = NULL;
7119
7120       if (path_down_mode)
7121         *path_down_mode = dr->path_down_mode;
7122
7123       if (dr->dest_row)
7124         path = gtk_tree_row_reference_get_path (dr->dest_row);
7125       else if (dr->empty_view_drop)
7126         path = gtk_tree_path_new_from_indices (0, -1);
7127       else
7128         path = NULL;
7129
7130       if (path && dr->drop_append_mode)
7131         gtk_tree_path_next (path);
7132
7133       return path;
7134     }
7135   else
7136     return NULL;
7137 }
7138
7139 /* Get/set whether drag_motion requested the drag data and
7140  * drag_data_received should thus not actually insert the data,
7141  * since the data doesn't result from a drop.
7142  */
7143 static void
7144 set_status_pending (GdkDragContext *context,
7145                     GdkDragAction   suggested_action)
7146 {
7147   g_object_set_data (G_OBJECT (context),
7148                      I_("gtk-tree-view-status-pending"),
7149                      GINT_TO_POINTER (suggested_action));
7150 }
7151
7152 static GdkDragAction
7153 get_status_pending (GdkDragContext *context)
7154 {
7155   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7156                                              "gtk-tree-view-status-pending"));
7157 }
7158
7159 static TreeViewDragInfo*
7160 get_info (GtkTreeView *tree_view)
7161 {
7162   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7163 }
7164
7165 static void
7166 destroy_info (TreeViewDragInfo *di)
7167 {
7168   g_slice_free (TreeViewDragInfo, di);
7169 }
7170
7171 static TreeViewDragInfo*
7172 ensure_info (GtkTreeView *tree_view)
7173 {
7174   TreeViewDragInfo *di;
7175
7176   di = get_info (tree_view);
7177
7178   if (di == NULL)
7179     {
7180       di = g_slice_new0 (TreeViewDragInfo);
7181
7182       g_object_set_data_full (G_OBJECT (tree_view),
7183                               I_("gtk-tree-view-drag-info"),
7184                               di,
7185                               (GDestroyNotify) destroy_info);
7186     }
7187
7188   return di;
7189 }
7190
7191 static void
7192 remove_info (GtkTreeView *tree_view)
7193 {
7194   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7195 }
7196
7197 #if 0
7198 static gint
7199 drag_scan_timeout (gpointer data)
7200 {
7201   GtkTreeView *tree_view;
7202   gint x, y;
7203   GdkModifierType state;
7204   GtkTreePath *path = NULL;
7205   GtkTreeViewColumn *column = NULL;
7206   GdkRectangle visible_rect;
7207
7208   GDK_THREADS_ENTER ();
7209
7210   tree_view = GTK_TREE_VIEW (data);
7211
7212   gdk_window_get_pointer (tree_view->priv->bin_window,
7213                           &x, &y, &state);
7214
7215   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7216
7217   /* See if we are near the edge. */
7218   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7219       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7220       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7221       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7222     {
7223       gtk_tree_view_get_path_at_pos (tree_view,
7224                                      tree_view->priv->bin_window,
7225                                      x, y,
7226                                      &path,
7227                                      &column,
7228                                      NULL,
7229                                      NULL);
7230
7231       if (path != NULL)
7232         {
7233           gtk_tree_view_scroll_to_cell (tree_view,
7234                                         path,
7235                                         column,
7236                                         TRUE,
7237                                         0.5, 0.5);
7238
7239           gtk_tree_path_free (path);
7240         }
7241     }
7242
7243   GDK_THREADS_LEAVE ();
7244
7245   return TRUE;
7246 }
7247 #endif /* 0 */
7248
7249 static void
7250 add_scroll_timeout (GtkTreeView *tree_view)
7251 {
7252   if (tree_view->priv->scroll_timeout == 0)
7253     {
7254       tree_view->priv->scroll_timeout =
7255         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7256     }
7257 }
7258
7259 static void
7260 remove_scroll_timeout (GtkTreeView *tree_view)
7261 {
7262   if (tree_view->priv->scroll_timeout != 0)
7263     {
7264       g_source_remove (tree_view->priv->scroll_timeout);
7265       tree_view->priv->scroll_timeout = 0;
7266     }
7267 }
7268
7269 static gboolean
7270 check_model_dnd (GtkTreeModel *model,
7271                  GType         required_iface,
7272                  const gchar  *signal)
7273 {
7274   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7275     {
7276       g_warning ("You must override the default '%s' handler "
7277                  "on GtkTreeView when using models that don't support "
7278                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7279                  "is to connect to '%s' and call "
7280                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7281                  "the default handler from running. Look at the source code "
7282                  "for the default handler in gtktreeview.c to get an idea what "
7283                  "your handler should do. (gtktreeview.c is in the GTK source "
7284                  "code.) If you're using GTK from a language other than C, "
7285                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7286                  signal, g_type_name (required_iface), signal);
7287       return FALSE;
7288     }
7289   else
7290     return TRUE;
7291 }
7292
7293 static void
7294 remove_open_timeout (GtkTreeView *tree_view)
7295 {
7296   if (tree_view->priv->open_dest_timeout != 0)
7297     {
7298       g_source_remove (tree_view->priv->open_dest_timeout);
7299       tree_view->priv->open_dest_timeout = 0;
7300     }
7301 }
7302
7303
7304 static gint
7305 open_row_timeout (gpointer data)
7306 {
7307   GtkTreeView *tree_view = data;
7308   GtkTreePath *dest_path = NULL;
7309   GtkTreeViewDropPosition pos;
7310   gboolean result = FALSE;
7311
7312   gtk_tree_view_get_drag_dest_row (tree_view,
7313                                    &dest_path,
7314                                    &pos);
7315
7316   if (dest_path &&
7317       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7318        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7319     {
7320       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7321       tree_view->priv->open_dest_timeout = 0;
7322
7323       gtk_tree_path_free (dest_path);
7324     }
7325   else
7326     {
7327       if (dest_path)
7328         gtk_tree_path_free (dest_path);
7329
7330       result = TRUE;
7331     }
7332
7333   return result;
7334 }
7335
7336 static gboolean
7337 scroll_row_timeout (gpointer data)
7338 {
7339   GtkTreeView *tree_view = data;
7340
7341   gtk_tree_view_vertical_autoscroll (tree_view);
7342
7343   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7344     gtk_tree_view_update_rubber_band (tree_view);
7345
7346   return TRUE;
7347 }
7348
7349 /* Returns TRUE if event should not be propagated to parent widgets */
7350 static gboolean
7351 set_destination_row (GtkTreeView    *tree_view,
7352                      GdkDragContext *context,
7353                      /* coordinates relative to the widget */
7354                      gint            x,
7355                      gint            y,
7356                      GdkDragAction  *suggested_action,
7357                      GdkAtom        *target)
7358 {
7359   GtkTreePath *path = NULL;
7360   GtkTreeViewDropPosition pos;
7361   GtkTreeViewDropPosition old_pos;
7362   TreeViewDragInfo *di;
7363   GtkWidget *widget;
7364   GtkTreePath *old_dest_path = NULL;
7365   gboolean can_drop = FALSE;
7366
7367   *suggested_action = 0;
7368   *target = GDK_NONE;
7369
7370   widget = GTK_WIDGET (tree_view);
7371
7372   di = get_info (tree_view);
7373
7374   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7375     {
7376       /* someone unset us as a drag dest, note that if
7377        * we return FALSE drag_leave isn't called
7378        */
7379
7380       gtk_tree_view_set_drag_dest_row (tree_view,
7381                                        NULL,
7382                                        GTK_TREE_VIEW_DROP_BEFORE);
7383
7384       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7385       remove_open_timeout (GTK_TREE_VIEW (widget));
7386
7387       return FALSE; /* no longer a drop site */
7388     }
7389
7390   *target = gtk_drag_dest_find_target (widget, context,
7391                                        gtk_drag_dest_get_target_list (widget));
7392   if (*target == GDK_NONE)
7393     {
7394       return FALSE;
7395     }
7396
7397   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7398                                           x, y,
7399                                           &path,
7400                                           &pos))
7401     {
7402       gint n_children;
7403       GtkTreeModel *model;
7404
7405       remove_open_timeout (tree_view);
7406
7407       /* the row got dropped on empty space, let's setup a special case
7408        */
7409
7410       if (path)
7411         gtk_tree_path_free (path);
7412
7413       model = gtk_tree_view_get_model (tree_view);
7414
7415       n_children = gtk_tree_model_iter_n_children (model, NULL);
7416       if (n_children)
7417         {
7418           pos = GTK_TREE_VIEW_DROP_AFTER;
7419           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7420         }
7421       else
7422         {
7423           pos = GTK_TREE_VIEW_DROP_BEFORE;
7424           path = gtk_tree_path_new_from_indices (0, -1);
7425         }
7426
7427       can_drop = TRUE;
7428
7429       goto out;
7430     }
7431
7432   g_assert (path);
7433
7434   /* If we left the current row's "open" zone, unset the timeout for
7435    * opening the row
7436    */
7437   gtk_tree_view_get_drag_dest_row (tree_view,
7438                                    &old_dest_path,
7439                                    &old_pos);
7440
7441   if (old_dest_path &&
7442       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7443        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7444          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7445     remove_open_timeout (tree_view);
7446
7447   if (old_dest_path)
7448     gtk_tree_path_free (old_dest_path);
7449
7450   if (TRUE /* FIXME if the location droppable predicate */)
7451     {
7452       can_drop = TRUE;
7453     }
7454
7455 out:
7456   if (can_drop)
7457     {
7458       GtkWidget *source_widget;
7459
7460       *suggested_action = context->suggested_action;
7461       source_widget = gtk_drag_get_source_widget (context);
7462
7463       if (source_widget == widget)
7464         {
7465           /* Default to MOVE, unless the user has
7466            * pressed ctrl or shift to affect available actions
7467            */
7468           if ((context->actions & GDK_ACTION_MOVE) != 0)
7469             *suggested_action = GDK_ACTION_MOVE;
7470         }
7471
7472       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7473                                        path, pos);
7474     }
7475   else
7476     {
7477       /* can't drop here */
7478       remove_open_timeout (tree_view);
7479
7480       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7481                                        NULL,
7482                                        GTK_TREE_VIEW_DROP_BEFORE);
7483     }
7484
7485   if (path)
7486     gtk_tree_path_free (path);
7487
7488   return TRUE;
7489 }
7490
7491 static GtkTreePath*
7492 get_logical_dest_row (GtkTreeView *tree_view,
7493                       gboolean    *path_down_mode,
7494                       gboolean    *drop_append_mode)
7495 {
7496   /* adjust path to point to the row the drop goes in front of */
7497   GtkTreePath *path = NULL;
7498   GtkTreeViewDropPosition pos;
7499
7500   g_return_val_if_fail (path_down_mode != NULL, NULL);
7501   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7502
7503   *path_down_mode = FALSE;
7504   *drop_append_mode = 0;
7505
7506   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7507
7508   if (path == NULL)
7509     return NULL;
7510
7511   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7512     ; /* do nothing */
7513   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7514            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7515     *path_down_mode = TRUE;
7516   else
7517     {
7518       GtkTreeIter iter;
7519       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7520
7521       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7522
7523       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7524           !gtk_tree_model_iter_next (model, &iter))
7525         *drop_append_mode = 1;
7526       else
7527         {
7528           *drop_append_mode = 0;
7529           gtk_tree_path_next (path);
7530         }
7531     }
7532
7533   return path;
7534 }
7535
7536 static gboolean
7537 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7538                                         GdkEventMotion   *event)
7539 {
7540   GtkWidget *widget = GTK_WIDGET (tree_view);
7541   GdkDragContext *context;
7542   TreeViewDragInfo *di;
7543   GtkTreePath *path = NULL;
7544   gint button;
7545   gint cell_x, cell_y;
7546   GtkTreeModel *model;
7547   gboolean retval = FALSE;
7548
7549   di = get_info (tree_view);
7550
7551   if (di == NULL || !di->source_set)
7552     goto out;
7553
7554   if (tree_view->priv->pressed_button < 0)
7555     goto out;
7556
7557   if (!gtk_drag_check_threshold (widget,
7558                                  tree_view->priv->press_start_x,
7559                                  tree_view->priv->press_start_y,
7560                                  event->x, event->y))
7561     goto out;
7562
7563   model = gtk_tree_view_get_model (tree_view);
7564
7565   if (model == NULL)
7566     goto out;
7567
7568   button = tree_view->priv->pressed_button;
7569   tree_view->priv->pressed_button = -1;
7570
7571   gtk_tree_view_get_path_at_pos (tree_view,
7572                                  tree_view->priv->press_start_x,
7573                                  tree_view->priv->press_start_y,
7574                                  &path,
7575                                  NULL,
7576                                  &cell_x,
7577                                  &cell_y);
7578
7579   if (path == NULL)
7580     goto out;
7581
7582   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7583       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7584                                            path))
7585     goto out;
7586
7587   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7588     goto out;
7589
7590   /* Now we can begin the drag */
7591
7592   retval = TRUE;
7593
7594   context = gtk_drag_begin (widget,
7595                             gtk_drag_source_get_target_list (widget),
7596                             di->source_actions,
7597                             button,
7598                             (GdkEvent*)event);
7599
7600   set_source_row (context, model, path);
7601
7602  out:
7603   if (path)
7604     gtk_tree_path_free (path);
7605
7606   return retval;
7607 }
7608
7609
7610 static void
7611 gtk_tree_view_drag_begin (GtkWidget      *widget,
7612                           GdkDragContext *context)
7613 {
7614   GtkTreeView *tree_view;
7615   GtkTreePath *path = NULL;
7616   gint cell_x, cell_y;
7617   cairo_surface_t *row_pix;
7618   TreeViewDragInfo *di;
7619
7620   tree_view = GTK_TREE_VIEW (widget);
7621
7622   /* if the user uses a custom DND source impl, we don't set the icon here */
7623   di = get_info (tree_view);
7624
7625   if (di == NULL || !di->source_set)
7626     return;
7627
7628   gtk_tree_view_get_path_at_pos (tree_view,
7629                                  tree_view->priv->press_start_x,
7630                                  tree_view->priv->press_start_y,
7631                                  &path,
7632                                  NULL,
7633                                  &cell_x,
7634                                  &cell_y);
7635
7636   g_return_if_fail (path != NULL);
7637
7638   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7639                                                 path);
7640   cairo_surface_set_device_offset (row_pix,
7641                                    /* the + 1 is for the black border in the icon */
7642                                    - (tree_view->priv->press_start_x + 1),
7643                                    - (cell_y + 1));
7644
7645   gtk_drag_set_icon_surface (context, row_pix);
7646
7647   cairo_surface_destroy (row_pix);
7648   gtk_tree_path_free (path);
7649 }
7650
7651 static void
7652 gtk_tree_view_drag_end (GtkWidget      *widget,
7653                         GdkDragContext *context)
7654 {
7655   /* do nothing */
7656 }
7657
7658 /* Default signal implementations for the drag signals */
7659 static void
7660 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7661                              GdkDragContext   *context,
7662                              GtkSelectionData *selection_data,
7663                              guint             info,
7664                              guint             time)
7665 {
7666   GtkTreeView *tree_view;
7667   GtkTreeModel *model;
7668   TreeViewDragInfo *di;
7669   GtkTreePath *source_row;
7670
7671   tree_view = GTK_TREE_VIEW (widget);
7672
7673   model = gtk_tree_view_get_model (tree_view);
7674
7675   if (model == NULL)
7676     return;
7677
7678   di = get_info (GTK_TREE_VIEW (widget));
7679
7680   if (di == NULL)
7681     return;
7682
7683   source_row = get_source_row (context);
7684
7685   if (source_row == NULL)
7686     return;
7687
7688   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7689    * any model; for DragSource models there are some other targets
7690    * we also support.
7691    */
7692
7693   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7694       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7695                                           source_row,
7696                                           selection_data))
7697     goto done;
7698
7699   /* If drag_data_get does nothing, try providing row data. */
7700   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7701     {
7702       gtk_tree_set_row_drag_data (selection_data,
7703                                   model,
7704                                   source_row);
7705     }
7706
7707  done:
7708   gtk_tree_path_free (source_row);
7709 }
7710
7711
7712 static void
7713 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7714                                 GdkDragContext *context)
7715 {
7716   TreeViewDragInfo *di;
7717   GtkTreeModel *model;
7718   GtkTreeView *tree_view;
7719   GtkTreePath *source_row;
7720
7721   tree_view = GTK_TREE_VIEW (widget);
7722   model = gtk_tree_view_get_model (tree_view);
7723
7724   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7725     return;
7726
7727   di = get_info (tree_view);
7728
7729   if (di == NULL)
7730     return;
7731
7732   source_row = get_source_row (context);
7733
7734   if (source_row == NULL)
7735     return;
7736
7737   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7738                                          source_row);
7739
7740   gtk_tree_path_free (source_row);
7741
7742   set_source_row (context, NULL, NULL);
7743 }
7744
7745 static void
7746 gtk_tree_view_drag_leave (GtkWidget      *widget,
7747                           GdkDragContext *context,
7748                           guint             time)
7749 {
7750   /* unset any highlight row */
7751   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7752                                    NULL,
7753                                    GTK_TREE_VIEW_DROP_BEFORE);
7754
7755   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7756   remove_open_timeout (GTK_TREE_VIEW (widget));
7757 }
7758
7759
7760 static gboolean
7761 gtk_tree_view_drag_motion (GtkWidget        *widget,
7762                            GdkDragContext   *context,
7763                            /* coordinates relative to the widget */
7764                            gint              x,
7765                            gint              y,
7766                            guint             time)
7767 {
7768   gboolean empty;
7769   GtkTreePath *path = NULL;
7770   GtkTreeViewDropPosition pos;
7771   GtkTreeView *tree_view;
7772   GdkDragAction suggested_action = 0;
7773   GdkAtom target;
7774
7775   tree_view = GTK_TREE_VIEW (widget);
7776
7777   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7778     return FALSE;
7779
7780   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7781
7782   /* we only know this *after* set_desination_row */
7783   empty = tree_view->priv->empty_view_drop;
7784
7785   if (path == NULL && !empty)
7786     {
7787       /* Can't drop here. */
7788       gdk_drag_status (context, 0, time);
7789     }
7790   else
7791     {
7792       if (tree_view->priv->open_dest_timeout == 0 &&
7793           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7794            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7795         {
7796           tree_view->priv->open_dest_timeout =
7797             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7798         }
7799       else
7800         {
7801           add_scroll_timeout (tree_view);
7802         }
7803
7804       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7805         {
7806           /* Request data so we can use the source row when
7807            * determining whether to accept the drop
7808            */
7809           set_status_pending (context, suggested_action);
7810           gtk_drag_get_data (widget, context, target, time);
7811         }
7812       else
7813         {
7814           set_status_pending (context, 0);
7815           gdk_drag_status (context, suggested_action, time);
7816         }
7817     }
7818
7819   if (path)
7820     gtk_tree_path_free (path);
7821
7822   return TRUE;
7823 }
7824
7825
7826 static gboolean
7827 gtk_tree_view_drag_drop (GtkWidget        *widget,
7828                          GdkDragContext   *context,
7829                          /* coordinates relative to the widget */
7830                          gint              x,
7831                          gint              y,
7832                          guint             time)
7833 {
7834   GtkTreeView *tree_view;
7835   GtkTreePath *path;
7836   GdkDragAction suggested_action = 0;
7837   GdkAtom target = GDK_NONE;
7838   TreeViewDragInfo *di;
7839   GtkTreeModel *model;
7840   gboolean path_down_mode;
7841   gboolean drop_append_mode;
7842
7843   tree_view = GTK_TREE_VIEW (widget);
7844
7845   model = gtk_tree_view_get_model (tree_view);
7846
7847   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7848   remove_open_timeout (GTK_TREE_VIEW (widget));
7849
7850   di = get_info (tree_view);
7851
7852   if (di == NULL)
7853     return FALSE;
7854
7855   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7856     return FALSE;
7857
7858   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7859     return FALSE;
7860
7861   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7862
7863   if (target != GDK_NONE && path != NULL)
7864     {
7865       /* in case a motion had requested drag data, change things so we
7866        * treat drag data receives as a drop.
7867        */
7868       set_status_pending (context, 0);
7869       set_dest_row (context, model, path,
7870                     path_down_mode, tree_view->priv->empty_view_drop,
7871                     drop_append_mode);
7872     }
7873
7874   if (path)
7875     gtk_tree_path_free (path);
7876
7877   /* Unset this thing */
7878   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7879                                    NULL,
7880                                    GTK_TREE_VIEW_DROP_BEFORE);
7881
7882   if (target != GDK_NONE)
7883     {
7884       gtk_drag_get_data (widget, context, target, time);
7885       return TRUE;
7886     }
7887   else
7888     return FALSE;
7889 }
7890
7891 static void
7892 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7893                                   GdkDragContext   *context,
7894                                   /* coordinates relative to the widget */
7895                                   gint              x,
7896                                   gint              y,
7897                                   GtkSelectionData *selection_data,
7898                                   guint             info,
7899                                   guint             time)
7900 {
7901   GtkTreePath *path;
7902   TreeViewDragInfo *di;
7903   gboolean accepted = FALSE;
7904   GtkTreeModel *model;
7905   GtkTreeView *tree_view;
7906   GtkTreePath *dest_row;
7907   GdkDragAction suggested_action;
7908   gboolean path_down_mode;
7909   gboolean drop_append_mode;
7910
7911   tree_view = GTK_TREE_VIEW (widget);
7912
7913   model = gtk_tree_view_get_model (tree_view);
7914
7915   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7916     return;
7917
7918   di = get_info (tree_view);
7919
7920   if (di == NULL)
7921     return;
7922
7923   suggested_action = get_status_pending (context);
7924
7925   if (suggested_action)
7926     {
7927       /* We are getting this data due to a request in drag_motion,
7928        * rather than due to a request in drag_drop, so we are just
7929        * supposed to call drag_status, not actually paste in the
7930        * data.
7931        */
7932       path = get_logical_dest_row (tree_view, &path_down_mode,
7933                                    &drop_append_mode);
7934
7935       if (path == NULL)
7936         suggested_action = 0;
7937       else if (path_down_mode)
7938         gtk_tree_path_down (path);
7939
7940       if (suggested_action)
7941         {
7942           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7943                                                      path,
7944                                                      selection_data))
7945             {
7946               if (path_down_mode)
7947                 {
7948                   path_down_mode = FALSE;
7949                   gtk_tree_path_up (path);
7950
7951                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7952                                                              path,
7953                                                              selection_data))
7954                     suggested_action = 0;
7955                 }
7956               else
7957                 suggested_action = 0;
7958             }
7959         }
7960
7961       gdk_drag_status (context, suggested_action, time);
7962
7963       if (path)
7964         gtk_tree_path_free (path);
7965
7966       /* If you can't drop, remove user drop indicator until the next motion */
7967       if (suggested_action == 0)
7968         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7969                                          NULL,
7970                                          GTK_TREE_VIEW_DROP_BEFORE);
7971
7972       return;
7973     }
7974
7975   dest_row = get_dest_row (context, &path_down_mode);
7976
7977   if (dest_row == NULL)
7978     return;
7979
7980   if (selection_data->length >= 0)
7981     {
7982       if (path_down_mode)
7983         {
7984           gtk_tree_path_down (dest_row);
7985           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7986                                                      dest_row, selection_data))
7987             gtk_tree_path_up (dest_row);
7988         }
7989     }
7990
7991   if (selection_data->length >= 0)
7992     {
7993       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7994                                                  dest_row,
7995                                                  selection_data))
7996         accepted = TRUE;
7997     }
7998
7999   gtk_drag_finish (context,
8000                    accepted,
8001                    (context->action == GDK_ACTION_MOVE),
8002                    time);
8003
8004   if (gtk_tree_path_get_depth (dest_row) == 1
8005       && gtk_tree_path_get_indices (dest_row)[0] == 0)
8006     {
8007       /* special special case drag to "0", scroll to first item */
8008       if (!tree_view->priv->scroll_to_path)
8009         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
8010     }
8011
8012   gtk_tree_path_free (dest_row);
8013
8014   /* drop dest_row */
8015   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
8016 }
8017
8018
8019
8020 /* GtkContainer Methods
8021  */
8022
8023
8024 static void
8025 gtk_tree_view_remove (GtkContainer *container,
8026                       GtkWidget    *widget)
8027 {
8028   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8029   GtkTreeViewChild *child = NULL;
8030   GList *tmp_list;
8031
8032   tmp_list = tree_view->priv->children;
8033   while (tmp_list)
8034     {
8035       child = tmp_list->data;
8036       if (child->widget == widget)
8037         {
8038           gtk_widget_unparent (widget);
8039
8040           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
8041           g_list_free_1 (tmp_list);
8042           g_slice_free (GtkTreeViewChild, child);
8043           return;
8044         }
8045
8046       tmp_list = tmp_list->next;
8047     }
8048
8049   tmp_list = tree_view->priv->columns;
8050
8051   while (tmp_list)
8052     {
8053       GtkTreeViewColumn *column;
8054       GtkWidget         *button;
8055
8056       column = tmp_list->data;
8057       button = gtk_tree_view_column_get_button (column);
8058
8059       if (button == widget)
8060         {
8061           gtk_widget_unparent (widget);
8062           return;
8063         }
8064       tmp_list = tmp_list->next;
8065     }
8066 }
8067
8068 static void
8069 gtk_tree_view_forall (GtkContainer *container,
8070                       gboolean      include_internals,
8071                       GtkCallback   callback,
8072                       gpointer      callback_data)
8073 {
8074   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8075   GtkTreeViewChild *child = NULL;
8076   GtkTreeViewColumn *column;
8077   GtkWidget *button;
8078   GList *tmp_list;
8079
8080   tmp_list = tree_view->priv->children;
8081   while (tmp_list)
8082     {
8083       child = tmp_list->data;
8084       tmp_list = tmp_list->next;
8085
8086       (* callback) (child->widget, callback_data);
8087     }
8088   if (include_internals == FALSE)
8089     return;
8090
8091   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8092     {
8093       column = tmp_list->data;
8094       button = gtk_tree_view_column_get_button (column);
8095
8096       if (button)
8097         (* callback) (button, callback_data);
8098     }
8099 }
8100
8101 /* Returns TRUE is any of the columns contains a cell that can-focus.
8102  * If this is not the case, a column-spanning focus rectangle will be
8103  * drawn.
8104  */
8105 static gboolean
8106 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8107 {
8108   GList *list;
8109
8110   for (list = tree_view->priv->columns; list; list = list->next)
8111     {
8112       GtkTreeViewColumn *column = list->data;
8113
8114       if (!gtk_tree_view_column_get_visible (column))
8115         continue;
8116       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8117         return TRUE;
8118     }
8119
8120   return FALSE;
8121 }
8122
8123 static void
8124 column_sizing_notify (GObject    *object,
8125                       GParamSpec *pspec,
8126                       gpointer    data)
8127 {
8128   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8129
8130   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8131     /* disable fixed height mode */
8132     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8133 }
8134
8135 /**
8136  * gtk_tree_view_set_fixed_height_mode:
8137  * @tree_view: a #GtkTreeView 
8138  * @enable: %TRUE to enable fixed height mode
8139  * 
8140  * Enables or disables the fixed height mode of @tree_view. 
8141  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8142  * rows have the same height. 
8143  * Only enable this option if all rows are the same height and all
8144  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8145  *
8146  * Since: 2.6 
8147  **/
8148 void
8149 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8150                                      gboolean     enable)
8151 {
8152   GList *l;
8153   
8154   enable = enable != FALSE;
8155
8156   if (enable == tree_view->priv->fixed_height_mode)
8157     return;
8158
8159   if (!enable)
8160     {
8161       tree_view->priv->fixed_height_mode = 0;
8162       tree_view->priv->fixed_height = -1;
8163
8164       /* force a revalidation */
8165       install_presize_handler (tree_view);
8166     }
8167   else 
8168     {
8169       /* make sure all columns are of type FIXED */
8170       for (l = tree_view->priv->columns; l; l = l->next)
8171         {
8172           GtkTreeViewColumn *c = l->data;
8173           
8174           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8175         }
8176       
8177       /* yes, we really have to do this is in a separate loop */
8178       for (l = tree_view->priv->columns; l; l = l->next)
8179         g_signal_connect (l->data, "notify::sizing",
8180                           G_CALLBACK (column_sizing_notify), tree_view);
8181       
8182       tree_view->priv->fixed_height_mode = 1;
8183       tree_view->priv->fixed_height = -1;
8184       
8185       if (tree_view->priv->tree)
8186         initialize_fixed_height_mode (tree_view);
8187     }
8188
8189   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8190 }
8191
8192 /**
8193  * gtk_tree_view_get_fixed_height_mode:
8194  * @tree_view: a #GtkTreeView
8195  * 
8196  * Returns whether fixed height mode is turned on for @tree_view.
8197  * 
8198  * Return value: %TRUE if @tree_view is in fixed height mode
8199  * 
8200  * Since: 2.6
8201  **/
8202 gboolean
8203 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8204 {
8205   return tree_view->priv->fixed_height_mode;
8206 }
8207
8208 /* Returns TRUE if the focus is within the headers, after the focus operation is
8209  * done
8210  */
8211 static gboolean
8212 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8213                             GtkDirectionType  dir,
8214                             gboolean          clamp_column_visible)
8215 {
8216   GtkTreeViewColumn *column;
8217   GtkWidget *focus_child;
8218   GtkWidget *button;
8219   GList *last_column, *first_column;
8220   GList *tmp_list;
8221   gboolean rtl;
8222
8223   if (! tree_view->priv->headers_visible)
8224     return FALSE;
8225
8226   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8227
8228   first_column = tree_view->priv->columns;
8229   while (first_column)
8230     {
8231       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8232       button = gtk_tree_view_column_get_button (column);
8233
8234       if (gtk_widget_get_can_focus (button) &&
8235           gtk_tree_view_column_get_visible (column) &&
8236           (gtk_tree_view_column_get_clickable (column) ||
8237            gtk_tree_view_column_get_reorderable (column)))
8238         break;
8239       first_column = first_column->next;
8240     }
8241
8242   /* No headers are visible, or are focusable.  We can't focus in or out.
8243    */
8244   if (first_column == NULL)
8245     return FALSE;
8246
8247   last_column = g_list_last (tree_view->priv->columns);
8248   while (last_column)
8249     {
8250       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8251       button = gtk_tree_view_column_get_button (column);
8252
8253       if (gtk_widget_get_can_focus (button) &&
8254           gtk_tree_view_column_get_visible (column) &&
8255           (gtk_tree_view_column_get_clickable (column) ||
8256            gtk_tree_view_column_get_reorderable (column)))
8257         break;
8258       last_column = last_column->prev;
8259     }
8260
8261
8262   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8263
8264   switch (dir)
8265     {
8266     case GTK_DIR_TAB_BACKWARD:
8267     case GTK_DIR_TAB_FORWARD:
8268     case GTK_DIR_UP:
8269     case GTK_DIR_DOWN:
8270       if (focus_child == NULL)
8271         {
8272           if (tree_view->priv->focus_column != NULL)
8273             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8274           else 
8275             button = NULL;
8276
8277           if (button && gtk_widget_get_can_focus (button))
8278             focus_child = button;
8279           else
8280             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8281
8282           gtk_widget_grab_focus (focus_child);
8283           break;
8284         }
8285       return FALSE;
8286
8287     case GTK_DIR_LEFT:
8288     case GTK_DIR_RIGHT:
8289       if (focus_child == NULL)
8290         {
8291           if (tree_view->priv->focus_column != NULL)
8292             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8293           else if (dir == GTK_DIR_LEFT)
8294             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8295           else
8296             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8297
8298           gtk_widget_grab_focus (focus_child);
8299           break;
8300         }
8301
8302       if (gtk_widget_child_focus (focus_child, dir))
8303         {
8304           /* The focus moves inside the button. */
8305           /* This is probably a great example of bad UI */
8306           break;
8307         }
8308
8309       /* We need to move the focus among the row of buttons. */
8310       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8311         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8312           break;
8313
8314       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8315           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8316         {
8317           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8318           break;
8319         }
8320
8321       while (tmp_list)
8322         {
8323           GtkTreeViewColumn *column;
8324           GtkWidget         *button;
8325
8326           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8327             tmp_list = tmp_list->next;
8328           else
8329             tmp_list = tmp_list->prev;
8330
8331           if (tmp_list == NULL)
8332             {
8333               g_warning ("Internal button not found");
8334               break;
8335             }
8336           column = tmp_list->data;
8337           button = gtk_tree_view_column_get_button (column);
8338           if (button &&
8339               gtk_tree_view_column_get_visible (column) &&
8340               gtk_widget_get_can_focus (button))
8341             {
8342               focus_child = button;
8343               gtk_widget_grab_focus (button);
8344               break;
8345             }
8346         }
8347       break;
8348     default:
8349       g_assert_not_reached ();
8350       break;
8351     }
8352
8353   /* if focus child is non-null, we assume it's been set to the current focus child
8354    */
8355   if (focus_child)
8356     {
8357       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8358         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8359           {
8360             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8361             break;
8362           }
8363
8364       if (clamp_column_visible)
8365         {
8366           gtk_tree_view_clamp_column_visible (tree_view,
8367                                               tree_view->priv->focus_column,
8368                                               FALSE);
8369         }
8370     }
8371
8372   return (focus_child != NULL);
8373 }
8374
8375 /* This function returns in 'path' the first focusable path, if the given path
8376  * is already focusable, it's the returned one.
8377  */
8378 static gboolean
8379 search_first_focusable_path (GtkTreeView  *tree_view,
8380                              GtkTreePath **path,
8381                              gboolean      search_forward,
8382                              GtkRBTree   **new_tree,
8383                              GtkRBNode   **new_node)
8384 {
8385   GtkRBTree *tree = NULL;
8386   GtkRBNode *node = NULL;
8387
8388   if (!path || !*path)
8389     return FALSE;
8390
8391   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8392
8393   if (!tree || !node)
8394     return FALSE;
8395
8396   while (node && row_is_separator (tree_view, NULL, *path))
8397     {
8398       if (search_forward)
8399         _gtk_rbtree_next_full (tree, node, &tree, &node);
8400       else
8401         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8402
8403       if (*path)
8404         gtk_tree_path_free (*path);
8405
8406       if (node)
8407         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8408       else
8409         *path = NULL;
8410     }
8411
8412   if (new_tree)
8413     *new_tree = tree;
8414
8415   if (new_node)
8416     *new_node = node;
8417
8418   return (*path != NULL);
8419 }
8420
8421 static gint
8422 gtk_tree_view_focus (GtkWidget        *widget,
8423                      GtkDirectionType  direction)
8424 {
8425   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8426   GtkContainer *container = GTK_CONTAINER (widget);
8427   GtkWidget *focus_child;
8428
8429   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8430     return FALSE;
8431
8432   focus_child = gtk_container_get_focus_child (container);
8433
8434   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8435   /* Case 1.  Headers currently have focus. */
8436   if (focus_child)
8437     {
8438       switch (direction)
8439         {
8440         case GTK_DIR_LEFT:
8441         case GTK_DIR_RIGHT:
8442           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8443           return TRUE;
8444         case GTK_DIR_TAB_BACKWARD:
8445         case GTK_DIR_UP:
8446           return FALSE;
8447         case GTK_DIR_TAB_FORWARD:
8448         case GTK_DIR_DOWN:
8449           gtk_widget_grab_focus (widget);
8450           return TRUE;
8451         default:
8452           g_assert_not_reached ();
8453           return FALSE;
8454         }
8455     }
8456
8457   /* Case 2. We don't have focus at all. */
8458   if (!gtk_widget_has_focus (widget))
8459     {
8460       gtk_widget_grab_focus (widget);
8461       return TRUE;
8462     }
8463
8464   /* Case 3. We have focus already. */
8465   if (direction == GTK_DIR_TAB_BACKWARD)
8466     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8467   else if (direction == GTK_DIR_TAB_FORWARD)
8468     return FALSE;
8469
8470   /* Other directions caught by the keybindings */
8471   gtk_widget_grab_focus (widget);
8472   return TRUE;
8473 }
8474
8475 static void
8476 gtk_tree_view_grab_focus (GtkWidget *widget)
8477 {
8478   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8479
8480   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8481 }
8482
8483 static void
8484 gtk_tree_view_style_set (GtkWidget *widget,
8485                          GtkStyle *previous_style)
8486 {
8487   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8488   GtkStyle *style;
8489   GList *list;
8490   GtkTreeViewColumn *column;
8491
8492   if (gtk_widget_get_realized (widget))
8493     {
8494       style = gtk_widget_get_style (widget);
8495       gdk_window_set_background (tree_view->priv->bin_window,
8496                                  &style->base[gtk_widget_get_state (widget)]);
8497       gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8498
8499       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8500       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8501     }
8502
8503   gtk_widget_style_get (widget,
8504                         "expander-size", &tree_view->priv->expander_size,
8505                         NULL);
8506   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8507
8508   for (list = tree_view->priv->columns; list; list = list->next)
8509     {
8510       column = list->data;
8511       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8512     }
8513
8514   tree_view->priv->fixed_height = -1;
8515   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8516
8517   gtk_widget_queue_resize (widget);
8518 }
8519
8520
8521 static void
8522 gtk_tree_view_set_focus_child (GtkContainer *container,
8523                                GtkWidget    *child)
8524 {
8525   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8526   GList *list;
8527
8528   for (list = tree_view->priv->columns; list; list = list->next)
8529     {
8530       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8531         {
8532           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8533           break;
8534         }
8535     }
8536
8537   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8538 }
8539
8540 static gboolean
8541 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8542                                 GtkMovementStep    step,
8543                                 gint               count)
8544 {
8545   GdkModifierType state;
8546
8547   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8548   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8549                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8550                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8551                         step == GTK_MOVEMENT_PAGES ||
8552                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8553
8554   if (tree_view->priv->tree == NULL)
8555     return FALSE;
8556   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8557     return FALSE;
8558
8559   gtk_tree_view_stop_editing (tree_view, FALSE);
8560   tree_view->priv->draw_keyfocus = TRUE;
8561   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8562
8563   if (gtk_get_current_event_state (&state))
8564     {
8565       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8566         tree_view->priv->ctrl_pressed = TRUE;
8567       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8568         tree_view->priv->shift_pressed = TRUE;
8569     }
8570   /* else we assume not pressed */
8571
8572   switch (step)
8573     {
8574       /* currently we make no distinction.  When we go bi-di, we need to */
8575     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8576     case GTK_MOVEMENT_VISUAL_POSITIONS:
8577       gtk_tree_view_move_cursor_left_right (tree_view, count);
8578       break;
8579     case GTK_MOVEMENT_DISPLAY_LINES:
8580       gtk_tree_view_move_cursor_up_down (tree_view, count);
8581       break;
8582     case GTK_MOVEMENT_PAGES:
8583       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8584       break;
8585     case GTK_MOVEMENT_BUFFER_ENDS:
8586       gtk_tree_view_move_cursor_start_end (tree_view, count);
8587       break;
8588     default:
8589       g_assert_not_reached ();
8590     }
8591
8592   tree_view->priv->ctrl_pressed = FALSE;
8593   tree_view->priv->shift_pressed = FALSE;
8594
8595   return TRUE;
8596 }
8597
8598 static void
8599 gtk_tree_view_put (GtkTreeView *tree_view,
8600                    GtkWidget   *child_widget,
8601                    /* in bin_window coordinates */
8602                    gint         x,
8603                    gint         y,
8604                    gint         width,
8605                    gint         height)
8606 {
8607   GtkTreeViewChild *child;
8608   
8609   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8610   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8611
8612   child = g_slice_new (GtkTreeViewChild);
8613
8614   child->widget = child_widget;
8615   child->x = x;
8616   child->y = y;
8617   child->width = width;
8618   child->height = height;
8619
8620   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8621
8622   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8623     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8624   
8625   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8626 }
8627
8628 void
8629 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8630                                   GtkWidget   *widget,
8631                                   /* in tree coordinates */
8632                                   gint         x,
8633                                   gint         y,
8634                                   gint         width,
8635                                   gint         height)
8636 {
8637   GtkTreeViewChild *child = NULL;
8638   GList *list;
8639   GdkRectangle allocation;
8640
8641   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8642   g_return_if_fail (GTK_IS_WIDGET (widget));
8643
8644   for (list = tree_view->priv->children; list; list = list->next)
8645     {
8646       if (((GtkTreeViewChild *)list->data)->widget == widget)
8647         {
8648           child = list->data;
8649           break;
8650         }
8651     }
8652   if (child == NULL)
8653     return;
8654
8655   allocation.x = child->x = x;
8656   allocation.y = child->y = y;
8657   allocation.width = child->width = width;
8658   allocation.height = child->height = height;
8659
8660   if (gtk_widget_get_realized (widget))
8661     gtk_widget_size_allocate (widget, &allocation);
8662 }
8663
8664
8665 /* TreeModel Callbacks
8666  */
8667
8668 static void
8669 gtk_tree_view_row_changed (GtkTreeModel *model,
8670                            GtkTreePath  *path,
8671                            GtkTreeIter  *iter,
8672                            gpointer      data)
8673 {
8674   GtkTreeView *tree_view = (GtkTreeView *)data;
8675   GtkRBTree *tree;
8676   GtkRBNode *node;
8677   gboolean free_path = FALSE;
8678   GList *list;
8679   GtkTreePath *cursor_path;
8680
8681   g_return_if_fail (path != NULL || iter != NULL);
8682
8683   if (tree_view->priv->cursor != NULL)
8684     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8685   else
8686     cursor_path = NULL;
8687
8688   if (tree_view->priv->edited_column &&
8689       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8690     gtk_tree_view_stop_editing (tree_view, TRUE);
8691
8692   if (cursor_path != NULL)
8693     gtk_tree_path_free (cursor_path);
8694
8695   if (path == NULL)
8696     {
8697       path = gtk_tree_model_get_path (model, iter);
8698       free_path = TRUE;
8699     }
8700   else if (iter == NULL)
8701     gtk_tree_model_get_iter (model, iter, path);
8702
8703   if (_gtk_tree_view_find_node (tree_view,
8704                                 path,
8705                                 &tree,
8706                                 &node))
8707     /* We aren't actually showing the node */
8708     goto done;
8709
8710   if (tree == NULL)
8711     goto done;
8712
8713   if (tree_view->priv->fixed_height_mode
8714       && tree_view->priv->fixed_height >= 0)
8715     {
8716       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8717       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8718         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8719     }
8720   else
8721     {
8722       _gtk_rbtree_node_mark_invalid (tree, node);
8723       for (list = tree_view->priv->columns; list; list = list->next)
8724         {
8725           GtkTreeViewColumn *column;
8726
8727           column = list->data;
8728           if (!gtk_tree_view_column_get_visible (column))
8729             continue;
8730
8731           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8732             {
8733               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8734             }
8735         }
8736     }
8737
8738  done:
8739   if (!tree_view->priv->fixed_height_mode &&
8740       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8741     install_presize_handler (tree_view);
8742   if (free_path)
8743     gtk_tree_path_free (path);
8744 }
8745
8746 static void
8747 gtk_tree_view_row_inserted (GtkTreeModel *model,
8748                             GtkTreePath  *path,
8749                             GtkTreeIter  *iter,
8750                             gpointer      data)
8751 {
8752   GtkTreeView *tree_view = (GtkTreeView *) data;
8753   gint *indices;
8754   GtkRBTree *tmptree, *tree;
8755   GtkRBNode *tmpnode = NULL;
8756   gint depth;
8757   gint i = 0;
8758   gint height;
8759   gboolean free_path = FALSE;
8760   gboolean node_visible = TRUE;
8761
8762   g_return_if_fail (path != NULL || iter != NULL);
8763
8764   if (tree_view->priv->fixed_height_mode
8765       && tree_view->priv->fixed_height >= 0)
8766     height = tree_view->priv->fixed_height;
8767   else
8768     height = 0;
8769
8770   if (path == NULL)
8771     {
8772       path = gtk_tree_model_get_path (model, iter);
8773       free_path = TRUE;
8774     }
8775   else if (iter == NULL)
8776     gtk_tree_model_get_iter (model, iter, path);
8777
8778   if (tree_view->priv->tree == NULL)
8779     tree_view->priv->tree = _gtk_rbtree_new ();
8780
8781   tmptree = tree = tree_view->priv->tree;
8782
8783   /* Update all row-references */
8784   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8785   depth = gtk_tree_path_get_depth (path);
8786   indices = gtk_tree_path_get_indices (path);
8787
8788   /* First, find the parent tree */
8789   while (i < depth - 1)
8790     {
8791       if (tmptree == NULL)
8792         {
8793           /* We aren't showing the node */
8794           node_visible = FALSE;
8795           goto done;
8796         }
8797
8798       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8799       if (tmpnode == NULL)
8800         {
8801           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8802                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8803                      "before the parent was inserted.");
8804           goto done;
8805         }
8806       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8807         {
8808           /* FIXME enforce correct behavior on model, probably */
8809           /* In theory, the model should have emitted has_child_toggled here.  We
8810            * try to catch it anyway, just to be safe, in case the model hasn't.
8811            */
8812           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8813                                                            tree,
8814                                                            tmpnode);
8815           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8816           gtk_tree_path_free (tmppath);
8817           goto done;
8818         }
8819
8820       tmptree = tmpnode->children;
8821       tree = tmptree;
8822       i++;
8823     }
8824
8825   if (tree == NULL)
8826     {
8827       node_visible = FALSE;
8828       goto done;
8829     }
8830
8831   /* ref the node */
8832   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8833   if (indices[depth - 1] == 0)
8834     {
8835       tmpnode = _gtk_rbtree_find_count (tree, 1);
8836       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8837     }
8838   else
8839     {
8840       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8841       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8842     }
8843
8844  done:
8845   if (height > 0)
8846     {
8847       if (tree)
8848         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8849
8850       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8851         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8852       else
8853         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8854     }
8855   else
8856     install_presize_handler (tree_view);
8857   if (free_path)
8858     gtk_tree_path_free (path);
8859 }
8860
8861 static void
8862 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8863                                      GtkTreePath  *path,
8864                                      GtkTreeIter  *iter,
8865                                      gpointer      data)
8866 {
8867   GtkTreeView *tree_view = (GtkTreeView *)data;
8868   GtkTreeIter real_iter;
8869   gboolean has_child;
8870   GtkRBTree *tree;
8871   GtkRBNode *node;
8872   gboolean free_path = FALSE;
8873
8874   g_return_if_fail (path != NULL || iter != NULL);
8875
8876   if (iter)
8877     real_iter = *iter;
8878
8879   if (path == NULL)
8880     {
8881       path = gtk_tree_model_get_path (model, iter);
8882       free_path = TRUE;
8883     }
8884   else if (iter == NULL)
8885     gtk_tree_model_get_iter (model, &real_iter, path);
8886
8887   if (_gtk_tree_view_find_node (tree_view,
8888                                 path,
8889                                 &tree,
8890                                 &node))
8891     /* We aren't actually showing the node */
8892     goto done;
8893
8894   if (tree == NULL)
8895     goto done;
8896
8897   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8898   /* Sanity check.
8899    */
8900   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8901     goto done;
8902
8903   if (has_child)
8904     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8905   else
8906     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8907
8908   if (has_child && tree_view->priv->is_list)
8909     {
8910       tree_view->priv->is_list = FALSE;
8911       if (tree_view->priv->show_expanders)
8912         {
8913           GList *list;
8914
8915           for (list = tree_view->priv->columns; list; list = list->next)
8916             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8917               {
8918                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8919                 break;
8920               }
8921         }
8922       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8923     }
8924   else
8925     {
8926       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8927     }
8928
8929  done:
8930   if (free_path)
8931     gtk_tree_path_free (path);
8932 }
8933
8934 static void
8935 count_children_helper (GtkRBTree *tree,
8936                        GtkRBNode *node,
8937                        gpointer   data)
8938 {
8939   if (node->children)
8940     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8941   (*((gint *)data))++;
8942 }
8943
8944 static void
8945 check_selection_helper (GtkRBTree *tree,
8946                         GtkRBNode *node,
8947                         gpointer   data)
8948 {
8949   gint *value = (gint *)data;
8950
8951   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8952
8953   if (node->children && !*value)
8954     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8955 }
8956
8957 static void
8958 gtk_tree_view_row_deleted (GtkTreeModel *model,
8959                            GtkTreePath  *path,
8960                            gpointer      data)
8961 {
8962   GtkTreeView *tree_view = (GtkTreeView *)data;
8963   GtkRBTree *tree;
8964   GtkRBNode *node;
8965   GList *list;
8966   gint selection_changed = FALSE;
8967
8968   g_return_if_fail (path != NULL);
8969
8970   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8971
8972   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8973     return;
8974
8975   if (tree == NULL)
8976     return;
8977
8978   /* check if the selection has been changed */
8979   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8980                         check_selection_helper, &selection_changed);
8981
8982   for (list = tree_view->priv->columns; list; list = list->next)
8983     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
8984         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8985       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8986
8987   /* Ensure we don't have a dangling pointer to a dead node */
8988   ensure_unprelighted (tree_view);
8989
8990   /* Cancel editting if we've started */
8991   gtk_tree_view_stop_editing (tree_view, TRUE);
8992
8993   /* If we have a node expanded/collapsed timeout, remove it */
8994   remove_expand_collapse_timeout (tree_view);
8995
8996   if (tree_view->priv->destroy_count_func)
8997     {
8998       gint child_count = 0;
8999       if (node->children)
9000         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9001       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9002     }
9003
9004   if (tree->root->count == 1)
9005     {
9006       if (tree_view->priv->tree == tree)
9007         tree_view->priv->tree = NULL;
9008
9009       _gtk_rbtree_remove (tree);
9010     }
9011   else
9012     {
9013       _gtk_rbtree_remove_node (tree, node);
9014     }
9015
9016   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9017     {
9018       gtk_tree_row_reference_free (tree_view->priv->top_row);
9019       tree_view->priv->top_row = NULL;
9020     }
9021
9022   install_scroll_sync_handler (tree_view);
9023
9024   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9025
9026   if (selection_changed)
9027     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9028 }
9029
9030 static void
9031 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9032                               GtkTreePath  *parent,
9033                               GtkTreeIter  *iter,
9034                               gint         *new_order,
9035                               gpointer      data)
9036 {
9037   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9038   GtkRBTree *tree;
9039   GtkRBNode *node;
9040   gint len;
9041
9042   len = gtk_tree_model_iter_n_children (model, iter);
9043
9044   if (len < 2)
9045     return;
9046
9047   gtk_tree_row_reference_reordered (G_OBJECT (data),
9048                                     parent,
9049                                     iter,
9050                                     new_order);
9051
9052   if (_gtk_tree_view_find_node (tree_view,
9053                                 parent,
9054                                 &tree,
9055                                 &node))
9056     return;
9057
9058   /* We need to special case the parent path */
9059   if (tree == NULL)
9060     tree = tree_view->priv->tree;
9061   else
9062     tree = node->children;
9063
9064   if (tree == NULL)
9065     return;
9066
9067   if (tree_view->priv->edited_column)
9068     gtk_tree_view_stop_editing (tree_view, TRUE);
9069
9070   /* we need to be unprelighted */
9071   ensure_unprelighted (tree_view);
9072
9073   /* clear the timeout */
9074   cancel_arrow_animation (tree_view);
9075   
9076   _gtk_rbtree_reorder (tree, new_order, len);
9077
9078   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9079
9080   gtk_tree_view_dy_to_top_row (tree_view);
9081 }
9082
9083
9084 /* Internal tree functions
9085  */
9086
9087
9088 static void
9089 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9090                                      GtkRBTree         *tree,
9091                                      GtkTreeViewColumn *column,
9092                                      gint              *x1,
9093                                      gint              *x2)
9094 {
9095   GtkTreeViewColumn *tmp_column = NULL;
9096   gint total_width;
9097   GList *list;
9098   gboolean rtl;
9099
9100   if (x1)
9101     *x1 = 0;
9102
9103   if (x2)
9104     *x2 = 0;
9105
9106   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9107
9108   total_width = 0;
9109   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9110        list;
9111        list = (rtl ? list->prev : list->next))
9112     {
9113       tmp_column = list->data;
9114
9115       if (tmp_column == column)
9116         break;
9117
9118       if (gtk_tree_view_column_get_visible (tmp_column))
9119         total_width += gtk_tree_view_column_get_width (tmp_column);
9120     }
9121
9122   if (tmp_column != column)
9123     {
9124       g_warning (G_STRLOC": passed-in column isn't in the tree");
9125       return;
9126     }
9127
9128   if (x1)
9129     *x1 = total_width;
9130
9131   if (x2)
9132     {
9133       if (gtk_tree_view_column_get_visible (column))
9134         *x2 = total_width + gtk_tree_view_column_get_width (column);
9135       else
9136         *x2 = total_width; /* width of 0 */
9137     }
9138 }
9139
9140 static void
9141 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9142                                 GtkRBTree   *tree,
9143                                 gint        *x1,
9144                                 gint        *x2)
9145 {
9146   gint x_offset = 0;
9147   GList *list;
9148   GtkTreeViewColumn *tmp_column = NULL;
9149   gint total_width;
9150   gboolean indent_expanders;
9151   gboolean rtl;
9152
9153   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9154
9155   total_width = 0;
9156   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9157        list;
9158        list = (rtl ? list->prev : list->next))
9159     {
9160       tmp_column = list->data;
9161
9162       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9163         {
9164           if (rtl)
9165             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - tree_view->priv->expander_size;
9166           else
9167             x_offset = total_width;
9168           break;
9169         }
9170
9171       if (gtk_tree_view_column_get_visible (tmp_column))
9172         total_width += gtk_tree_view_column_get_width (tmp_column);
9173     }
9174
9175   gtk_widget_style_get (GTK_WIDGET (tree_view),
9176                         "indent-expanders", &indent_expanders,
9177                         NULL);
9178
9179   if (indent_expanders)
9180     {
9181       if (rtl)
9182         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9183       else
9184         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9185     }
9186
9187   *x1 = x_offset;
9188
9189   if (tmp_column &&
9190       gtk_tree_view_column_get_visible (tmp_column))
9191     /* +1 because x2 isn't included in the range. */
9192     *x2 = *x1 + tree_view->priv->expander_size + 1;
9193   else
9194     *x2 = *x1;
9195 }
9196
9197 static void
9198 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9199                           GtkRBTree   *tree,
9200                           GtkTreeIter *iter,
9201                           gint         depth,
9202                           gboolean     recurse)
9203 {
9204   GtkRBNode *temp = NULL;
9205   GtkTreePath *path = NULL;
9206
9207   do
9208     {
9209       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9210       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9211
9212       if (tree_view->priv->fixed_height > 0)
9213         {
9214           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9215             {
9216               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9217               _gtk_rbtree_node_mark_valid (tree, temp);
9218             }
9219         }
9220
9221       if (tree_view->priv->is_list)
9222         continue;
9223
9224       if (recurse)
9225         {
9226           GtkTreeIter child;
9227
9228           if (!path)
9229             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9230           else
9231             gtk_tree_path_next (path);
9232
9233           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9234             {
9235               gboolean expand;
9236
9237               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9238
9239               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9240                   && !expand)
9241                 {
9242                   temp->children = _gtk_rbtree_new ();
9243                   temp->children->parent_tree = tree;
9244                   temp->children->parent_node = temp;
9245                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9246                 }
9247             }
9248         }
9249
9250       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9251         {
9252           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9253             temp->flags ^= GTK_RBNODE_IS_PARENT;
9254         }
9255     }
9256   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9257
9258   if (path)
9259     gtk_tree_path_free (path);
9260 }
9261
9262 /* Make sure the node is visible vertically */
9263 static void
9264 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9265                                   GtkRBTree   *tree,
9266                                   GtkRBNode   *node)
9267 {
9268   gint node_dy, height;
9269   GtkTreePath *path = NULL;
9270
9271   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9272     return;
9273
9274   /* just return if the node is visible, avoiding a costly expose */
9275   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9276   height = gtk_tree_view_get_row_height (tree_view, node);
9277   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9278       && node_dy >= tree_view->priv->vadjustment->value
9279       && node_dy + height <= (tree_view->priv->vadjustment->value
9280                               + tree_view->priv->vadjustment->page_size))
9281     return;
9282
9283   path = _gtk_tree_view_find_path (tree_view, tree, node);
9284   if (path)
9285     {
9286       /* We process updates because we want to clear old selected items when we scroll.
9287        * if this is removed, we get a "selection streak" at the bottom. */
9288       gtk_tree_view_bin_process_updates (tree_view);
9289
9290       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9291       gtk_tree_path_free (path);
9292     }
9293 }
9294
9295 static void
9296 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9297                                     GtkTreeViewColumn *column,
9298                                     gboolean           focus_to_cell)
9299 {
9300   GtkAllocation allocation;
9301   gint x, width;
9302
9303   if (column == NULL)
9304     return;
9305
9306   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9307   x = allocation.x;
9308   width = allocation.width;
9309
9310   if (width > tree_view->priv->hadjustment->page_size)
9311     {
9312       /* The column is larger than the horizontal page size.  If the
9313        * column has cells which can be focussed individually, then we make
9314        * sure the cell which gets focus is fully visible (if even the
9315        * focus cell is bigger than the page size, we make sure the
9316        * left-hand side of the cell is visible).
9317        *
9318        * If the column does not have an activatable cell, we
9319        * make sure the left-hand side of the column is visible.
9320        */
9321
9322       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9323         {
9324           GtkCellArea *cell_area;
9325           GtkCellRenderer *focus_cell;
9326
9327           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9328           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9329
9330           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9331                                                       &x, &width))
9332             {
9333               if (width < tree_view->priv->hadjustment->page_size)
9334                 {
9335                   if (tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size < x + width)
9336                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9337                                               x + width - tree_view->priv->hadjustment->page_size);
9338                   else if (tree_view->priv->hadjustment->value > x)
9339                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9340                 }
9341             }
9342         }
9343
9344       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9345     }
9346   else
9347     {
9348       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
9349           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9350                                     x + width - tree_view->priv->hadjustment->page_size);
9351       else if (tree_view->priv->hadjustment->value > x)
9352         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9353   }
9354 }
9355
9356 /* This function could be more efficient.  I'll optimize it if profiling seems
9357  * to imply that it is important */
9358 GtkTreePath *
9359 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9360                           GtkRBTree   *tree,
9361                           GtkRBNode   *node)
9362 {
9363   GtkTreePath *path;
9364   GtkRBTree *tmp_tree;
9365   GtkRBNode *tmp_node, *last;
9366   gint count;
9367
9368   path = gtk_tree_path_new ();
9369
9370   g_return_val_if_fail (node != NULL, path);
9371   g_return_val_if_fail (node != tree->nil, path);
9372
9373   count = 1 + node->left->count;
9374
9375   last = node;
9376   tmp_node = node->parent;
9377   tmp_tree = tree;
9378   while (tmp_tree)
9379     {
9380       while (tmp_node != tmp_tree->nil)
9381         {
9382           if (tmp_node->right == last)
9383             count += 1 + tmp_node->left->count;
9384           last = tmp_node;
9385           tmp_node = tmp_node->parent;
9386         }
9387       gtk_tree_path_prepend_index (path, count - 1);
9388       last = tmp_tree->parent_node;
9389       tmp_tree = tmp_tree->parent_tree;
9390       if (last)
9391         {
9392           count = 1 + last->left->count;
9393           tmp_node = last->parent;
9394         }
9395     }
9396   return path;
9397 }
9398
9399 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9400  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9401  * both set to NULL.
9402  */
9403 gboolean
9404 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9405                           GtkTreePath  *path,
9406                           GtkRBTree   **tree,
9407                           GtkRBNode   **node)
9408 {
9409   GtkRBNode *tmpnode = NULL;
9410   GtkRBTree *tmptree = tree_view->priv->tree;
9411   gint *indices = gtk_tree_path_get_indices (path);
9412   gint depth = gtk_tree_path_get_depth (path);
9413   gint i = 0;
9414
9415   *node = NULL;
9416   *tree = NULL;
9417
9418   if (depth == 0 || tmptree == NULL)
9419     return FALSE;
9420   do
9421     {
9422       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9423       ++i;
9424       if (tmpnode == NULL)
9425         {
9426           *tree = NULL;
9427           *node = NULL;
9428           return FALSE;
9429         }
9430       if (i >= depth)
9431         {
9432           *tree = tmptree;
9433           *node = tmpnode;
9434           return FALSE;
9435         }
9436       *tree = tmptree;
9437       *node = tmpnode;
9438       tmptree = tmpnode->children;
9439       if (tmptree == NULL)
9440         return TRUE;
9441     }
9442   while (1);
9443 }
9444
9445 static gboolean
9446 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9447                                   GtkTreeViewColumn *column)
9448 {
9449   GList *list;
9450
9451   if (tree_view->priv->is_list)
9452     return FALSE;
9453
9454   if (tree_view->priv->expander_column != NULL)
9455     {
9456       if (tree_view->priv->expander_column == column)
9457         return TRUE;
9458       return FALSE;
9459     }
9460   else
9461     {
9462       for (list = tree_view->priv->columns;
9463            list;
9464            list = list->next)
9465         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9466           break;
9467       if (list && list->data == column)
9468         return TRUE;
9469     }
9470   return FALSE;
9471 }
9472
9473 static inline gboolean
9474 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9475 {
9476   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9477     return TRUE;
9478   /* else */
9479   return FALSE;
9480 }
9481
9482 static void
9483 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9484                                 guint           keyval,
9485                                 guint           modmask,
9486                                 gboolean        add_shifted_binding,
9487                                 GtkMovementStep step,
9488                                 gint            count)
9489 {
9490   
9491   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9492                                 "move-cursor", 2,
9493                                 G_TYPE_ENUM, step,
9494                                 G_TYPE_INT, count);
9495
9496   if (add_shifted_binding)
9497     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9498                                   "move-cursor", 2,
9499                                   G_TYPE_ENUM, step,
9500                                   G_TYPE_INT, count);
9501
9502   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9503    return;
9504
9505   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9506                                 "move-cursor", 2,
9507                                 G_TYPE_ENUM, step,
9508                                 G_TYPE_INT, count);
9509
9510   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9511                                 "move-cursor", 2,
9512                                 G_TYPE_ENUM, step,
9513                                 G_TYPE_INT, count);
9514 }
9515
9516 static gint
9517 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9518                                  GtkTreeIter  *iter,
9519                                  GtkRBTree    *tree,
9520                                  GtkRBNode    *node)
9521 {
9522   gint retval = FALSE;
9523   do
9524     {
9525       g_return_val_if_fail (node != NULL, FALSE);
9526
9527       if (node->children)
9528         {
9529           GtkTreeIter child;
9530           GtkRBTree *new_tree;
9531           GtkRBNode *new_node;
9532
9533           new_tree = node->children;
9534           new_node = new_tree->root;
9535
9536           while (new_node && new_node->left != new_tree->nil)
9537             new_node = new_node->left;
9538
9539           if (!gtk_tree_model_iter_children (model, &child, iter))
9540             return FALSE;
9541
9542           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9543         }
9544
9545       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9546         retval = TRUE;
9547       gtk_tree_model_unref_node (model, iter);
9548       node = _gtk_rbtree_next (tree, node);
9549     }
9550   while (gtk_tree_model_iter_next (model, iter));
9551
9552   return retval;
9553 }
9554
9555 static gint
9556 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9557                                               GtkRBTree   *tree)
9558 {
9559   GtkTreeIter iter;
9560   GtkTreePath *path;
9561   GtkRBNode *node;
9562   gint retval;
9563
9564   if (!tree)
9565     return FALSE;
9566
9567   node = tree->root;
9568   while (node && node->left != tree->nil)
9569     node = node->left;
9570
9571   g_return_val_if_fail (node != NULL, FALSE);
9572   path = _gtk_tree_view_find_path (tree_view, tree, node);
9573   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9574                            &iter, path);
9575   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9576   gtk_tree_path_free (path);
9577
9578   return retval;
9579 }
9580
9581 static void
9582 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9583                                     GtkTreeViewColumn *column)
9584 {
9585   GtkTreeViewColumn *left_column;
9586   GtkTreeViewColumn *cur_column = NULL;
9587   GtkTreeViewColumnReorder *reorder;
9588   gboolean rtl;
9589   GList *tmp_list;
9590   gint left;
9591
9592   /* We want to precalculate the motion list such that we know what column slots
9593    * are available.
9594    */
9595   left_column = NULL;
9596   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9597
9598   /* First, identify all possible drop spots */
9599   if (rtl)
9600     tmp_list = g_list_last (tree_view->priv->columns);
9601   else
9602     tmp_list = g_list_first (tree_view->priv->columns);
9603
9604   while (tmp_list)
9605     {
9606       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9607       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9608
9609       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9610         continue;
9611
9612       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9613       if (left_column != column && cur_column != column &&
9614           tree_view->priv->column_drop_func &&
9615           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9616         {
9617           left_column = cur_column;
9618           continue;
9619         }
9620       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9621       reorder->left_column = left_column;
9622       left_column = reorder->right_column = cur_column;
9623
9624       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9625     }
9626
9627   /* Add the last one */
9628   if (tree_view->priv->column_drop_func == NULL ||
9629       ((left_column != column) &&
9630        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9631     {
9632       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9633       reorder->left_column = left_column;
9634       reorder->right_column = NULL;
9635       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9636     }
9637
9638   /* We quickly check to see if it even makes sense to reorder columns. */
9639   /* If there is nothing that can be moved, then we return */
9640
9641   if (tree_view->priv->column_drag_info == NULL)
9642     return;
9643
9644   /* We know there are always 2 slots possbile, as you can always return column. */
9645   /* If that's all there is, return */
9646   if (tree_view->priv->column_drag_info->next == NULL || 
9647       (tree_view->priv->column_drag_info->next->next == NULL &&
9648        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9649        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9650     {
9651       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9652         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9653       g_list_free (tree_view->priv->column_drag_info);
9654       tree_view->priv->column_drag_info = NULL;
9655       return;
9656     }
9657   /* We fill in the ranges for the columns, now that we've isolated them */
9658   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9659
9660   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9661     {
9662       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9663
9664       reorder->left_align = left;
9665       if (tmp_list->next != NULL)
9666         {
9667           GtkAllocation right_allocation, left_allocation;
9668           GtkWidget    *left_button, *right_button;
9669
9670           g_assert (tmp_list->next->data);
9671
9672           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9673           left_button  = gtk_tree_view_column_get_button
9674             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9675
9676           gtk_widget_get_allocation (right_button, &right_allocation);
9677           gtk_widget_get_allocation (left_button, &left_allocation);
9678           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9679         }
9680       else
9681         {
9682           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9683                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9684         }
9685     }
9686 }
9687
9688 void
9689 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9690                                   GtkTreeViewColumn *column,
9691                                   GdkDevice         *device)
9692 {
9693   GdkEvent *send_event;
9694   GtkAllocation allocation;
9695   GtkAllocation button_allocation;
9696   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9697   GdkDisplay *display = gdk_screen_get_display (screen);
9698   GtkWidget *button;
9699
9700   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9701   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9702
9703   gtk_tree_view_set_column_drag_info (tree_view, column);
9704
9705   if (tree_view->priv->column_drag_info == NULL)
9706     return;
9707
9708   button = gtk_tree_view_column_get_button (column);
9709
9710   if (tree_view->priv->drag_window == NULL)
9711     {
9712       GdkWindowAttr attributes;
9713       guint attributes_mask;
9714
9715       gtk_widget_get_allocation (button, &button_allocation);
9716
9717       attributes.window_type = GDK_WINDOW_CHILD;
9718       attributes.wclass = GDK_INPUT_OUTPUT;
9719       attributes.x = button_allocation.x;
9720       attributes.y = 0;
9721       attributes.width = button_allocation.width;
9722       attributes.height = button_allocation.height;
9723       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9724       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9725       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9726
9727       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9728                                                      &attributes,
9729                                                      attributes_mask);
9730       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9731     }
9732
9733   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9734   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9735
9736   gtk_grab_remove (button);
9737
9738   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9739   send_event->crossing.send_event = TRUE;
9740   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9741   send_event->crossing.subwindow = NULL;
9742   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9743   send_event->crossing.time = GDK_CURRENT_TIME;
9744   gdk_event_set_device (send_event, device);
9745
9746   gtk_propagate_event (button, send_event);
9747   gdk_event_free (send_event);
9748
9749   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9750   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9751   send_event->button.send_event = TRUE;
9752   send_event->button.time = GDK_CURRENT_TIME;
9753   send_event->button.x = -1;
9754   send_event->button.y = -1;
9755   send_event->button.axes = NULL;
9756   send_event->button.state = 0;
9757   send_event->button.button = 1;
9758   send_event->button.x_root = 0;
9759   send_event->button.y_root = 0;
9760   gdk_event_set_device (send_event, device);
9761
9762   gtk_propagate_event (button, send_event);
9763   gdk_event_free (send_event);
9764
9765   /* Kids, don't try this at home */
9766   g_object_ref (button);
9767   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9768   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9769   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9770   g_object_unref (button);
9771
9772   gtk_widget_get_allocation (button, &button_allocation);
9773   tree_view->priv->drag_column_x = button_allocation.x;
9774   allocation = button_allocation;
9775   allocation.x = 0;
9776   gtk_widget_size_allocate (button, &allocation);
9777   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9778
9779   tree_view->priv->drag_column = column;
9780   gdk_window_show (tree_view->priv->drag_window);
9781
9782   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9783   while (gtk_events_pending ())
9784     gtk_main_iteration ();
9785
9786   tree_view->priv->in_column_drag = TRUE;
9787   gdk_pointer_grab (tree_view->priv->drag_window,
9788                     FALSE,
9789                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9790                     NULL, NULL, GDK_CURRENT_TIME);
9791   gdk_keyboard_grab (tree_view->priv->drag_window,
9792                      FALSE,
9793                      GDK_CURRENT_TIME);
9794 }
9795
9796 static void
9797 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9798                                 GtkRBTree          *tree,
9799                                 GtkRBNode          *node)
9800 {
9801   GtkAllocation allocation;
9802   GdkRectangle rect;
9803
9804   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9805     return;
9806
9807   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9808   rect.x = 0;
9809   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9810
9811   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9812   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9813
9814   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9815 }
9816
9817 void
9818 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9819                                 GtkRBTree          *tree,
9820                                 GtkRBNode          *node,
9821                                 const GdkRectangle *clip_rect)
9822 {
9823   GtkAllocation allocation;
9824   GdkRectangle rect;
9825
9826   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9827     return;
9828
9829   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9830   rect.x = 0;
9831   rect.width = MAX (tree_view->priv->width, allocation.width);
9832
9833   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9834   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9835
9836   if (clip_rect)
9837     {
9838       GdkRectangle new_rect;
9839
9840       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9841
9842       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9843     }
9844   else
9845     {
9846       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9847     }
9848 }
9849
9850 static inline gint
9851 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9852 {
9853   if (tree_view->priv->headers_visible)
9854     return tree_view->priv->header_height;
9855   /* else */
9856   return 0;
9857 }
9858
9859 gint
9860 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9861 {
9862   return tree_view->priv->header_height;
9863 }
9864
9865 void
9866 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9867                                        GtkTreeViewRowSeparatorFunc *func,
9868                                        gpointer                    *data)
9869 {
9870   *func = tree_view->priv->row_separator_func;
9871   *data = tree_view->priv->row_separator_data;
9872 }
9873
9874 GtkTreePath *
9875 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9876 {
9877   if (tree_view->priv->anchor)
9878     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9879
9880   return NULL;
9881 }
9882
9883 void
9884 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9885                                 GtkTreePath *anchor_path)
9886 {
9887   if (tree_view->priv->anchor)
9888     {
9889       gtk_tree_row_reference_free (tree_view->priv->anchor);
9890       tree_view->priv->anchor = NULL;
9891     }
9892
9893   if (anchor_path && tree_view->priv->model)
9894     tree_view->priv->anchor =
9895       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
9896                                         tree_view->priv->model, anchor_path);
9897 }
9898
9899 GtkRBTree *
9900 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
9901 {
9902   return tree_view->priv->tree;
9903 }
9904
9905 GdkWindow *
9906 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
9907 {
9908   return tree_view->priv->header_window;
9909 }
9910
9911 void
9912 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
9913                                  GtkTreeViewColumn *column)
9914 {
9915   tree_view->priv->focus_column = column;
9916 }
9917
9918
9919 static void
9920 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9921                                GtkTreePath        *path,
9922                                const GdkRectangle *clip_rect)
9923 {
9924   GtkRBTree *tree = NULL;
9925   GtkRBNode *node = NULL;
9926
9927   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9928
9929   if (tree)
9930     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9931 }
9932
9933 /* x and y are the mouse position
9934  */
9935 static void
9936 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9937                           cairo_t     *cr,
9938                           GtkRBTree   *tree,
9939                           GtkRBNode   *node,
9940                           /* in bin_window coordinates */
9941                           gint         x,
9942                           gint         y)
9943 {
9944   GdkRectangle area;
9945   GtkStateType state;
9946   GtkWidget *widget;
9947   gint x_offset = 0;
9948   gint x2;
9949   gint vertical_separator;
9950   gint expander_size;
9951   GtkExpanderStyle expander_style;
9952
9953   widget = GTK_WIDGET (tree_view);
9954
9955   gtk_widget_style_get (widget,
9956                         "vertical-separator", &vertical_separator,
9957                         NULL);
9958   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9959
9960   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9961     return;
9962
9963   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9964
9965   area.x = x_offset;
9966   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
9967                                                  vertical_separator);
9968   area.width = expander_size + 2;
9969   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
9970                                                     vertical_separator);
9971
9972   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9973     {
9974       state = GTK_STATE_INSENSITIVE;
9975     }
9976   else if (node == tree_view->priv->button_pressed_node)
9977     {
9978       if (x >= area.x && x <= (area.x + area.width) &&
9979           y >= area.y && y <= (area.y + area.height))
9980         state = GTK_STATE_ACTIVE;
9981       else
9982         state = GTK_STATE_NORMAL;
9983     }
9984   else
9985     {
9986       if (node == tree_view->priv->prelight_node &&
9987           tree_view->priv->arrow_prelit)
9988         state = GTK_STATE_PRELIGHT;
9989       else
9990         state = GTK_STATE_NORMAL;
9991     }
9992
9993   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9994     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9995   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9996     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9997   else if (node->children != NULL)
9998     expander_style = GTK_EXPANDER_EXPANDED;
9999   else
10000     expander_style = GTK_EXPANDER_COLLAPSED;
10001
10002   gtk_paint_expander (gtk_widget_get_style (widget),
10003                       cr,
10004                       state,
10005                       widget,
10006                       "treeview",
10007                       area.x + area.width / 2,
10008                       area.y + area.height / 2,
10009                       expander_style);
10010 }
10011
10012 static void
10013 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10014
10015 {
10016   GtkTreePath *cursor_path;
10017
10018   if ((tree_view->priv->tree == NULL) ||
10019       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10020     return;
10021
10022   cursor_path = NULL;
10023   if (tree_view->priv->cursor)
10024     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10025
10026   if (cursor_path == NULL)
10027     {
10028       /* Consult the selection before defaulting to the
10029        * first focusable element
10030        */
10031       GList *selected_rows;
10032       GtkTreeModel *model;
10033       GtkTreeSelection *selection;
10034
10035       selection = gtk_tree_view_get_selection (tree_view);
10036       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10037
10038       if (selected_rows)
10039         {
10040           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10041           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
10042           g_list_free (selected_rows);
10043         }
10044       else
10045         {
10046           cursor_path = gtk_tree_path_new_first ();
10047           search_first_focusable_path (tree_view, &cursor_path,
10048                                        TRUE, NULL, NULL);
10049         }
10050
10051       gtk_tree_row_reference_free (tree_view->priv->cursor);
10052       tree_view->priv->cursor = NULL;
10053
10054       if (cursor_path)
10055         {
10056           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
10057             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
10058           else
10059             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10060         }
10061     }
10062
10063   if (cursor_path)
10064     {
10065       tree_view->priv->draw_keyfocus = TRUE;
10066
10067       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10068       gtk_tree_path_free (cursor_path);
10069
10070       if (tree_view->priv->focus_column == NULL)
10071         {
10072           GList *list;
10073           for (list = tree_view->priv->columns; list; list = list->next)
10074             {
10075               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10076                 {
10077                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
10078                   break;
10079                 }
10080             }
10081         }
10082     }
10083 }
10084
10085 static void
10086 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10087                                    gint         count)
10088 {
10089   gint selection_count;
10090   GtkRBTree *cursor_tree = NULL;
10091   GtkRBNode *cursor_node = NULL;
10092   GtkRBTree *new_cursor_tree = NULL;
10093   GtkRBNode *new_cursor_node = NULL;
10094   GtkTreePath *cursor_path = NULL;
10095   gboolean grab_focus = TRUE;
10096   gboolean selectable;
10097
10098   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10099     return;
10100
10101   cursor_path = NULL;
10102   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
10103     /* FIXME: we lost the cursor; should we get the first? */
10104     return;
10105
10106   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10107   _gtk_tree_view_find_node (tree_view, cursor_path,
10108                             &cursor_tree, &cursor_node);
10109
10110   if (cursor_tree == NULL)
10111     /* FIXME: we lost the cursor; should we get the first? */
10112     return;
10113
10114   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10115   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10116                                                       cursor_node,
10117                                                       cursor_path);
10118
10119   if (selection_count == 0
10120       && tree_view->priv->selection->type != GTK_SELECTION_NONE
10121       && !tree_view->priv->ctrl_pressed
10122       && selectable)
10123     {
10124       /* Don't move the cursor, but just select the current node */
10125       new_cursor_tree = cursor_tree;
10126       new_cursor_node = cursor_node;
10127     }
10128   else
10129     {
10130       if (count == -1)
10131         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10132                                &new_cursor_tree, &new_cursor_node);
10133       else
10134         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10135                                &new_cursor_tree, &new_cursor_node);
10136     }
10137
10138   gtk_tree_path_free (cursor_path);
10139
10140   if (new_cursor_node)
10141     {
10142       cursor_path = _gtk_tree_view_find_path (tree_view,
10143                                               new_cursor_tree, new_cursor_node);
10144
10145       search_first_focusable_path (tree_view, &cursor_path,
10146                                    (count != -1),
10147                                    &new_cursor_tree,
10148                                    &new_cursor_node);
10149
10150       if (cursor_path)
10151         gtk_tree_path_free (cursor_path);
10152     }
10153
10154   /*
10155    * If the list has only one item and multi-selection is set then select
10156    * the row (if not yet selected).
10157    */
10158   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
10159       new_cursor_node == NULL)
10160     {
10161       if (count == -1)
10162         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10163                                &new_cursor_tree, &new_cursor_node);
10164       else
10165         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10166                                &new_cursor_tree, &new_cursor_node);
10167
10168       if (new_cursor_node == NULL
10169           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
10170         {
10171           new_cursor_node = cursor_node;
10172           new_cursor_tree = cursor_tree;
10173         }
10174       else
10175         {
10176           new_cursor_node = NULL;
10177         }
10178     }
10179
10180   if (new_cursor_node)
10181     {
10182       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
10183       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
10184       gtk_tree_path_free (cursor_path);
10185     }
10186   else
10187     {
10188       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10189
10190       if (!tree_view->priv->shift_pressed)
10191         {
10192           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10193                                           count < 0 ?
10194                                           GTK_DIR_UP : GTK_DIR_DOWN))
10195             {
10196               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10197
10198               if (toplevel)
10199                 gtk_widget_child_focus (toplevel,
10200                                         count < 0 ?
10201                                         GTK_DIR_TAB_BACKWARD :
10202                                         GTK_DIR_TAB_FORWARD);
10203
10204               grab_focus = FALSE;
10205             }
10206         }
10207       else
10208         {
10209           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10210         }
10211     }
10212
10213   if (grab_focus)
10214     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10215 }
10216
10217 static void
10218 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10219                                         gint         count)
10220 {
10221   GtkRBTree *cursor_tree = NULL;
10222   GtkRBNode *cursor_node = NULL;
10223   GtkTreePath *old_cursor_path = NULL;
10224   GtkTreePath *cursor_path = NULL;
10225   GtkRBTree *start_cursor_tree = NULL;
10226   GtkRBNode *start_cursor_node = NULL;
10227   gint y;
10228   gint window_y;
10229   gint vertical_separator;
10230
10231   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10232     return;
10233
10234   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10235     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10236   else
10237     /* This is sorta weird.  Focus in should give us a cursor */
10238     return;
10239
10240   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10241   _gtk_tree_view_find_node (tree_view, old_cursor_path,
10242                             &cursor_tree, &cursor_node);
10243
10244   if (cursor_tree == NULL)
10245     {
10246       /* FIXME: we lost the cursor.  Should we try to get one? */
10247       gtk_tree_path_free (old_cursor_path);
10248       return;
10249     }
10250   g_return_if_fail (cursor_node != NULL);
10251
10252   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10253   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10254   y += tree_view->priv->cursor_offset;
10255   y += count * (int)tree_view->priv->vadjustment->page_increment;
10256   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
10257
10258   if (y >= tree_view->priv->height)
10259     y = tree_view->priv->height - 1;
10260
10261   tree_view->priv->cursor_offset =
10262     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10263                              &cursor_tree, &cursor_node);
10264
10265   if (cursor_tree == NULL)
10266     {
10267       /* FIXME: we lost the cursor.  Should we try to get one? */
10268       gtk_tree_path_free (old_cursor_path);
10269       return;
10270     }
10271
10272   if (tree_view->priv->cursor_offset
10273       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10274     {
10275       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10276                              &cursor_tree, &cursor_node);
10277       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10278     }
10279
10280   y -= tree_view->priv->cursor_offset;
10281   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10282
10283   start_cursor_tree = cursor_tree;
10284   start_cursor_node = cursor_node;
10285
10286   if (! search_first_focusable_path (tree_view, &cursor_path,
10287                                      (count != -1),
10288                                      &cursor_tree, &cursor_node))
10289     {
10290       /* It looks like we reached the end of the view without finding
10291        * a focusable row.  We will step backwards to find the last
10292        * focusable row.
10293        */
10294       cursor_tree = start_cursor_tree;
10295       cursor_node = start_cursor_node;
10296       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10297
10298       search_first_focusable_path (tree_view, &cursor_path,
10299                                    (count == -1),
10300                                    &cursor_tree, &cursor_node);
10301     }
10302
10303   if (!cursor_path)
10304     goto cleanup;
10305
10306   /* update y */
10307   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10308
10309   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10310
10311   y -= window_y;
10312   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10313   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10314   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10315
10316   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10317     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10318
10319   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10320
10321 cleanup:
10322   gtk_tree_path_free (old_cursor_path);
10323   gtk_tree_path_free (cursor_path);
10324 }
10325
10326 static gboolean
10327 gtk_tree_view_move_focus_column  (GtkTreeView       *tree_view,
10328                                   GtkTreeViewColumn *tree_column,
10329                                   gint               count,
10330                                   gboolean           left,
10331                                   gboolean           right)
10332 {
10333   gboolean rtl;
10334   GtkDirectionType direction = 0;
10335   GtkCellArea *cell_area;
10336
10337   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
10338
10339   switch (count)
10340     {
10341       case -1:
10342         direction = GTK_DIR_LEFT;
10343         break;
10344
10345       case 1:
10346         direction = GTK_DIR_RIGHT;
10347         break;
10348     }
10349
10350   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_column));
10351
10352   /* if we are the current focus column and have multiple editable cells,
10353    * try to select the next one, else move the focus to the next column
10354    */
10355   if (tree_view->priv->focus_column == tree_column)
10356     {
10357       if (gtk_cell_area_focus (cell_area, direction))
10358         /* Focus stays in this column, so we are done */
10359         return TRUE;
10360
10361       /* FIXME: RTL support for the following: */
10362       if (count == -1 && !left)
10363         {
10364           direction = GTK_DIR_RIGHT;
10365           gtk_cell_area_focus (cell_area, direction);
10366         }
10367       else if (count == 1 && !right)
10368         {
10369           direction = GTK_DIR_LEFT;
10370           gtk_cell_area_focus (cell_area, direction);
10371         }
10372
10373       return FALSE;
10374     }
10375
10376   return gtk_cell_area_focus (cell_area, direction);
10377 }
10378
10379 static void
10380 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10381                                       gint         count)
10382 {
10383   GtkRBTree *cursor_tree = NULL;
10384   GtkRBNode *cursor_node = NULL;
10385   GtkTreePath *cursor_path = NULL;
10386   GtkTreeViewColumn *column;
10387   GtkTreeIter iter;
10388   GList *list;
10389   gboolean found_column = FALSE;
10390   gboolean rtl;
10391   GtkDirectionType direction;
10392
10393   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10394
10395   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10396     return;
10397
10398   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10399     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10400   else
10401     return;
10402
10403   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
10404   if (cursor_tree == NULL)
10405     return;
10406   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10407     {
10408       gtk_tree_path_free (cursor_path);
10409       return;
10410     }
10411   gtk_tree_path_free (cursor_path);
10412
10413   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10414   if (tree_view->priv->focus_column)
10415     {
10416       for (; list; list = (rtl ? list->prev : list->next))
10417         {
10418           if (list->data == tree_view->priv->focus_column)
10419             break;
10420         }
10421     }
10422
10423   switch (count)
10424     {
10425       case -1:
10426         direction = rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10427         break;
10428
10429       case 1:
10430         direction = rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
10431         break;
10432     }
10433
10434   while (list)
10435     {
10436       gboolean left, right;
10437
10438       column = list->data;
10439       if (gtk_tree_view_column_get_visible (column) == FALSE)
10440         goto loop_end;
10441
10442       gtk_tree_view_column_cell_set_cell_data (column,
10443                                                tree_view->priv->model,
10444                                                &iter,
10445                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10446                                                cursor_node->children?TRUE:FALSE);
10447
10448       if (rtl)
10449         {
10450           right = list->prev ? TRUE : FALSE;
10451           left = list->next ? TRUE : FALSE;
10452         }
10453       else
10454         {
10455           left = list->prev ? TRUE : FALSE;
10456           right = list->next ? TRUE : FALSE;
10457
10458         }
10459       if (gtk_tree_view_move_focus_column (tree_view, column, count, left, right))
10460         {
10461           tree_view->priv->focus_column = column;
10462           found_column = TRUE;
10463           break;
10464         }
10465     loop_end:
10466       if (count == 1)
10467         list = rtl ? list->prev : list->next;
10468       else
10469         list = rtl ? list->next : list->prev;
10470     }
10471
10472   if (found_column)
10473     {
10474       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10475         _gtk_tree_view_queue_draw_node (tree_view,
10476                                         cursor_tree,
10477                                         cursor_node,
10478                                         NULL);
10479       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10480       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10481     }
10482   else
10483     {
10484       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10485     }
10486
10487   gtk_tree_view_clamp_column_visible (tree_view,
10488                                       tree_view->priv->focus_column, TRUE);
10489 }
10490
10491 static void
10492 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10493                                      gint         count)
10494 {
10495   GtkRBTree *cursor_tree;
10496   GtkRBNode *cursor_node;
10497   GtkTreePath *path;
10498   GtkTreePath *old_path;
10499
10500   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10501     return;
10502
10503   g_return_if_fail (tree_view->priv->tree != NULL);
10504
10505   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10506
10507   cursor_tree = tree_view->priv->tree;
10508   cursor_node = cursor_tree->root;
10509
10510   if (count == -1)
10511     {
10512       while (cursor_node && cursor_node->left != cursor_tree->nil)
10513         cursor_node = cursor_node->left;
10514
10515       /* Now go forward to find the first focusable row. */
10516       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10517       search_first_focusable_path (tree_view, &path,
10518                                    TRUE, &cursor_tree, &cursor_node);
10519     }
10520   else
10521     {
10522       do
10523         {
10524           while (cursor_node && cursor_node->right != cursor_tree->nil)
10525             cursor_node = cursor_node->right;
10526           if (cursor_node->children == NULL)
10527             break;
10528
10529           cursor_tree = cursor_node->children;
10530           cursor_node = cursor_tree->root;
10531         }
10532       while (1);
10533
10534       /* Now go backwards to find last focusable row. */
10535       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10536       search_first_focusable_path (tree_view, &path,
10537                                    FALSE, &cursor_tree, &cursor_node);
10538     }
10539
10540   if (!path)
10541     goto cleanup;
10542
10543   if (gtk_tree_path_compare (old_path, path))
10544     {
10545       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10546       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10547     }
10548   else
10549     {
10550       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10551     }
10552
10553 cleanup:
10554   gtk_tree_path_free (old_path);
10555   gtk_tree_path_free (path);
10556 }
10557
10558 static gboolean
10559 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10560 {
10561   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10562     return FALSE;
10563
10564   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10565     return FALSE;
10566
10567   gtk_tree_selection_select_all (tree_view->priv->selection);
10568
10569   return TRUE;
10570 }
10571
10572 static gboolean
10573 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10574 {
10575   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10576     return FALSE;
10577
10578   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10579     return FALSE;
10580
10581   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10582
10583   return TRUE;
10584 }
10585
10586 static gboolean
10587 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10588                                       gboolean     start_editing)
10589 {
10590   GtkRBTree *new_tree = NULL;
10591   GtkRBNode *new_node = NULL;
10592   GtkRBTree *cursor_tree = NULL;
10593   GtkRBNode *cursor_node = NULL;
10594   GtkTreePath *cursor_path = NULL;
10595   GtkTreeSelectMode mode = 0;
10596
10597   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10598     return FALSE;
10599
10600   if (tree_view->priv->cursor)
10601     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10602
10603   if (cursor_path == NULL)
10604     return FALSE;
10605
10606   _gtk_tree_view_find_node (tree_view, cursor_path,
10607                             &cursor_tree, &cursor_node);
10608
10609   if (cursor_tree == NULL)
10610     {
10611       gtk_tree_path_free (cursor_path);
10612       return FALSE;
10613     }
10614
10615   if (!tree_view->priv->shift_pressed && start_editing &&
10616       tree_view->priv->focus_column)
10617     {
10618       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10619         {
10620           gtk_tree_path_free (cursor_path);
10621           return TRUE;
10622         }
10623     }
10624
10625   if (tree_view->priv->ctrl_pressed)
10626     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10627   if (tree_view->priv->shift_pressed)
10628     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10629
10630   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10631                                             cursor_node,
10632                                             cursor_tree,
10633                                             cursor_path,
10634                                             mode,
10635                                             FALSE);
10636
10637   /* We bail out if the original (tree, node) don't exist anymore after
10638    * handling the selection-changed callback.  We do return TRUE because
10639    * the key press has been handled at this point.
10640    */
10641   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10642
10643   if (cursor_tree != new_tree || cursor_node != new_node)
10644     return FALSE;
10645
10646   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10647
10648   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10649   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10650
10651   if (!tree_view->priv->shift_pressed)
10652     gtk_tree_view_row_activated (tree_view, cursor_path,
10653                                  tree_view->priv->focus_column);
10654     
10655   gtk_tree_path_free (cursor_path);
10656
10657   return TRUE;
10658 }
10659
10660 static gboolean
10661 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10662 {
10663   GtkRBTree *new_tree = NULL;
10664   GtkRBNode *new_node = NULL;
10665   GtkRBTree *cursor_tree = NULL;
10666   GtkRBNode *cursor_node = NULL;
10667   GtkTreePath *cursor_path = NULL;
10668
10669   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10670     return FALSE;
10671
10672   cursor_path = NULL;
10673   if (tree_view->priv->cursor)
10674     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10675
10676   if (cursor_path == NULL)
10677     return FALSE;
10678
10679   _gtk_tree_view_find_node (tree_view, cursor_path,
10680                             &cursor_tree, &cursor_node);
10681   if (cursor_tree == NULL)
10682     {
10683       gtk_tree_path_free (cursor_path);
10684       return FALSE;
10685     }
10686
10687   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10688                                             cursor_node,
10689                                             cursor_tree,
10690                                             cursor_path,
10691                                             GTK_TREE_SELECT_MODE_TOGGLE,
10692                                             FALSE);
10693
10694   /* We bail out if the original (tree, node) don't exist anymore after
10695    * handling the selection-changed callback.  We do return TRUE because
10696    * the key press has been handled at this point.
10697    */
10698   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10699
10700   if (cursor_tree != new_tree || cursor_node != new_node)
10701     return FALSE;
10702
10703   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10704
10705   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10706   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10707   gtk_tree_path_free (cursor_path);
10708
10709   return TRUE;
10710 }
10711
10712 static gboolean
10713 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10714                                                gboolean     logical,
10715                                                gboolean     expand,
10716                                                gboolean     open_all)
10717 {
10718   GtkTreePath *cursor_path = NULL;
10719   GtkRBTree *tree;
10720   GtkRBNode *node;
10721
10722   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10723     return FALSE;
10724
10725   cursor_path = NULL;
10726   if (tree_view->priv->cursor)
10727     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10728
10729   if (cursor_path == NULL)
10730     return FALSE;
10731
10732   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10733     return FALSE;
10734
10735   /* Don't handle the event if we aren't an expander */
10736   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10737     return FALSE;
10738
10739   if (!logical
10740       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10741     expand = !expand;
10742
10743   if (expand)
10744     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10745   else
10746     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10747
10748   gtk_tree_path_free (cursor_path);
10749
10750   return TRUE;
10751 }
10752
10753 static gboolean
10754 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10755 {
10756   GtkRBTree *cursor_tree = NULL;
10757   GtkRBNode *cursor_node = NULL;
10758   GtkTreePath *cursor_path = NULL;
10759   GdkModifierType state;
10760
10761   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10762     goto out;
10763
10764   cursor_path = NULL;
10765   if (tree_view->priv->cursor)
10766     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10767
10768   if (cursor_path == NULL)
10769     goto out;
10770
10771   _gtk_tree_view_find_node (tree_view, cursor_path,
10772                             &cursor_tree, &cursor_node);
10773   if (cursor_tree == NULL)
10774     {
10775       gtk_tree_path_free (cursor_path);
10776       goto out;
10777     }
10778
10779   if (cursor_tree->parent_node)
10780     {
10781       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10782       cursor_node = cursor_tree->parent_node;
10783       cursor_tree = cursor_tree->parent_tree;
10784
10785       gtk_tree_path_up (cursor_path);
10786
10787       if (gtk_get_current_event_state (&state))
10788         {
10789           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10790             tree_view->priv->ctrl_pressed = TRUE;
10791         }
10792
10793       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10794       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10795
10796       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10797       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10798       gtk_tree_path_free (cursor_path);
10799
10800       tree_view->priv->ctrl_pressed = FALSE;
10801
10802       return TRUE;
10803     }
10804
10805  out:
10806
10807   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10808   return FALSE;
10809 }
10810
10811 static gboolean
10812 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10813 {
10814   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10815   tree_view->priv->typeselect_flush_timeout = 0;
10816
10817   return FALSE;
10818 }
10819
10820 /* Cut and paste from gtkwindow.c */
10821 static void
10822 send_focus_change (GtkWidget *widget,
10823                    GdkDevice *device,
10824                    gboolean   in)
10825 {
10826   GdkDeviceManager *device_manager;
10827   GList *devices, *d;
10828
10829   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10830   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10831   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10832   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10833
10834   for (d = devices; d; d = d->next)
10835     {
10836       GdkDevice *dev = d->data;
10837       GdkEvent *fevent;
10838       GdkWindow *window;
10839
10840       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10841         continue;
10842
10843       window = gtk_widget_get_window (widget);
10844
10845       /* Skip non-master keyboards that haven't
10846        * selected for events from this window
10847        */
10848       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10849           !gdk_window_get_device_events (window, dev))
10850         continue;
10851
10852       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10853
10854       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10855       fevent->focus_change.window = g_object_ref (window);
10856       fevent->focus_change.in = in;
10857       gdk_event_set_device (fevent, device);
10858
10859       gtk_widget_send_focus_change (widget, fevent);
10860
10861       gdk_event_free (fevent);
10862     }
10863 }
10864
10865 static void
10866 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10867 {
10868   GtkWidget *frame, *vbox, *toplevel;
10869   GdkScreen *screen;
10870
10871   if (tree_view->priv->search_custom_entry_set)
10872     return;
10873
10874   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10875   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10876
10877    if (tree_view->priv->search_window != NULL)
10878      {
10879        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10880          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10881                                       GTK_WINDOW (tree_view->priv->search_window));
10882        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10883          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10884                                          GTK_WINDOW (tree_view->priv->search_window));
10885
10886        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10887
10888        return;
10889      }
10890    
10891   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10892   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10893
10894   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10895     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10896                                  GTK_WINDOW (tree_view->priv->search_window));
10897
10898   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10899                             GDK_WINDOW_TYPE_HINT_UTILITY);
10900   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10901   g_signal_connect (tree_view->priv->search_window, "delete-event",
10902                     G_CALLBACK (gtk_tree_view_search_delete_event),
10903                     tree_view);
10904   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10905                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10906                     tree_view);
10907   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10908                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10909                     tree_view);
10910   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10911                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10912                     tree_view);
10913
10914   frame = gtk_frame_new (NULL);
10915   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10916   gtk_widget_show (frame);
10917   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10918
10919   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10920   gtk_widget_show (vbox);
10921   gtk_container_add (GTK_CONTAINER (frame), vbox);
10922   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10923
10924   /* add entry */
10925   tree_view->priv->search_entry = gtk_entry_new ();
10926   gtk_widget_show (tree_view->priv->search_entry);
10927   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10928                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10929                     tree_view);
10930   g_signal_connect (tree_view->priv->search_entry,
10931                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10932                     tree_view);
10933
10934   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
10935                     "preedit-changed",
10936                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10937                     tree_view);
10938
10939   gtk_container_add (GTK_CONTAINER (vbox),
10940                      tree_view->priv->search_entry);
10941
10942   gtk_widget_realize (tree_view->priv->search_entry);
10943 }
10944
10945 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10946  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10947  */
10948 static gboolean
10949 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10950                                              GdkDevice   *device,
10951                                              gboolean     keybinding)
10952 {
10953   /* We only start interactive search if we have focus or the columns
10954    * have focus.  If one of our children have focus, we don't want to
10955    * start the search.
10956    */
10957   GList *list;
10958   gboolean found_focus = FALSE;
10959   GtkWidgetClass *entry_parent_class;
10960   
10961   if (!tree_view->priv->enable_search && !keybinding)
10962     return FALSE;
10963
10964   if (tree_view->priv->search_custom_entry_set)
10965     return FALSE;
10966
10967   if (tree_view->priv->search_window != NULL &&
10968       gtk_widget_get_visible (tree_view->priv->search_window))
10969     return TRUE;
10970
10971   for (list = tree_view->priv->columns; list; list = list->next)
10972     {
10973       GtkTreeViewColumn *column;
10974       GtkWidget         *button;
10975
10976       column = list->data;
10977       if (!gtk_tree_view_column_get_visible (column))
10978         continue;
10979
10980       button = gtk_tree_view_column_get_button (column);
10981       if (gtk_widget_has_focus (button))
10982         {
10983           found_focus = TRUE;
10984           break;
10985         }
10986     }
10987   
10988   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10989     found_focus = TRUE;
10990
10991   if (!found_focus)
10992     return FALSE;
10993
10994   if (tree_view->priv->search_column < 0)
10995     return FALSE;
10996
10997   gtk_tree_view_ensure_interactive_directory (tree_view);
10998
10999   if (keybinding)
11000     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11001
11002   /* done, show it */
11003   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11004   gtk_widget_show (tree_view->priv->search_window);
11005   if (tree_view->priv->search_entry_changed_id == 0)
11006     {
11007       tree_view->priv->search_entry_changed_id =
11008         g_signal_connect (tree_view->priv->search_entry, "changed",
11009                           G_CALLBACK (gtk_tree_view_search_init),
11010                           tree_view);
11011     }
11012
11013   tree_view->priv->typeselect_flush_timeout =
11014     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11015                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11016                    tree_view);
11017
11018   /* Grab focus will select all the text.  We don't want that to happen, so we
11019    * call the parent instance and bypass the selection change.  This is probably
11020    * really non-kosher. */
11021   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11022   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11023
11024   /* send focus-in event */
11025   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11026
11027   /* search first matching iter */
11028   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11029
11030   return TRUE;
11031 }
11032
11033 static gboolean
11034 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11035 {
11036   return gtk_tree_view_real_start_interactive_search (tree_view,
11037                                                       gtk_get_current_event_device (),
11038                                                       TRUE);
11039 }
11040
11041 /* this function returns the new width of the column being resized given
11042  * the column and x position of the cursor; the x cursor position is passed
11043  * in as a pointer and automagicly corrected if it's beyond min/max limits
11044  */
11045 static gint
11046 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11047                                 gint       i,
11048                                 gint      *x)
11049 {
11050   GtkAllocation allocation;
11051   GtkTreeViewColumn *column;
11052   GtkRequisition button_req;
11053   gint max_width, min_width;
11054   gint width;
11055   gboolean rtl;
11056
11057   /* first translate the x position from widget->window
11058    * to clist->clist_window
11059    */
11060   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11061   column = g_list_nth (tree_view->priv->columns, i)->data;
11062   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11063   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11064
11065   /* Clamp down the value */
11066   min_width = gtk_tree_view_column_get_min_width (column);
11067   if (min_width == -1)
11068     {
11069       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11070       width = MAX (button_req.width, width);
11071     }
11072   else
11073     width = MAX (min_width, width);
11074
11075   max_width = gtk_tree_view_column_get_max_width (column);
11076   if (max_width != -1)
11077     width = MIN (width, max_width);
11078
11079   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11080
11081   return width;
11082 }
11083
11084
11085 /* FIXME this adjust_allocation is a big cut-and-paste from
11086  * GtkCList, needs to be some "official" way to do this
11087  * factored out.
11088  */
11089 typedef struct
11090 {
11091   GdkWindow *window;
11092   int dx;
11093   int dy;
11094 } ScrollData;
11095
11096 /* The window to which widget->window is relative */
11097 #define ALLOCATION_WINDOW(widget)               \
11098    (!gtk_widget_get_has_window (widget) ?                   \
11099     gtk_widget_get_window (widget) :                        \
11100     gdk_window_get_parent (gtk_widget_get_window (widget)))
11101
11102 static void
11103 adjust_allocation_recurse (GtkWidget *widget,
11104                            gpointer   data)
11105 {
11106   GtkAllocation allocation;
11107   ScrollData *scroll_data = data;
11108
11109   /* Need to really size allocate instead of just poking
11110    * into widget->allocation if the widget is not realized.
11111    * FIXME someone figure out why this was.
11112    */
11113   gtk_widget_get_allocation (widget, &allocation);
11114   if (!gtk_widget_get_realized (widget))
11115     {
11116       if (gtk_widget_get_visible (widget))
11117         {
11118           GdkRectangle tmp_rectangle = allocation;
11119           tmp_rectangle.x += scroll_data->dx;
11120           tmp_rectangle.y += scroll_data->dy;
11121           
11122           gtk_widget_size_allocate (widget, &tmp_rectangle);
11123         }
11124     }
11125   else
11126     {
11127       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11128         {
11129           allocation.x += scroll_data->dx;
11130           allocation.y += scroll_data->dy;
11131           gtk_widget_set_allocation (widget, &allocation);
11132
11133           if (GTK_IS_CONTAINER (widget))
11134             gtk_container_forall (GTK_CONTAINER (widget),
11135                                   adjust_allocation_recurse,
11136                                   data);
11137         }
11138     }
11139 }
11140
11141 static void
11142 adjust_allocation (GtkWidget *widget,
11143                    int        dx,
11144                    int        dy)
11145 {
11146   ScrollData scroll_data;
11147
11148   if (gtk_widget_get_realized (widget))
11149     scroll_data.window = ALLOCATION_WINDOW (widget);
11150   else
11151     scroll_data.window = NULL;
11152     
11153   scroll_data.dx = dx;
11154   scroll_data.dy = dy;
11155   
11156   adjust_allocation_recurse (widget, &scroll_data);
11157 }
11158
11159 /* Callbacks */
11160 static void
11161 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11162                                   GtkTreeView   *tree_view)
11163 {
11164   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11165     {
11166       gint dy;
11167         
11168       gdk_window_move (tree_view->priv->bin_window,
11169                        - tree_view->priv->hadjustment->value,
11170                        gtk_tree_view_get_effective_header_height (tree_view));
11171       gdk_window_move (tree_view->priv->header_window,
11172                        - tree_view->priv->hadjustment->value,
11173                        0);
11174       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
11175       if (dy)
11176         {
11177           update_prelight (tree_view,
11178                            tree_view->priv->event_last_x,
11179                            tree_view->priv->event_last_y - dy);
11180
11181           if (tree_view->priv->edited_column)
11182             {
11183               GList *list;
11184               GtkTreeViewChild *child = NULL;
11185               GtkCellEditable *edit_widget;
11186               GtkCellArea *area;
11187
11188               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11189               edit_widget = gtk_cell_area_get_edit_widget (area);
11190               if (GTK_IS_WIDGET (edit_widget))
11191                 {
11192                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11193
11194                   for (list = tree_view->priv->children; list; list = list->next)
11195                     {
11196                       child = (GtkTreeViewChild *)list->data;
11197                       if (child->widget == GTK_WIDGET (edit_widget))
11198                         {
11199                           child->y += dy;
11200                           break;
11201                         }
11202                     }
11203                 }
11204             }
11205         }
11206       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11207
11208       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
11209         {
11210           /* update our dy and top_row */
11211           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
11212
11213           if (!tree_view->priv->in_top_row_to_dy)
11214             gtk_tree_view_dy_to_top_row (tree_view);
11215         }
11216
11217       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
11218       gtk_tree_view_bin_process_updates (tree_view);
11219     }
11220 }
11221
11222 \f
11223
11224 /* Public methods
11225  */
11226
11227 /**
11228  * gtk_tree_view_new:
11229  *
11230  * Creates a new #GtkTreeView widget.
11231  *
11232  * Return value: A newly created #GtkTreeView widget.
11233  **/
11234 GtkWidget *
11235 gtk_tree_view_new (void)
11236 {
11237   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11238 }
11239
11240 /**
11241  * gtk_tree_view_new_with_model:
11242  * @model: the model.
11243  *
11244  * Creates a new #GtkTreeView widget with the model initialized to @model.
11245  *
11246  * Return value: A newly created #GtkTreeView widget.
11247  **/
11248 GtkWidget *
11249 gtk_tree_view_new_with_model (GtkTreeModel *model)
11250 {
11251   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11252 }
11253
11254 /* Public Accessors
11255  */
11256
11257 /**
11258  * gtk_tree_view_get_model:
11259  * @tree_view: a #GtkTreeView
11260  *
11261  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11262  * model is unset.
11263  *
11264  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11265  **/
11266 GtkTreeModel *
11267 gtk_tree_view_get_model (GtkTreeView *tree_view)
11268 {
11269   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11270
11271   return tree_view->priv->model;
11272 }
11273
11274 /**
11275  * gtk_tree_view_set_model:
11276  * @tree_view: A #GtkTreeNode.
11277  * @model: (allow-none): The model.
11278  *
11279  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11280  * set, it will remove it before setting the new model.  If @model is %NULL,
11281  * then it will unset the old model.
11282  **/
11283 void
11284 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11285                          GtkTreeModel *model)
11286 {
11287   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11288   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11289
11290   if (model == tree_view->priv->model)
11291     return;
11292
11293   if (tree_view->priv->scroll_to_path)
11294     {
11295       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11296       tree_view->priv->scroll_to_path = NULL;
11297     }
11298
11299   if (tree_view->priv->model)
11300     {
11301       GList *tmplist = tree_view->priv->columns;
11302
11303       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11304       gtk_tree_view_stop_editing (tree_view, TRUE);
11305
11306       remove_expand_collapse_timeout (tree_view);
11307
11308       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11309                                             gtk_tree_view_row_changed,
11310                                             tree_view);
11311       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11312                                             gtk_tree_view_row_inserted,
11313                                             tree_view);
11314       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11315                                             gtk_tree_view_row_has_child_toggled,
11316                                             tree_view);
11317       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11318                                             gtk_tree_view_row_deleted,
11319                                             tree_view);
11320       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11321                                             gtk_tree_view_rows_reordered,
11322                                             tree_view);
11323
11324       for (; tmplist; tmplist = tmplist->next)
11325         _gtk_tree_view_column_unset_model (tmplist->data,
11326                                            tree_view->priv->model);
11327
11328       if (tree_view->priv->tree)
11329         gtk_tree_view_free_rbtree (tree_view);
11330
11331       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11332       tree_view->priv->drag_dest_row = NULL;
11333       gtk_tree_row_reference_free (tree_view->priv->cursor);
11334       tree_view->priv->cursor = NULL;
11335       gtk_tree_row_reference_free (tree_view->priv->anchor);
11336       tree_view->priv->anchor = NULL;
11337       gtk_tree_row_reference_free (tree_view->priv->top_row);
11338       tree_view->priv->top_row = NULL;
11339       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11340       tree_view->priv->scroll_to_path = NULL;
11341
11342       tree_view->priv->scroll_to_column = NULL;
11343
11344       g_object_unref (tree_view->priv->model);
11345
11346       tree_view->priv->search_column = -1;
11347       tree_view->priv->fixed_height_check = 0;
11348       tree_view->priv->fixed_height = -1;
11349       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11350       tree_view->priv->last_button_x = -1;
11351       tree_view->priv->last_button_y = -1;
11352     }
11353
11354   tree_view->priv->model = model;
11355
11356   if (tree_view->priv->model)
11357     {
11358       gint i;
11359       GtkTreePath *path;
11360       GtkTreeIter iter;
11361       GtkTreeModelFlags flags;
11362
11363       if (tree_view->priv->search_column == -1)
11364         {
11365           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11366             {
11367               GType type = gtk_tree_model_get_column_type (model, i);
11368
11369               if (g_value_type_transformable (type, G_TYPE_STRING))
11370                 {
11371                   tree_view->priv->search_column = i;
11372                   break;
11373                 }
11374             }
11375         }
11376
11377       g_object_ref (tree_view->priv->model);
11378       g_signal_connect (tree_view->priv->model,
11379                         "row-changed",
11380                         G_CALLBACK (gtk_tree_view_row_changed),
11381                         tree_view);
11382       g_signal_connect (tree_view->priv->model,
11383                         "row-inserted",
11384                         G_CALLBACK (gtk_tree_view_row_inserted),
11385                         tree_view);
11386       g_signal_connect (tree_view->priv->model,
11387                         "row-has-child-toggled",
11388                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11389                         tree_view);
11390       g_signal_connect (tree_view->priv->model,
11391                         "row-deleted",
11392                         G_CALLBACK (gtk_tree_view_row_deleted),
11393                         tree_view);
11394       g_signal_connect (tree_view->priv->model,
11395                         "rows-reordered",
11396                         G_CALLBACK (gtk_tree_view_rows_reordered),
11397                         tree_view);
11398
11399       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11400       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11401         tree_view->priv->is_list = TRUE;
11402       else
11403         tree_view->priv->is_list = FALSE;
11404
11405       path = gtk_tree_path_new_first ();
11406       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11407         {
11408           tree_view->priv->tree = _gtk_rbtree_new ();
11409           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11410         }
11411       gtk_tree_path_free (path);
11412
11413       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11414       install_presize_handler (tree_view);
11415     }
11416
11417   g_object_notify (G_OBJECT (tree_view), "model");
11418
11419   if (tree_view->priv->selection)
11420   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11421
11422   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11423     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11424 }
11425
11426 /**
11427  * gtk_tree_view_get_selection:
11428  * @tree_view: A #GtkTreeView.
11429  *
11430  * Gets the #GtkTreeSelection associated with @tree_view.
11431  *
11432  * Return value: (transfer none): A #GtkTreeSelection object.
11433  **/
11434 GtkTreeSelection *
11435 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11436 {
11437   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11438
11439   return tree_view->priv->selection;
11440 }
11441
11442 /**
11443  * gtk_tree_view_get_hadjustment:
11444  * @tree_view: A #GtkTreeView
11445  *
11446  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11447  *
11448  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11449  *     if none is currently being used.
11450  *
11451  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11452  **/
11453 GtkAdjustment *
11454 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11455 {
11456   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11457
11458   return tree_view->priv->hadjustment;
11459 }
11460
11461 /**
11462  * gtk_tree_view_set_hadjustment:
11463  * @tree_view: A #GtkTreeView
11464  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11465  *
11466  * Sets the #GtkAdjustment for the current horizontal aspect.
11467  *
11468  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11469  **/
11470 void
11471 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11472                                GtkAdjustment *adjustment)
11473 {
11474   GtkTreeViewPrivate *priv = tree_view->priv;
11475
11476   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11477   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11478
11479   if (adjustment && priv->hadjustment == adjustment)
11480     return;
11481
11482   if (priv->hadjustment != NULL)
11483     {
11484       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11485                                             gtk_tree_view_adjustment_changed,
11486                                             tree_view);
11487       g_object_unref (priv->hadjustment);
11488     }
11489
11490   if (adjustment == NULL)
11491     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11492                                      0.0, 0.0, 0.0);
11493
11494   g_signal_connect (adjustment, "value-changed",
11495                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11496   priv->hadjustment = g_object_ref_sink (adjustment);
11497   /* FIXME: Adjustment should probably be populated here with fresh values, but
11498    * internal details are too complicated for me to decipher right now.
11499    */
11500   gtk_tree_view_adjustment_changed (NULL, tree_view);
11501
11502   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11503 }
11504
11505 /**
11506  * gtk_tree_view_get_vadjustment:
11507  * @tree_view: A #GtkTreeView
11508  *
11509  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11510  *
11511  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11512  *     if none is currently being used.
11513  *
11514  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11515  **/
11516 GtkAdjustment *
11517 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11518 {
11519   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11520
11521   return tree_view->priv->vadjustment;
11522 }
11523
11524 /**
11525  * gtk_tree_view_set_vadjustment:
11526  * @tree_view: A #GtkTreeView
11527  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11528  *
11529  * Sets the #GtkAdjustment for the current vertical aspect.
11530  *
11531  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11532  **/
11533 void
11534 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11535                                GtkAdjustment *adjustment)
11536 {
11537   GtkTreeViewPrivate *priv = tree_view->priv;
11538
11539   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11540   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11541
11542   if (adjustment && priv->vadjustment == adjustment)
11543     return;
11544
11545   if (priv->vadjustment != NULL)
11546     {
11547       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11548                                             gtk_tree_view_adjustment_changed,
11549                                             tree_view);
11550       g_object_unref (priv->vadjustment);
11551     }
11552
11553   if (adjustment == NULL)
11554     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11555                                      0.0, 0.0, 0.0);
11556
11557   g_signal_connect (adjustment, "value-changed",
11558                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11559   priv->vadjustment = g_object_ref_sink (adjustment);
11560   /* FIXME: Adjustment should probably be populated here with fresh values, but
11561    * internal details are too complicated for me to decipher right now.
11562    */
11563   gtk_tree_view_adjustment_changed (NULL, tree_view);
11564   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11565 }
11566
11567 /* Column and header operations */
11568
11569 /**
11570  * gtk_tree_view_get_headers_visible:
11571  * @tree_view: A #GtkTreeView.
11572  *
11573  * Returns %TRUE if the headers on the @tree_view are visible.
11574  *
11575  * Return value: Whether the headers are visible or not.
11576  **/
11577 gboolean
11578 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11579 {
11580   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11581
11582   return tree_view->priv->headers_visible;
11583 }
11584
11585 /**
11586  * gtk_tree_view_set_headers_visible:
11587  * @tree_view: A #GtkTreeView.
11588  * @headers_visible: %TRUE if the headers are visible
11589  *
11590  * Sets the visibility state of the headers.
11591  **/
11592 void
11593 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11594                                    gboolean     headers_visible)
11595 {
11596   gint x, y;
11597   GList *list;
11598   GtkTreeViewColumn *column;
11599   GtkAllocation allocation;
11600   GtkWidget *button;
11601
11602   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11603
11604   headers_visible = !! headers_visible;
11605
11606   if (tree_view->priv->headers_visible == headers_visible)
11607     return;
11608
11609   tree_view->priv->headers_visible = headers_visible == TRUE;
11610
11611   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11612     {
11613       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11614       if (headers_visible)
11615         {
11616           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11617           gdk_window_move_resize (tree_view->priv->bin_window,
11618                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11619                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11620
11621           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11622             gtk_tree_view_map_buttons (tree_view);
11623         }
11624       else
11625         {
11626           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11627
11628           for (list = tree_view->priv->columns; list; list = list->next)
11629             {
11630               column = list->data;
11631               button = gtk_tree_view_column_get_button (column);
11632               gtk_widget_unmap (button);
11633             }
11634           gdk_window_hide (tree_view->priv->header_window);
11635         }
11636     }
11637
11638   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11639   tree_view->priv->vadjustment->page_size = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
11640   tree_view->priv->vadjustment->page_increment = (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2;
11641   tree_view->priv->vadjustment->lower = 0;
11642   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11643   gtk_adjustment_changed (tree_view->priv->vadjustment);
11644
11645   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11646
11647   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11648 }
11649
11650 /**
11651  * gtk_tree_view_columns_autosize:
11652  * @tree_view: A #GtkTreeView.
11653  *
11654  * Resizes all columns to their optimal width. Only works after the
11655  * treeview has been realized.
11656  **/
11657 void
11658 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11659 {
11660   gboolean dirty = FALSE;
11661   GList *list;
11662   GtkTreeViewColumn *column;
11663
11664   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11665
11666   for (list = tree_view->priv->columns; list; list = list->next)
11667     {
11668       column = list->data;
11669       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11670         continue;
11671       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11672       dirty = TRUE;
11673     }
11674
11675   if (dirty)
11676     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11677 }
11678
11679 /**
11680  * gtk_tree_view_set_headers_clickable:
11681  * @tree_view: A #GtkTreeView.
11682  * @setting: %TRUE if the columns are clickable.
11683  *
11684  * Allow the column title buttons to be clicked.
11685  **/
11686 void
11687 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11688                                      gboolean   setting)
11689 {
11690   GList *list;
11691
11692   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11693
11694   for (list = tree_view->priv->columns; list; list = list->next)
11695     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11696
11697   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11698 }
11699
11700
11701 /**
11702  * gtk_tree_view_get_headers_clickable:
11703  * @tree_view: A #GtkTreeView.
11704  *
11705  * Returns whether all header columns are clickable.
11706  *
11707  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11708  *
11709  * Since: 2.10
11710  **/
11711 gboolean 
11712 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11713 {
11714   GList *list;
11715   
11716   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11717
11718   for (list = tree_view->priv->columns; list; list = list->next)
11719     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11720       return FALSE;
11721
11722   return TRUE;
11723 }
11724
11725 /**
11726  * gtk_tree_view_set_rules_hint
11727  * @tree_view: a #GtkTreeView
11728  * @setting: %TRUE if the tree requires reading across rows
11729  *
11730  * This function tells GTK+ that the user interface for your
11731  * application requires users to read across tree rows and associate
11732  * cells with one another. By default, GTK+ will then render the tree
11733  * with alternating row colors. Do <emphasis>not</emphasis> use it
11734  * just because you prefer the appearance of the ruled tree; that's a
11735  * question for the theme. Some themes will draw tree rows in
11736  * alternating colors even when rules are turned off, and users who
11737  * prefer that appearance all the time can choose those themes. You
11738  * should call this function only as a <emphasis>semantic</emphasis>
11739  * hint to the theme engine that your tree makes alternating colors
11740  * useful from a functional standpoint (since it has lots of columns,
11741  * generally).
11742  *
11743  **/
11744 void
11745 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11746                               gboolean      setting)
11747 {
11748   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11749
11750   setting = setting != FALSE;
11751
11752   if (tree_view->priv->has_rules != setting)
11753     {
11754       tree_view->priv->has_rules = setting;
11755       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11756     }
11757
11758   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11759 }
11760
11761 /**
11762  * gtk_tree_view_get_rules_hint
11763  * @tree_view: a #GtkTreeView
11764  *
11765  * Gets the setting set by gtk_tree_view_set_rules_hint().
11766  *
11767  * Return value: %TRUE if rules are useful for the user of this tree
11768  **/
11769 gboolean
11770 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11771 {
11772   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11773
11774   return tree_view->priv->has_rules;
11775 }
11776
11777 /* Public Column functions
11778  */
11779
11780 /**
11781  * gtk_tree_view_append_column:
11782  * @tree_view: A #GtkTreeView.
11783  * @column: The #GtkTreeViewColumn to add.
11784  *
11785  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11786  * mode enabled, then @column must have its "sizing" property set to be
11787  * GTK_TREE_VIEW_COLUMN_FIXED.
11788  *
11789  * Return value: The number of columns in @tree_view after appending.
11790  **/
11791 gint
11792 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11793                              GtkTreeViewColumn *column)
11794 {
11795   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11796   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11797   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11798
11799   return gtk_tree_view_insert_column (tree_view, column, -1);
11800 }
11801
11802
11803 /**
11804  * gtk_tree_view_remove_column:
11805  * @tree_view: A #GtkTreeView.
11806  * @column: The #GtkTreeViewColumn to remove.
11807  *
11808  * Removes @column from @tree_view.
11809  *
11810  * Return value: The number of columns in @tree_view after removing.
11811  **/
11812 gint
11813 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11814                              GtkTreeViewColumn *column)
11815 {
11816   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11817   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11818   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11819
11820   if (tree_view->priv->focus_column == column)
11821     tree_view->priv->focus_column = NULL;
11822
11823   if (tree_view->priv->edited_column == column)
11824     {
11825       gtk_tree_view_stop_editing (tree_view, TRUE);
11826
11827       /* no need to, but just to be sure ... */
11828       tree_view->priv->edited_column = NULL;
11829     }
11830
11831   if (tree_view->priv->expander_column == column)
11832     tree_view->priv->expander_column = NULL;
11833
11834   g_signal_handlers_disconnect_by_func (column,
11835                                         G_CALLBACK (column_sizing_notify),
11836                                         tree_view);
11837
11838   _gtk_tree_view_column_unset_tree_view (column);
11839
11840   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11841   tree_view->priv->n_columns--;
11842
11843   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11844     {
11845       GList *list;
11846
11847       _gtk_tree_view_column_unrealize_button (column);
11848       for (list = tree_view->priv->columns; list; list = list->next)
11849         {
11850           GtkTreeViewColumn *tmp_column;
11851
11852           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11853           if (gtk_tree_view_column_get_visible (tmp_column))
11854             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11855         }
11856
11857       if (tree_view->priv->n_columns == 0 &&
11858           gtk_tree_view_get_headers_visible (tree_view))
11859         gdk_window_hide (tree_view->priv->header_window);
11860
11861       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11862     }
11863
11864   g_object_unref (column);
11865   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11866
11867   return tree_view->priv->n_columns;
11868 }
11869
11870 /**
11871  * gtk_tree_view_insert_column:
11872  * @tree_view: A #GtkTreeView.
11873  * @column: The #GtkTreeViewColumn to be inserted.
11874  * @position: The position to insert @column in.
11875  *
11876  * This inserts the @column into the @tree_view at @position.  If @position is
11877  * -1, then the column is inserted at the end. If @tree_view has
11878  * "fixed_height" mode enabled, then @column must have its "sizing" property
11879  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11880  *
11881  * Return value: The number of columns in @tree_view after insertion.
11882  **/
11883 gint
11884 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11885                              GtkTreeViewColumn *column,
11886                              gint               position)
11887 {
11888   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11889   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11890   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11891
11892   if (tree_view->priv->fixed_height_mode)
11893     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11894                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11895
11896   g_object_ref_sink (column);
11897
11898   if (tree_view->priv->n_columns == 0 &&
11899       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11900       gtk_tree_view_get_headers_visible (tree_view))
11901     {
11902       gdk_window_show (tree_view->priv->header_window);
11903     }
11904
11905   g_signal_connect (column, "notify::sizing",
11906                     G_CALLBACK (column_sizing_notify), tree_view);
11907
11908   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11909                                             column, position);
11910   tree_view->priv->n_columns++;
11911
11912   _gtk_tree_view_column_set_tree_view (column, tree_view);
11913
11914   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11915     {
11916       GList *list;
11917
11918       _gtk_tree_view_column_realize_button (column);
11919
11920       for (list = tree_view->priv->columns; list; list = list->next)
11921         {
11922           column = GTK_TREE_VIEW_COLUMN (list->data);
11923           if (gtk_tree_view_column_get_visible (column))
11924             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11925         }
11926       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11927     }
11928
11929   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11930
11931   return tree_view->priv->n_columns;
11932 }
11933
11934 /**
11935  * gtk_tree_view_insert_column_with_attributes:
11936  * @tree_view: A #GtkTreeView
11937  * @position: The position to insert the new column in.
11938  * @title: The title to set the header to.
11939  * @cell: The #GtkCellRenderer.
11940  * @Varargs: A %NULL-terminated list of attributes.
11941  *
11942  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11943  * @position.  If @position is -1, then the newly created column is inserted at
11944  * the end.  The column is initialized with the attributes given. If @tree_view
11945  * has "fixed_height" mode enabled, then the new column will have its sizing
11946  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11947  *
11948  * Return value: The number of columns in @tree_view after insertion.
11949  **/
11950 gint
11951 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11952                                              gint             position,
11953                                              const gchar     *title,
11954                                              GtkCellRenderer *cell,
11955                                              ...)
11956 {
11957   GtkTreeViewColumn *column;
11958   gchar *attribute;
11959   va_list args;
11960   gint column_id;
11961
11962   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11963
11964   column = gtk_tree_view_column_new ();
11965   if (tree_view->priv->fixed_height_mode)
11966     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11967
11968   gtk_tree_view_column_set_title (column, title);
11969   gtk_tree_view_column_pack_start (column, cell, TRUE);
11970
11971   va_start (args, cell);
11972
11973   attribute = va_arg (args, gchar *);
11974
11975   while (attribute != NULL)
11976     {
11977       column_id = va_arg (args, gint);
11978       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11979       attribute = va_arg (args, gchar *);
11980     }
11981
11982   va_end (args);
11983
11984   gtk_tree_view_insert_column (tree_view, column, position);
11985
11986   return tree_view->priv->n_columns;
11987 }
11988
11989 /**
11990  * gtk_tree_view_insert_column_with_data_func:
11991  * @tree_view: a #GtkTreeView
11992  * @position: Position to insert, -1 for append
11993  * @title: column title
11994  * @cell: cell renderer for column
11995  * @func: function to set attributes of cell renderer
11996  * @data: data for @func
11997  * @dnotify: destroy notifier for @data
11998  *
11999  * Convenience function that inserts a new column into the #GtkTreeView
12000  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
12001  * attributes (normally using data from the model). See also
12002  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12003  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12004  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12005  *
12006  * Return value: number of columns in the tree view post-insert
12007  **/
12008 gint
12009 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12010                                              gint                       position,
12011                                              const gchar               *title,
12012                                              GtkCellRenderer           *cell,
12013                                              GtkTreeCellDataFunc        func,
12014                                              gpointer                   data,
12015                                              GDestroyNotify             dnotify)
12016 {
12017   GtkTreeViewColumn *column;
12018
12019   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12020
12021   column = gtk_tree_view_column_new ();
12022   if (tree_view->priv->fixed_height_mode)
12023     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12024
12025   gtk_tree_view_column_set_title (column, title);
12026   gtk_tree_view_column_pack_start (column, cell, TRUE);
12027   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12028
12029   gtk_tree_view_insert_column (tree_view, column, position);
12030
12031   return tree_view->priv->n_columns;
12032 }
12033
12034 /**
12035  * gtk_tree_view_get_column:
12036  * @tree_view: A #GtkTreeView.
12037  * @n: The position of the column, counting from 0.
12038  *
12039  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12040  *
12041  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12042  *     position is outside the range of columns.
12043  **/
12044 GtkTreeViewColumn *
12045 gtk_tree_view_get_column (GtkTreeView *tree_view,
12046                           gint         n)
12047 {
12048   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12049
12050   if (n < 0 || n >= tree_view->priv->n_columns)
12051     return NULL;
12052
12053   if (tree_view->priv->columns == NULL)
12054     return NULL;
12055
12056   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12057 }
12058
12059 /**
12060  * gtk_tree_view_get_columns:
12061  * @tree_view: A #GtkTreeView
12062  *
12063  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12064  * The returned list must be freed with g_list_free ().
12065  *
12066  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12067  **/
12068 GList *
12069 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12070 {
12071   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12072
12073   return g_list_copy (tree_view->priv->columns);
12074 }
12075
12076 /**
12077  * gtk_tree_view_move_column_after:
12078  * @tree_view: A #GtkTreeView
12079  * @column: The #GtkTreeViewColumn to be moved.
12080  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12081  *
12082  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12083  * @column is placed in the first position.
12084  **/
12085 void
12086 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12087                                  GtkTreeViewColumn *column,
12088                                  GtkTreeViewColumn *base_column)
12089 {
12090   GList *column_list_el, *base_el = NULL;
12091
12092   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12093
12094   column_list_el = g_list_find (tree_view->priv->columns, column);
12095   g_return_if_fail (column_list_el != NULL);
12096
12097   if (base_column)
12098     {
12099       base_el = g_list_find (tree_view->priv->columns, base_column);
12100       g_return_if_fail (base_el != NULL);
12101     }
12102
12103   if (column_list_el->prev == base_el)
12104     return;
12105
12106   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12107   if (base_el == NULL)
12108     {
12109       column_list_el->prev = NULL;
12110       column_list_el->next = tree_view->priv->columns;
12111       if (column_list_el->next)
12112         column_list_el->next->prev = column_list_el;
12113       tree_view->priv->columns = column_list_el;
12114     }
12115   else
12116     {
12117       column_list_el->prev = base_el;
12118       column_list_el->next = base_el->next;
12119       if (column_list_el->next)
12120         column_list_el->next->prev = column_list_el;
12121       base_el->next = column_list_el;
12122     }
12123
12124   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12125     {
12126       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12127       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12128     }
12129
12130   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12131 }
12132
12133 /**
12134  * gtk_tree_view_set_expander_column:
12135  * @tree_view: A #GtkTreeView
12136  * @column: %NULL, or the column to draw the expander arrow at.
12137  *
12138  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12139  * If @column is %NULL, then the expander arrow is always at the first 
12140  * visible column.
12141  *
12142  * If you do not want expander arrow to appear in your tree, set the 
12143  * expander column to a hidden column.
12144  **/
12145 void
12146 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12147                                    GtkTreeViewColumn *column)
12148 {
12149   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12150   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12151
12152   if (tree_view->priv->expander_column != column)
12153     {
12154       GList *list;
12155
12156       if (column)
12157         {
12158           /* Confirm that column is in tree_view */
12159           for (list = tree_view->priv->columns; list; list = list->next)
12160             if (list->data == column)
12161               break;
12162           g_return_if_fail (list != NULL);
12163         }
12164
12165       tree_view->priv->expander_column = column;
12166       g_object_notify (G_OBJECT (tree_view), "expander-column");
12167     }
12168 }
12169
12170 /**
12171  * gtk_tree_view_get_expander_column:
12172  * @tree_view: A #GtkTreeView
12173  *
12174  * Returns the column that is the current expander column.
12175  * This column has the expander arrow drawn next to it.
12176  *
12177  * Return value: (transfer none): The expander column.
12178  **/
12179 GtkTreeViewColumn *
12180 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12181 {
12182   GList *list;
12183
12184   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12185
12186   for (list = tree_view->priv->columns; list; list = list->next)
12187     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12188       return (GtkTreeViewColumn *) list->data;
12189   return NULL;
12190 }
12191
12192
12193 /**
12194  * gtk_tree_view_set_column_drag_function:
12195  * @tree_view: A #GtkTreeView.
12196  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12197  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12198  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12199  *
12200  * Sets a user function for determining where a column may be dropped when
12201  * dragged.  This function is called on every column pair in turn at the
12202  * beginning of a column drag to determine where a drop can take place.  The
12203  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12204  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12205  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12206  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12207  * @tree_view reverts to the default behavior of allowing all columns to be
12208  * dropped everywhere.
12209  **/
12210 void
12211 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12212                                         GtkTreeViewColumnDropFunc  func,
12213                                         gpointer                   user_data,
12214                                         GDestroyNotify             destroy)
12215 {
12216   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12217
12218   if (tree_view->priv->column_drop_func_data_destroy)
12219     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12220
12221   tree_view->priv->column_drop_func = func;
12222   tree_view->priv->column_drop_func_data = user_data;
12223   tree_view->priv->column_drop_func_data_destroy = destroy;
12224 }
12225
12226 /**
12227  * gtk_tree_view_scroll_to_point:
12228  * @tree_view: a #GtkTreeView
12229  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12230  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12231  *
12232  * Scrolls the tree view such that the top-left corner of the visible
12233  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12234  * in tree coordinates.  The @tree_view must be realized before
12235  * this function is called.  If it isn't, you probably want to be
12236  * using gtk_tree_view_scroll_to_cell().
12237  *
12238  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12239  **/
12240 void
12241 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12242                                gint         tree_x,
12243                                gint         tree_y)
12244 {
12245   GtkAdjustment *hadj;
12246   GtkAdjustment *vadj;
12247
12248   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12249   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12250
12251   hadj = tree_view->priv->hadjustment;
12252   vadj = tree_view->priv->vadjustment;
12253
12254   if (tree_x != -1)
12255     gtk_adjustment_set_value (hadj, tree_x);
12256   if (tree_y != -1)
12257     gtk_adjustment_set_value (vadj, tree_y);
12258 }
12259
12260 /**
12261  * gtk_tree_view_scroll_to_cell:
12262  * @tree_view: A #GtkTreeView.
12263  * @path: (allow-none): The path of the row to move to, or %NULL.
12264  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12265  * @use_align: whether to use alignment arguments, or %FALSE.
12266  * @row_align: The vertical alignment of the row specified by @path.
12267  * @col_align: The horizontal alignment of the column specified by @column.
12268  *
12269  * Moves the alignments of @tree_view to the position specified by @column and
12270  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12271  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12272  * or @path need to be non-%NULL.  @row_align determines where the row is
12273  * placed, and @col_align determines where @column is placed.  Both are expected
12274  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12275  * right/bottom alignment, 0.5 means center.
12276  *
12277  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12278  * tree does the minimum amount of work to scroll the cell onto the screen.
12279  * This means that the cell will be scrolled to the edge closest to its current
12280  * position.  If the cell is currently visible on the screen, nothing is done.
12281  *
12282  * This function only works if the model is set, and @path is a valid row on the
12283  * model.  If the model changes before the @tree_view is realized, the centered
12284  * path will be modified to reflect this change.
12285  **/
12286 void
12287 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12288                               GtkTreePath       *path,
12289                               GtkTreeViewColumn *column,
12290                               gboolean           use_align,
12291                               gfloat             row_align,
12292                               gfloat             col_align)
12293 {
12294   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12295   g_return_if_fail (tree_view->priv->model != NULL);
12296   g_return_if_fail (tree_view->priv->tree != NULL);
12297   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12298   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12299   g_return_if_fail (path != NULL || column != NULL);
12300
12301 #if 0
12302   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12303            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12304 #endif
12305   row_align = CLAMP (row_align, 0.0, 1.0);
12306   col_align = CLAMP (col_align, 0.0, 1.0);
12307
12308
12309   /* Note: Despite the benefits that come from having one code path for the
12310    * scrolling code, we short-circuit validate_visible_area's immplementation as
12311    * it is much slower than just going to the point.
12312    */
12313   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12314       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12315       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12316       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12317     {
12318       if (tree_view->priv->scroll_to_path)
12319         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12320
12321       tree_view->priv->scroll_to_path = NULL;
12322       tree_view->priv->scroll_to_column = NULL;
12323
12324       if (path)
12325         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12326       if (column)
12327         tree_view->priv->scroll_to_column = column;
12328       tree_view->priv->scroll_to_use_align = use_align;
12329       tree_view->priv->scroll_to_row_align = row_align;
12330       tree_view->priv->scroll_to_col_align = col_align;
12331
12332       install_presize_handler (tree_view);
12333     }
12334   else
12335     {
12336       GdkRectangle cell_rect;
12337       GdkRectangle vis_rect;
12338       gint dest_x, dest_y;
12339
12340       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12341       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12342
12343       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12344
12345       dest_x = vis_rect.x;
12346       dest_y = vis_rect.y;
12347
12348       if (column)
12349         {
12350           if (use_align)
12351             {
12352               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12353             }
12354           else
12355             {
12356               if (cell_rect.x < vis_rect.x)
12357                 dest_x = cell_rect.x;
12358               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12359                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12360             }
12361         }
12362
12363       if (path)
12364         {
12365           if (use_align)
12366             {
12367               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12368               dest_y = MAX (dest_y, 0);
12369             }
12370           else
12371             {
12372               if (cell_rect.y < vis_rect.y)
12373                 dest_y = cell_rect.y;
12374               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12375                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12376             }
12377         }
12378
12379       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12380     }
12381 }
12382
12383 /**
12384  * gtk_tree_view_row_activated:
12385  * @tree_view: A #GtkTreeView
12386  * @path: The #GtkTreePath to be activated.
12387  * @column: The #GtkTreeViewColumn to be activated.
12388  *
12389  * Activates the cell determined by @path and @column.
12390  **/
12391 void
12392 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12393                              GtkTreePath       *path,
12394                              GtkTreeViewColumn *column)
12395 {
12396   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12397
12398   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12399 }
12400
12401
12402 static void
12403 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12404                                           GtkRBNode *node,
12405                                           gpointer   data)
12406 {
12407   GtkTreeView *tree_view = data;
12408
12409   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12410       node->children)
12411     {
12412       GtkTreePath *path;
12413       GtkTreeIter iter;
12414
12415       path = _gtk_tree_view_find_path (tree_view, tree, node);
12416       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12417
12418       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12419
12420       gtk_tree_path_free (path);
12421     }
12422
12423   if (node->children)
12424     _gtk_rbtree_traverse (node->children,
12425                           node->children->root,
12426                           G_PRE_ORDER,
12427                           gtk_tree_view_expand_all_emission_helper,
12428                           tree_view);
12429 }
12430
12431 /**
12432  * gtk_tree_view_expand_all:
12433  * @tree_view: A #GtkTreeView.
12434  *
12435  * Recursively expands all nodes in the @tree_view.
12436  **/
12437 void
12438 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12439 {
12440   GtkTreePath *path;
12441   GtkRBTree *tree;
12442   GtkRBNode *node;
12443
12444   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12445
12446   if (tree_view->priv->tree == NULL)
12447     return;
12448
12449   path = gtk_tree_path_new_first ();
12450   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12451
12452   while (node)
12453     {
12454       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12455       node = _gtk_rbtree_next (tree, node);
12456       gtk_tree_path_next (path);
12457   }
12458
12459   gtk_tree_path_free (path);
12460 }
12461
12462 /* Timeout to animate the expander during expands and collapses */
12463 static gboolean
12464 expand_collapse_timeout (gpointer data)
12465 {
12466   return do_expand_collapse (data);
12467 }
12468
12469 static void
12470 add_expand_collapse_timeout (GtkTreeView *tree_view,
12471                              GtkRBTree   *tree,
12472                              GtkRBNode   *node,
12473                              gboolean     expand)
12474 {
12475   if (tree_view->priv->expand_collapse_timeout != 0)
12476     return;
12477
12478   tree_view->priv->expand_collapse_timeout =
12479       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
12480   tree_view->priv->expanded_collapsed_tree = tree;
12481   tree_view->priv->expanded_collapsed_node = node;
12482
12483   if (expand)
12484     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12485   else
12486     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12487 }
12488
12489 static void
12490 remove_expand_collapse_timeout (GtkTreeView *tree_view)
12491 {
12492   if (tree_view->priv->expand_collapse_timeout)
12493     {
12494       g_source_remove (tree_view->priv->expand_collapse_timeout);
12495       tree_view->priv->expand_collapse_timeout = 0;
12496     }
12497
12498   if (tree_view->priv->expanded_collapsed_node != NULL)
12499     {
12500       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
12501       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12502
12503       tree_view->priv->expanded_collapsed_node = NULL;
12504     }
12505 }
12506
12507 static void
12508 cancel_arrow_animation (GtkTreeView *tree_view)
12509 {
12510   if (tree_view->priv->expand_collapse_timeout)
12511     {
12512       while (do_expand_collapse (tree_view));
12513
12514       remove_expand_collapse_timeout (tree_view);
12515     }
12516 }
12517
12518 static gboolean
12519 do_expand_collapse (GtkTreeView *tree_view)
12520 {
12521   GtkRBNode *node;
12522   GtkRBTree *tree;
12523   gboolean expanding;
12524   gboolean redraw;
12525
12526   redraw = FALSE;
12527   expanding = TRUE;
12528
12529   node = tree_view->priv->expanded_collapsed_node;
12530   tree = tree_view->priv->expanded_collapsed_tree;
12531
12532   if (node->children == NULL)
12533     expanding = FALSE;
12534
12535   if (expanding)
12536     {
12537       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12538         {
12539           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12540           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12541
12542           redraw = TRUE;
12543
12544         }
12545       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12546         {
12547           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12548
12549           redraw = TRUE;
12550         }
12551     }
12552   else
12553     {
12554       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12555         {
12556           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12557           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12558
12559           redraw = TRUE;
12560         }
12561       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12562         {
12563           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12564
12565           redraw = TRUE;
12566
12567         }
12568     }
12569
12570   if (redraw)
12571     {
12572       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
12573
12574       return TRUE;
12575     }
12576
12577   return FALSE;
12578 }
12579
12580 /**
12581  * gtk_tree_view_collapse_all:
12582  * @tree_view: A #GtkTreeView.
12583  *
12584  * Recursively collapses all visible, expanded nodes in @tree_view.
12585  **/
12586 void
12587 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12588 {
12589   GtkRBTree *tree;
12590   GtkRBNode *node;
12591   GtkTreePath *path;
12592   gint *indices;
12593
12594   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12595
12596   if (tree_view->priv->tree == NULL)
12597     return;
12598
12599   path = gtk_tree_path_new ();
12600   gtk_tree_path_down (path);
12601   indices = gtk_tree_path_get_indices (path);
12602
12603   tree = tree_view->priv->tree;
12604   node = tree->root;
12605   while (node && node->left != tree->nil)
12606     node = node->left;
12607
12608   while (node)
12609     {
12610       if (node->children)
12611         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12612       indices[0]++;
12613       node = _gtk_rbtree_next (tree, node);
12614     }
12615
12616   gtk_tree_path_free (path);
12617 }
12618
12619 /**
12620  * gtk_tree_view_expand_to_path:
12621  * @tree_view: A #GtkTreeView.
12622  * @path: path to a row.
12623  *
12624  * Expands the row at @path. This will also expand all parent rows of
12625  * @path as necessary.
12626  *
12627  * Since: 2.2
12628  **/
12629 void
12630 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12631                               GtkTreePath *path)
12632 {
12633   gint i, depth;
12634   gint *indices;
12635   GtkTreePath *tmp;
12636
12637   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12638   g_return_if_fail (path != NULL);
12639
12640   depth = gtk_tree_path_get_depth (path);
12641   indices = gtk_tree_path_get_indices (path);
12642
12643   tmp = gtk_tree_path_new ();
12644   g_return_if_fail (tmp != NULL);
12645
12646   for (i = 0; i < depth; i++)
12647     {
12648       gtk_tree_path_append_index (tmp, indices[i]);
12649       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12650     }
12651
12652   gtk_tree_path_free (tmp);
12653 }
12654
12655 /* FIXME the bool return values for expand_row and collapse_row are
12656  * not analagous; they should be TRUE if the row had children and
12657  * was not already in the requested state.
12658  */
12659
12660
12661 static gboolean
12662 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12663                                GtkTreePath *path,
12664                                GtkRBTree   *tree,
12665                                GtkRBNode   *node,
12666                                gboolean     open_all,
12667                                gboolean     animate)
12668 {
12669   GtkTreeIter iter;
12670   GtkTreeIter temp;
12671   gboolean expand;
12672
12673   if (animate)
12674     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12675                   "gtk-enable-animations", &animate,
12676                   NULL);
12677
12678   remove_auto_expand_timeout (tree_view);
12679
12680   if (node->children && !open_all)
12681     return FALSE;
12682
12683   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12684     return FALSE;
12685
12686   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12687   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12688     return FALSE;
12689
12690
12691    if (node->children && open_all)
12692     {
12693       gboolean retval = FALSE;
12694       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12695
12696       gtk_tree_path_append_index (tmp_path, 0);
12697       tree = node->children;
12698       node = tree->root;
12699       while (node->left != tree->nil)
12700         node = node->left;
12701       /* try to expand the children */
12702       do
12703         {
12704          gboolean t;
12705          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12706                                             TRUE, animate);
12707          if (t)
12708            retval = TRUE;
12709
12710          gtk_tree_path_next (tmp_path);
12711          node = _gtk_rbtree_next (tree, node);
12712        }
12713       while (node != NULL);
12714
12715       gtk_tree_path_free (tmp_path);
12716
12717       return retval;
12718     }
12719
12720   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12721
12722   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12723     return FALSE;
12724
12725   if (expand)
12726     return FALSE;
12727
12728   node->children = _gtk_rbtree_new ();
12729   node->children->parent_tree = tree;
12730   node->children->parent_node = node;
12731
12732   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12733
12734   gtk_tree_view_build_tree (tree_view,
12735                             node->children,
12736                             &temp,
12737                             gtk_tree_path_get_depth (path) + 1,
12738                             open_all);
12739
12740   remove_expand_collapse_timeout (tree_view);
12741
12742   if (animate)
12743     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12744
12745   install_presize_handler (tree_view);
12746
12747   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12748   if (open_all && node->children)
12749     {
12750       _gtk_rbtree_traverse (node->children,
12751                             node->children->root,
12752                             G_PRE_ORDER,
12753                             gtk_tree_view_expand_all_emission_helper,
12754                             tree_view);
12755     }
12756   return TRUE;
12757 }
12758
12759
12760 /**
12761  * gtk_tree_view_expand_row:
12762  * @tree_view: a #GtkTreeView
12763  * @path: path to a row
12764  * @open_all: whether to recursively expand, or just expand immediate children
12765  *
12766  * Opens the row so its children are visible.
12767  *
12768  * Return value: %TRUE if the row existed and had children
12769  **/
12770 gboolean
12771 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12772                           GtkTreePath *path,
12773                           gboolean     open_all)
12774 {
12775   GtkRBTree *tree;
12776   GtkRBNode *node;
12777
12778   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12779   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12780   g_return_val_if_fail (path != NULL, FALSE);
12781
12782   if (_gtk_tree_view_find_node (tree_view,
12783                                 path,
12784                                 &tree,
12785                                 &node))
12786     return FALSE;
12787
12788   if (tree != NULL)
12789     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12790   else
12791     return FALSE;
12792 }
12793
12794 static gboolean
12795 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12796                                  GtkTreePath *path,
12797                                  GtkRBTree   *tree,
12798                                  GtkRBNode   *node,
12799                                  gboolean     animate)
12800 {
12801   GtkTreeIter iter;
12802   GtkTreeIter children;
12803   gboolean collapse;
12804   gint x, y;
12805   GList *list;
12806   GdkWindow *child, *parent;
12807
12808   if (animate)
12809     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12810                   "gtk-enable-animations", &animate,
12811                   NULL);
12812
12813   remove_auto_expand_timeout (tree_view);
12814
12815   if (node->children == NULL)
12816     return FALSE;
12817
12818   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12819
12820   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12821
12822   if (collapse)
12823     return FALSE;
12824
12825   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12826    * a chance to prelight the correct node below */
12827
12828   if (tree_view->priv->prelight_tree)
12829     {
12830       GtkRBTree *parent_tree;
12831       GtkRBNode *parent_node;
12832
12833       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12834       parent_node = tree_view->priv->prelight_tree->parent_node;
12835       while (parent_tree)
12836         {
12837           if (parent_tree == tree && parent_node == node)
12838             {
12839               ensure_unprelighted (tree_view);
12840               break;
12841             }
12842           parent_node = parent_tree->parent_node;
12843           parent_tree = parent_tree->parent_tree;
12844         }
12845     }
12846
12847   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12848
12849   for (list = tree_view->priv->columns; list; list = list->next)
12850     {
12851       GtkTreeViewColumn *column = list->data;
12852
12853       if (gtk_tree_view_column_get_visible (column) == FALSE)
12854         continue;
12855       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12856         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12857     }
12858
12859   if (tree_view->priv->destroy_count_func)
12860     {
12861       GtkTreePath *child_path;
12862       gint child_count = 0;
12863       child_path = gtk_tree_path_copy (path);
12864       gtk_tree_path_down (child_path);
12865       if (node->children)
12866         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12867       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12868       gtk_tree_path_free (child_path);
12869     }
12870
12871   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12872     {
12873       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12874
12875       if (gtk_tree_path_is_ancestor (path, cursor_path))
12876         {
12877           gtk_tree_row_reference_free (tree_view->priv->cursor);
12878           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12879                                                                       tree_view->priv->model,
12880                                                                       path);
12881         }
12882       gtk_tree_path_free (cursor_path);
12883     }
12884
12885   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12886     {
12887       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12888       if (gtk_tree_path_is_ancestor (path, anchor_path))
12889         {
12890           gtk_tree_row_reference_free (tree_view->priv->anchor);
12891           tree_view->priv->anchor = NULL;
12892         }
12893       gtk_tree_path_free (anchor_path);
12894     }
12895
12896   /* Stop a pending double click */
12897   tree_view->priv->last_button_x = -1;
12898   tree_view->priv->last_button_y = -1;
12899
12900   remove_expand_collapse_timeout (tree_view);
12901
12902   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12903     {
12904       _gtk_rbtree_remove (node->children);
12905       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12906     }
12907   else
12908     _gtk_rbtree_remove (node->children);
12909   
12910   if (animate)
12911     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12912   
12913   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12914     {
12915       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12916     }
12917
12918   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12919   
12920   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12921     {
12922       /* now that we've collapsed all rows, we want to try to set the prelight
12923        * again. To do this, we fake a motion event and send it to ourselves. */
12924
12925       child = tree_view->priv->bin_window;
12926       parent = gdk_window_get_parent (child);
12927
12928       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12929         {
12930           GdkEventMotion event;
12931           gint child_x, child_y;
12932
12933           gdk_window_get_position (child, &child_x, &child_y);
12934
12935           event.window = tree_view->priv->bin_window;
12936           event.x = x - child_x;
12937           event.y = y - child_y;
12938
12939           /* despite the fact this isn't a real event, I'm almost positive it will
12940            * never trigger a drag event.  maybe_drag is the only function that uses
12941            * more than just event.x and event.y. */
12942           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12943         }
12944     }
12945
12946   return TRUE;
12947 }
12948
12949 /**
12950  * gtk_tree_view_collapse_row:
12951  * @tree_view: a #GtkTreeView
12952  * @path: path to a row in the @tree_view
12953  *
12954  * Collapses a row (hides its child rows, if they exist).
12955  *
12956  * Return value: %TRUE if the row was collapsed.
12957  **/
12958 gboolean
12959 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12960                             GtkTreePath *path)
12961 {
12962   GtkRBTree *tree;
12963   GtkRBNode *node;
12964
12965   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12966   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12967   g_return_val_if_fail (path != NULL, FALSE);
12968
12969   if (_gtk_tree_view_find_node (tree_view,
12970                                 path,
12971                                 &tree,
12972                                 &node))
12973     return FALSE;
12974
12975   if (tree == NULL || node->children == NULL)
12976     return FALSE;
12977
12978   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12979 }
12980
12981 static void
12982 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12983                                         GtkRBTree              *tree,
12984                                         GtkTreePath            *path,
12985                                         GtkTreeViewMappingFunc  func,
12986                                         gpointer                user_data)
12987 {
12988   GtkRBNode *node;
12989
12990   if (tree == NULL || tree->root == NULL)
12991     return;
12992
12993   node = tree->root;
12994
12995   while (node && node->left != tree->nil)
12996     node = node->left;
12997
12998   while (node)
12999     {
13000       if (node->children)
13001         {
13002           (* func) (tree_view, path, user_data);
13003           gtk_tree_path_down (path);
13004           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
13005           gtk_tree_path_up (path);
13006         }
13007       gtk_tree_path_next (path);
13008       node = _gtk_rbtree_next (tree, node);
13009     }
13010 }
13011
13012 /**
13013  * gtk_tree_view_map_expanded_rows:
13014  * @tree_view: A #GtkTreeView
13015  * @func: (scope call): A function to be called
13016  * @data: User data to be passed to the function.
13017  *
13018  * Calls @func on all expanded rows.
13019  **/
13020 void
13021 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
13022                                  GtkTreeViewMappingFunc  func,
13023                                  gpointer                user_data)
13024 {
13025   GtkTreePath *path;
13026
13027   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13028   g_return_if_fail (func != NULL);
13029
13030   path = gtk_tree_path_new_first ();
13031
13032   gtk_tree_view_map_expanded_rows_helper (tree_view,
13033                                           tree_view->priv->tree,
13034                                           path, func, user_data);
13035
13036   gtk_tree_path_free (path);
13037 }
13038
13039 /**
13040  * gtk_tree_view_row_expanded:
13041  * @tree_view: A #GtkTreeView.
13042  * @path: A #GtkTreePath to test expansion state.
13043  *
13044  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13045  *
13046  * Return value: %TRUE if #path is expanded.
13047  **/
13048 gboolean
13049 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13050                             GtkTreePath *path)
13051 {
13052   GtkRBTree *tree;
13053   GtkRBNode *node;
13054
13055   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13056   g_return_val_if_fail (path != NULL, FALSE);
13057
13058   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13059
13060   if (node == NULL)
13061     return FALSE;
13062
13063   return (node->children != NULL);
13064 }
13065
13066 /**
13067  * gtk_tree_view_get_reorderable:
13068  * @tree_view: a #GtkTreeView
13069  *
13070  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13071  * gtk_tree_view_set_reorderable().
13072  *
13073  * Return value: %TRUE if the tree can be reordered.
13074  **/
13075 gboolean
13076 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13077 {
13078   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13079
13080   return tree_view->priv->reorderable;
13081 }
13082
13083 /**
13084  * gtk_tree_view_set_reorderable:
13085  * @tree_view: A #GtkTreeView.
13086  * @reorderable: %TRUE, if the tree can be reordered.
13087  *
13088  * This function is a convenience function to allow you to reorder
13089  * models that support the #GtkDragSourceIface and the
13090  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13091  * these.  If @reorderable is %TRUE, then the user can reorder the
13092  * model by dragging and dropping rows. The developer can listen to
13093  * these changes by connecting to the model's row_inserted and
13094  * row_deleted signals. The reordering is implemented by setting up
13095  * the tree view as a drag source and destination. Therefore, drag and
13096  * drop can not be used in a reorderable view for any other purpose.
13097  *
13098  * This function does not give you any degree of control over the order -- any
13099  * reordering is allowed.  If more control is needed, you should probably
13100  * handle drag and drop manually.
13101  **/
13102 void
13103 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13104                                gboolean     reorderable)
13105 {
13106   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13107
13108   reorderable = reorderable != FALSE;
13109
13110   if (tree_view->priv->reorderable == reorderable)
13111     return;
13112
13113   if (reorderable)
13114     {
13115       const GtkTargetEntry row_targets[] = {
13116         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13117       };
13118
13119       gtk_tree_view_enable_model_drag_source (tree_view,
13120                                               GDK_BUTTON1_MASK,
13121                                               row_targets,
13122                                               G_N_ELEMENTS (row_targets),
13123                                               GDK_ACTION_MOVE);
13124       gtk_tree_view_enable_model_drag_dest (tree_view,
13125                                             row_targets,
13126                                             G_N_ELEMENTS (row_targets),
13127                                             GDK_ACTION_MOVE);
13128     }
13129   else
13130     {
13131       gtk_tree_view_unset_rows_drag_source (tree_view);
13132       gtk_tree_view_unset_rows_drag_dest (tree_view);
13133     }
13134
13135   tree_view->priv->reorderable = reorderable;
13136
13137   g_object_notify (G_OBJECT (tree_view), "reorderable");
13138 }
13139
13140 static void
13141 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13142                                GtkTreePath     *path,
13143                                gboolean         clear_and_select,
13144                                gboolean         clamp_node)
13145 {
13146   GtkRBTree *tree = NULL;
13147   GtkRBNode *node = NULL;
13148
13149   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13150     {
13151       GtkTreePath *cursor_path;
13152       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13153       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
13154       gtk_tree_path_free (cursor_path);
13155     }
13156
13157   gtk_tree_row_reference_free (tree_view->priv->cursor);
13158   tree_view->priv->cursor = NULL;
13159
13160   /* One cannot set the cursor on a separator.   Also, if
13161    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13162    * before finding the tree and node belonging to path.  The
13163    * path maps to a non-existing path and we will silently bail out.
13164    * We unset tree and node to avoid further processing.
13165    */
13166   if (!row_is_separator (tree_view, NULL, path)
13167       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
13168     {
13169       tree_view->priv->cursor =
13170           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
13171                                             tree_view->priv->model,
13172                                             path);
13173     }
13174   else
13175     {
13176       tree = NULL;
13177       node = NULL;
13178     }
13179
13180   if (tree != NULL)
13181     {
13182       GtkRBTree *new_tree = NULL;
13183       GtkRBNode *new_node = NULL;
13184
13185       if (clear_and_select && !tree_view->priv->ctrl_pressed)
13186         {
13187           GtkTreeSelectMode mode = 0;
13188
13189           if (tree_view->priv->ctrl_pressed)
13190             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
13191           if (tree_view->priv->shift_pressed)
13192             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13193
13194           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13195                                                     node, tree, path, mode,
13196                                                     FALSE);
13197         }
13198
13199       /* We have to re-find tree and node here again, somebody might have
13200        * cleared the node or the whole tree in the GtkTreeSelection::changed
13201        * callback. If the nodes differ we bail out here.
13202        */
13203       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13204
13205       if (tree != new_tree || node != new_node)
13206         return;
13207
13208       if (clamp_node)
13209         {
13210           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
13211           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13212         }
13213     }
13214
13215   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13216 }
13217
13218 /**
13219  * gtk_tree_view_get_cursor:
13220  * @tree_view: A #GtkTreeView
13221  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13222  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
13223  *
13224  * Fills in @path and @focus_column with the current path and focus column.  If
13225  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13226  * currently has focus, then *@focus_column will be %NULL.
13227  *
13228  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13229  * you are done with it.
13230  **/
13231 void
13232 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13233                           GtkTreePath       **path,
13234                           GtkTreeViewColumn **focus_column)
13235 {
13236   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13237
13238   if (path)
13239     {
13240       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13241         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13242       else
13243         *path = NULL;
13244     }
13245
13246   if (focus_column)
13247     {
13248       *focus_column = tree_view->priv->focus_column;
13249     }
13250 }
13251
13252 /**
13253  * gtk_tree_view_set_cursor:
13254  * @tree_view: A #GtkTreeView
13255  * @path: A #GtkTreePath
13256  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13257  * @start_editing: %TRUE if the specified cell should start being edited.
13258  *
13259  * Sets the current keyboard focus to be at @path, and selects it.  This is
13260  * useful when you want to focus the user's attention on a particular row.  If
13261  * @focus_column is not %NULL, then focus is given to the column specified by 
13262  * it. Additionally, if @focus_column is specified, and @start_editing is 
13263  * %TRUE, then editing should be started in the specified cell.  
13264  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13265  * in order to give keyboard focus to the widget.  Please note that editing 
13266  * can only happen when the widget is realized.
13267  *
13268  * If @path is invalid for @model, the current cursor (if any) will be unset
13269  * and the function will return without failing.
13270  **/
13271 void
13272 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13273                           GtkTreePath       *path,
13274                           GtkTreeViewColumn *focus_column,
13275                           gboolean           start_editing)
13276 {
13277   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13278                                     NULL, start_editing);
13279 }
13280
13281 /**
13282  * gtk_tree_view_set_cursor_on_cell:
13283  * @tree_view: A #GtkTreeView
13284  * @path: A #GtkTreePath
13285  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13286  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13287  * @start_editing: %TRUE if the specified cell should start being edited.
13288  *
13289  * Sets the current keyboard focus to be at @path, and selects it.  This is
13290  * useful when you want to focus the user's attention on a particular row.  If
13291  * @focus_column is not %NULL, then focus is given to the column specified by
13292  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13293  * contains 2 or more editable or activatable cells, then focus is given to
13294  * the cell specified by @focus_cell. Additionally, if @focus_column is
13295  * specified, and @start_editing is %TRUE, then editing should be started in
13296  * the specified cell.  This function is often followed by
13297  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13298  * widget.  Please note that editing can only happen when the widget is
13299  * realized.
13300  *
13301  * If @path is invalid for @model, the current cursor (if any) will be unset
13302  * and the function will return without failing.
13303  *
13304  * Since: 2.2
13305  **/
13306 void
13307 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13308                                   GtkTreePath       *path,
13309                                   GtkTreeViewColumn *focus_column,
13310                                   GtkCellRenderer   *focus_cell,
13311                                   gboolean           start_editing)
13312 {
13313   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13314   g_return_if_fail (path != NULL);
13315   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13316
13317   if (!tree_view->priv->model)
13318     return;
13319
13320   if (focus_cell)
13321     {
13322       g_return_if_fail (focus_column);
13323       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13324     }
13325
13326   /* cancel the current editing, if it exists */
13327   if (tree_view->priv->edited_column &&
13328       gtk_cell_area_get_edit_widget
13329       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13330     gtk_tree_view_stop_editing (tree_view, TRUE);
13331
13332   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
13333
13334   if (focus_column &&
13335       gtk_tree_view_column_get_visible (focus_column))
13336     {
13337       GList *list;
13338       gboolean column_in_tree = FALSE;
13339
13340       for (list = tree_view->priv->columns; list; list = list->next)
13341         if (list->data == focus_column)
13342           {
13343             column_in_tree = TRUE;
13344             break;
13345           }
13346       g_return_if_fail (column_in_tree);
13347       tree_view->priv->focus_column = focus_column;
13348       if (focus_cell)
13349         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13350       if (start_editing)
13351         gtk_tree_view_start_editing (tree_view, path);
13352     }
13353 }
13354
13355 /**
13356  * gtk_tree_view_get_bin_window:
13357  * @tree_view: A #GtkTreeView
13358  *
13359  * Returns the window that @tree_view renders to.
13360  * This is used primarily to compare to <literal>event->window</literal>
13361  * to confirm that the event on @tree_view is on the right window.
13362  *
13363  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13364  *     hasn't been realized yet
13365  **/
13366 GdkWindow *
13367 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13368 {
13369   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13370
13371   return tree_view->priv->bin_window;
13372 }
13373
13374 /**
13375  * gtk_tree_view_get_path_at_pos:
13376  * @tree_view: A #GtkTreeView.
13377  * @x: The x position to be identified (relative to bin_window).
13378  * @y: The y position to be identified (relative to bin_window).
13379  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13380  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13381  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13382  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13383  *
13384  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13385  * (please see gtk_tree_view_get_bin_window()).
13386  * That is, @x and @y are relative to an events coordinates. @x and @y must
13387  * come from an event on the @tree_view only where <literal>event->window ==
13388  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13389  * things like popup menus. If @path is non-%NULL, then it will be filled
13390  * with the #GtkTreePath at that point.  This path should be freed with
13391  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13392  * with the column at that point.  @cell_x and @cell_y return the coordinates
13393  * relative to the cell background (i.e. the @background_area passed to
13394  * gtk_cell_renderer_render()).  This function is only meaningful if
13395  * @tree_view is realized.  Therefore this function will always return %FALSE
13396  * if @tree_view is not realized or does not have a model.
13397  *
13398  * For converting widget coordinates (eg. the ones you get from
13399  * GtkWidget::query-tooltip), please see
13400  * gtk_tree_view_convert_widget_to_bin_window_coords().
13401  *
13402  * Return value: %TRUE if a row exists at that coordinate.
13403  **/
13404 gboolean
13405 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13406                                gint                x,
13407                                gint                y,
13408                                GtkTreePath       **path,
13409                                GtkTreeViewColumn **column,
13410                                gint               *cell_x,
13411                                gint               *cell_y)
13412 {
13413   GtkRBTree *tree;
13414   GtkRBNode *node;
13415   gint y_offset;
13416
13417   g_return_val_if_fail (tree_view != NULL, FALSE);
13418
13419   if (path)
13420     *path = NULL;
13421   if (column)
13422     *column = NULL;
13423
13424   if (tree_view->priv->bin_window == NULL)
13425     return FALSE;
13426
13427   if (tree_view->priv->tree == NULL)
13428     return FALSE;
13429
13430   if (x > tree_view->priv->hadjustment->upper)
13431     return FALSE;
13432
13433   if (x < 0 || y < 0)
13434     return FALSE;
13435
13436   if (column || cell_x)
13437     {
13438       GtkTreeViewColumn *tmp_column;
13439       GtkTreeViewColumn *last_column = NULL;
13440       GList *list;
13441       gint remaining_x = x;
13442       gboolean found = FALSE;
13443       gboolean rtl;
13444       gint width;
13445
13446       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13447       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13448            list;
13449            list = (rtl ? list->prev : list->next))
13450         {
13451           tmp_column = list->data;
13452
13453           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13454             continue;
13455
13456           last_column = tmp_column;
13457           width = gtk_tree_view_column_get_width (tmp_column);
13458           if (remaining_x <= width)
13459             {
13460               found = TRUE;
13461
13462               if (column)
13463                 *column = tmp_column;
13464
13465               if (cell_x)
13466                 *cell_x = remaining_x;
13467
13468               break;
13469             }
13470           remaining_x -= width;
13471         }
13472
13473       /* If found is FALSE and there is a last_column, then it the remainder
13474        * space is in that area
13475        */
13476       if (!found)
13477         {
13478           if (last_column)
13479             {
13480               if (column)
13481                 *column = last_column;
13482               
13483               if (cell_x)
13484                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13485             }
13486           else
13487             {
13488               return FALSE;
13489             }
13490         }
13491     }
13492
13493   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13494                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13495                                       &tree, &node);
13496
13497   if (tree == NULL)
13498     return FALSE;
13499
13500   if (cell_y)
13501     *cell_y = y_offset;
13502
13503   if (path)
13504     *path = _gtk_tree_view_find_path (tree_view, tree, node);
13505
13506   return TRUE;
13507 }
13508
13509
13510 static inline gint
13511 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13512                                     GtkRBNode   *node,
13513                                     gint         vertical_separator)
13514 {
13515   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13516    * i.e. just the cells, no spacing.
13517    *
13518    * The cell area height is at least expander_size - vertical_separator;
13519    */
13520
13521   return gtk_tree_view_get_row_height (tree_view, node) - vertical_separator;
13522 }
13523
13524 static inline gint
13525 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13526                                       GtkRBTree   *tree,
13527                                       GtkRBNode   *node,
13528                                       gint         vertical_separator)
13529 {
13530   int offset;
13531
13532   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13533   offset += vertical_separator / 2;
13534
13535   return offset;
13536 }
13537
13538 /**
13539  * gtk_tree_view_get_cell_area:
13540  * @tree_view: a #GtkTreeView
13541  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13542  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13543  * @rect: rectangle to fill with cell rect
13544  *
13545  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13546  * row specified by @path and the column specified by @column.  If @path is
13547  * %NULL, or points to a path not currently displayed, the @y and @height fields
13548  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13549  * fields will be filled with 0.  The sum of all cell rects does not cover the
13550  * entire tree; there are extra pixels in between rows, for example. The
13551  * returned rectangle is equivalent to the @cell_area passed to
13552  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13553  * realized.
13554  **/
13555 void
13556 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13557                              GtkTreePath        *path,
13558                              GtkTreeViewColumn  *column,
13559                              GdkRectangle       *rect)
13560 {
13561   GtkAllocation allocation;
13562   GtkRBTree *tree = NULL;
13563   GtkRBNode *node = NULL;
13564   gint vertical_separator;
13565   gint horizontal_separator;
13566
13567   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13568   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13569   g_return_if_fail (rect != NULL);
13570   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13571   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13572
13573   gtk_widget_style_get (GTK_WIDGET (tree_view),
13574                         "vertical-separator", &vertical_separator,
13575                         "horizontal-separator", &horizontal_separator,
13576                         NULL);
13577
13578   rect->x = 0;
13579   rect->y = 0;
13580   rect->width = 0;
13581   rect->height = 0;
13582
13583   if (column)
13584     {
13585       gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
13586       rect->x = allocation.x + horizontal_separator/2;
13587       rect->width = allocation.width - horizontal_separator;
13588     }
13589
13590   if (path)
13591     {
13592       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13593
13594       /* Get vertical coords */
13595       if ((!ret && tree == NULL) || ret)
13596         return;
13597
13598       rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13599                                                       vertical_separator);
13600       rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13601                                                          vertical_separator);
13602
13603       if (column &&
13604           gtk_tree_view_is_expander_column (tree_view, column))
13605         {
13606           gint depth = gtk_tree_path_get_depth (path);
13607           gboolean rtl;
13608
13609           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13610
13611           if (!rtl)
13612             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13613           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13614
13615           if (gtk_tree_view_draw_expanders (tree_view))
13616             {
13617               if (!rtl)
13618                 rect->x += depth * tree_view->priv->expander_size;
13619               rect->width -= depth * tree_view->priv->expander_size;
13620             }
13621
13622           rect->width = MAX (rect->width, 0);
13623         }
13624     }
13625 }
13626
13627 static inline gint
13628 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13629                               GtkRBNode   *node)
13630 {
13631   int height;
13632
13633   /* The "background" areas of all rows/cells add up to cover the entire tree.
13634    * The background includes all inter-row and inter-cell spacing.
13635    *
13636    * The height of a row is at least "expander_size".
13637    */
13638   height = GTK_RBNODE_GET_HEIGHT (node);
13639   if (height < tree_view->priv->expander_size)
13640     height = tree_view->priv->expander_size;
13641
13642   return height;
13643 }
13644
13645 static inline gint
13646 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13647                                 GtkRBTree   *tree,
13648                                 GtkRBNode   *node)
13649 {
13650   int offset;
13651
13652   offset = _gtk_rbtree_node_find_offset (tree, node);
13653
13654   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13655 }
13656
13657 /**
13658  * gtk_tree_view_get_background_area:
13659  * @tree_view: a #GtkTreeView
13660  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13661  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13662  * @rect: rectangle to fill with cell background rect
13663  *
13664  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13665  * row specified by @path and the column specified by @column.  If @path is
13666  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13667  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13668  * fields will be filled with 0.  The returned rectangle is equivalent to the
13669  * @background_area passed to gtk_cell_renderer_render().  These background
13670  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13671  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13672  * itself, excluding surrounding borders and the tree expander area.
13673  *
13674  **/
13675 void
13676 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13677                                    GtkTreePath        *path,
13678                                    GtkTreeViewColumn  *column,
13679                                    GdkRectangle       *rect)
13680 {
13681   GtkRBTree *tree = NULL;
13682   GtkRBNode *node = NULL;
13683
13684   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13685   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13686   g_return_if_fail (rect != NULL);
13687
13688   rect->x = 0;
13689   rect->y = 0;
13690   rect->width = 0;
13691   rect->height = 0;
13692
13693   if (path)
13694     {
13695       /* Get vertical coords */
13696
13697       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13698           tree == NULL)
13699         return;
13700
13701       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13702       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13703     }
13704
13705   if (column)
13706     {
13707       gint x2 = 0;
13708
13709       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13710       rect->width = x2 - rect->x;
13711     }
13712 }
13713
13714 /**
13715  * gtk_tree_view_get_visible_rect:
13716  * @tree_view: a #GtkTreeView
13717  * @visible_rect: rectangle to fill
13718  *
13719  * Fills @visible_rect with the currently-visible region of the
13720  * buffer, in tree coordinates. Convert to bin_window coordinates with
13721  * gtk_tree_view_convert_tree_to_bin_window_coords().
13722  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13723  * scrollable area of the tree.
13724  **/
13725 void
13726 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13727                                 GdkRectangle *visible_rect)
13728 {
13729   GtkAllocation allocation;
13730   GtkWidget *widget;
13731
13732   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13733
13734   widget = GTK_WIDGET (tree_view);
13735
13736   if (visible_rect)
13737     {
13738       gtk_widget_get_allocation (widget, &allocation);
13739       visible_rect->x = tree_view->priv->hadjustment->value;
13740       visible_rect->y = tree_view->priv->vadjustment->value;
13741       visible_rect->width = allocation.width;
13742       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13743     }
13744 }
13745
13746 /**
13747  * gtk_tree_view_convert_widget_to_tree_coords:
13748  * @tree_view: a #GtkTreeView
13749  * @wx: X coordinate relative to the widget
13750  * @wy: Y coordinate relative to the widget
13751  * @tx: return location for tree X coordinate
13752  * @ty: return location for tree Y coordinate
13753  *
13754  * Converts widget coordinates to coordinates for the
13755  * tree (the full scrollable area of the tree).
13756  *
13757  * Since: 2.12
13758  **/
13759 void
13760 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13761                                              gint         wx,
13762                                              gint         wy,
13763                                              gint        *tx,
13764                                              gint        *ty)
13765 {
13766   gint x, y;
13767
13768   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13769
13770   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13771                                                      wx, wy,
13772                                                      &x, &y);
13773   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13774                                                    x, y,
13775                                                    tx, ty);
13776 }
13777
13778 /**
13779  * gtk_tree_view_convert_tree_to_widget_coords:
13780  * @tree_view: a #GtkTreeView
13781  * @tx: X coordinate relative to the tree
13782  * @ty: Y coordinate relative to the tree
13783  * @wx: return location for widget X coordinate
13784  * @wy: return location for widget Y coordinate
13785  *
13786  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13787  * to widget coordinates.
13788  *
13789  * Since: 2.12
13790  **/
13791 void
13792 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13793                                              gint         tx,
13794                                              gint         ty,
13795                                              gint        *wx,
13796                                              gint        *wy)
13797 {
13798   gint x, y;
13799
13800   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13801
13802   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13803                                                    tx, ty,
13804                                                    &x, &y);
13805   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13806                                                      x, y,
13807                                                      wx, wy);
13808 }
13809
13810 /**
13811  * gtk_tree_view_convert_widget_to_bin_window_coords:
13812  * @tree_view: a #GtkTreeView
13813  * @wx: X coordinate relative to the widget
13814  * @wy: Y coordinate relative to the widget
13815  * @bx: return location for bin_window X coordinate
13816  * @by: return location for bin_window Y coordinate
13817  *
13818  * Converts widget coordinates to coordinates for the bin_window
13819  * (see gtk_tree_view_get_bin_window()).
13820  *
13821  * Since: 2.12
13822  **/
13823 void
13824 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13825                                                    gint         wx,
13826                                                    gint         wy,
13827                                                    gint        *bx,
13828                                                    gint        *by)
13829 {
13830   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13831
13832   if (bx)
13833     *bx = wx + tree_view->priv->hadjustment->value;
13834   if (by)
13835     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13836 }
13837
13838 /**
13839  * gtk_tree_view_convert_bin_window_to_widget_coords:
13840  * @tree_view: a #GtkTreeView
13841  * @bx: bin_window X coordinate
13842  * @by: bin_window Y coordinate
13843  * @wx: return location for widget X coordinate
13844  * @wy: return location for widget Y coordinate
13845  *
13846  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13847  * to widget relative coordinates.
13848  *
13849  * Since: 2.12
13850  **/
13851 void
13852 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13853                                                    gint         bx,
13854                                                    gint         by,
13855                                                    gint        *wx,
13856                                                    gint        *wy)
13857 {
13858   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13859
13860   if (wx)
13861     *wx = bx - tree_view->priv->hadjustment->value;
13862   if (wy)
13863     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13864 }
13865
13866 /**
13867  * gtk_tree_view_convert_tree_to_bin_window_coords:
13868  * @tree_view: a #GtkTreeView
13869  * @tx: tree X coordinate
13870  * @ty: tree Y coordinate
13871  * @bx: return location for X coordinate relative to bin_window
13872  * @by: return location for Y coordinate relative to bin_window
13873  *
13874  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13875  * to bin_window coordinates.
13876  *
13877  * Since: 2.12
13878  **/
13879 void
13880 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13881                                                  gint         tx,
13882                                                  gint         ty,
13883                                                  gint        *bx,
13884                                                  gint        *by)
13885 {
13886   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13887
13888   if (bx)
13889     *bx = tx;
13890   if (by)
13891     *by = ty - tree_view->priv->dy;
13892 }
13893
13894 /**
13895  * gtk_tree_view_convert_bin_window_to_tree_coords:
13896  * @tree_view: a #GtkTreeView
13897  * @bx: X coordinate relative to bin_window
13898  * @by: Y coordinate relative to bin_window
13899  * @tx: return location for tree X coordinate
13900  * @ty: return location for tree Y coordinate
13901  *
13902  * Converts bin_window coordinates to coordinates for the
13903  * tree (the full scrollable area of the tree).
13904  *
13905  * Since: 2.12
13906  **/
13907 void
13908 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13909                                                  gint         bx,
13910                                                  gint         by,
13911                                                  gint        *tx,
13912                                                  gint        *ty)
13913 {
13914   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13915
13916   if (tx)
13917     *tx = bx;
13918   if (ty)
13919     *ty = by + tree_view->priv->dy;
13920 }
13921
13922
13923
13924 /**
13925  * gtk_tree_view_get_visible_range:
13926  * @tree_view: A #GtkTreeView
13927  * @start_path: (allow-none): Return location for start of region, or %NULL.
13928  * @end_path: (allow-none): Return location for end of region, or %NULL.
13929  *
13930  * Sets @start_path and @end_path to be the first and last visible path.
13931  * Note that there may be invisible paths in between.
13932  *
13933  * The paths should be freed with gtk_tree_path_free() after use.
13934  *
13935  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13936  *
13937  * Since: 2.8
13938  **/
13939 gboolean
13940 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13941                                  GtkTreePath **start_path,
13942                                  GtkTreePath **end_path)
13943 {
13944   GtkRBTree *tree;
13945   GtkRBNode *node;
13946   gboolean retval;
13947   
13948   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13949
13950   if (!tree_view->priv->tree)
13951     return FALSE;
13952
13953   retval = TRUE;
13954
13955   if (start_path)
13956     {
13957       _gtk_rbtree_find_offset (tree_view->priv->tree,
13958                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13959                                &tree, &node);
13960       if (node)
13961         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13962       else
13963         retval = FALSE;
13964     }
13965
13966   if (end_path)
13967     {
13968       gint y;
13969
13970       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13971         y = tree_view->priv->height - 1;
13972       else
13973         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13974
13975       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13976       if (node)
13977         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13978       else
13979         retval = FALSE;
13980     }
13981
13982   return retval;
13983 }
13984
13985 static void
13986 unset_reorderable (GtkTreeView *tree_view)
13987 {
13988   if (tree_view->priv->reorderable)
13989     {
13990       tree_view->priv->reorderable = FALSE;
13991       g_object_notify (G_OBJECT (tree_view), "reorderable");
13992     }
13993 }
13994
13995 /**
13996  * gtk_tree_view_enable_model_drag_source:
13997  * @tree_view: a #GtkTreeView
13998  * @start_button_mask: Mask of allowed buttons to start drag
13999  * @targets: (array): the table of targets that the drag will support
14000  * @n_targets: the number of items in @targets
14001  * @actions: the bitmask of possible actions for a drag from this
14002  *    widget
14003  *
14004  * Turns @tree_view into a drag source for automatic DND. Calling this
14005  * method sets #GtkTreeView:reorderable to %FALSE.
14006  **/
14007 void
14008 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14009                                         GdkModifierType           start_button_mask,
14010                                         const GtkTargetEntry     *targets,
14011                                         gint                      n_targets,
14012                                         GdkDragAction             actions)
14013 {
14014   TreeViewDragInfo *di;
14015
14016   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14017
14018   gtk_drag_source_set (GTK_WIDGET (tree_view),
14019                        0,
14020                        targets,
14021                        n_targets,
14022                        actions);
14023
14024   di = ensure_info (tree_view);
14025
14026   di->start_button_mask = start_button_mask;
14027   di->source_actions = actions;
14028   di->source_set = TRUE;
14029
14030   unset_reorderable (tree_view);
14031 }
14032
14033 /**
14034  * gtk_tree_view_enable_model_drag_dest:
14035  * @tree_view: a #GtkTreeView
14036  * @targets: (array): the table of targets that the drag will support
14037  * @n_targets: the number of items in @targets
14038  * @actions: the bitmask of possible actions for a drag from this
14039  *    widget
14040  * 
14041  * Turns @tree_view into a drop destination for automatic DND. Calling
14042  * this method sets #GtkTreeView:reorderable to %FALSE.
14043  **/
14044 void
14045 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14046                                       const GtkTargetEntry     *targets,
14047                                       gint                      n_targets,
14048                                       GdkDragAction             actions)
14049 {
14050   TreeViewDragInfo *di;
14051
14052   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14053
14054   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14055                      0,
14056                      targets,
14057                      n_targets,
14058                      actions);
14059
14060   di = ensure_info (tree_view);
14061   di->dest_set = TRUE;
14062
14063   unset_reorderable (tree_view);
14064 }
14065
14066 /**
14067  * gtk_tree_view_unset_rows_drag_source:
14068  * @tree_view: a #GtkTreeView
14069  *
14070  * Undoes the effect of
14071  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14072  * #GtkTreeView:reorderable to %FALSE.
14073  **/
14074 void
14075 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14076 {
14077   TreeViewDragInfo *di;
14078
14079   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14080
14081   di = get_info (tree_view);
14082
14083   if (di)
14084     {
14085       if (di->source_set)
14086         {
14087           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14088           di->source_set = FALSE;
14089         }
14090
14091       if (!di->dest_set && !di->source_set)
14092         remove_info (tree_view);
14093     }
14094   
14095   unset_reorderable (tree_view);
14096 }
14097
14098 /**
14099  * gtk_tree_view_unset_rows_drag_dest:
14100  * @tree_view: a #GtkTreeView
14101  *
14102  * Undoes the effect of
14103  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14104  * #GtkTreeView:reorderable to %FALSE.
14105  **/
14106 void
14107 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14108 {
14109   TreeViewDragInfo *di;
14110
14111   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14112
14113   di = get_info (tree_view);
14114
14115   if (di)
14116     {
14117       if (di->dest_set)
14118         {
14119           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14120           di->dest_set = FALSE;
14121         }
14122
14123       if (!di->dest_set && !di->source_set)
14124         remove_info (tree_view);
14125     }
14126
14127   unset_reorderable (tree_view);
14128 }
14129
14130 /**
14131  * gtk_tree_view_set_drag_dest_row:
14132  * @tree_view: a #GtkTreeView
14133  * @path: (allow-none): The path of the row to highlight, or %NULL.
14134  * @pos: Specifies whether to drop before, after or into the row
14135  * 
14136  * Sets the row that is highlighted for feedback.
14137  **/
14138 void
14139 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14140                                  GtkTreePath            *path,
14141                                  GtkTreeViewDropPosition pos)
14142 {
14143   GtkTreePath *current_dest;
14144
14145   /* Note; this function is exported to allow a custom DND
14146    * implementation, so it can't touch TreeViewDragInfo
14147    */
14148
14149   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14150
14151   current_dest = NULL;
14152
14153   if (tree_view->priv->drag_dest_row)
14154     {
14155       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14156       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14157     }
14158
14159   /* special case a drop on an empty model */
14160   tree_view->priv->empty_view_drop = 0;
14161
14162   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14163       && gtk_tree_path_get_depth (path) == 1
14164       && gtk_tree_path_get_indices (path)[0] == 0)
14165     {
14166       gint n_children;
14167
14168       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14169                                                    NULL);
14170
14171       if (!n_children)
14172         tree_view->priv->empty_view_drop = 1;
14173     }
14174
14175   tree_view->priv->drag_dest_pos = pos;
14176
14177   if (path)
14178     {
14179       tree_view->priv->drag_dest_row =
14180         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14181       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14182     }
14183   else
14184     tree_view->priv->drag_dest_row = NULL;
14185
14186   if (current_dest)
14187     {
14188       GtkRBTree *tree, *new_tree;
14189       GtkRBNode *node, *new_node;
14190
14191       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14192       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14193
14194       if (tree && node)
14195         {
14196           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14197           if (new_tree && new_node)
14198             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14199
14200           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14201           if (new_tree && new_node)
14202             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14203         }
14204       gtk_tree_path_free (current_dest);
14205     }
14206 }
14207
14208 /**
14209  * gtk_tree_view_get_drag_dest_row:
14210  * @tree_view: a #GtkTreeView
14211  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14212  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14213  * 
14214  * Gets information about the row that is highlighted for feedback.
14215  **/
14216 void
14217 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14218                                  GtkTreePath             **path,
14219                                  GtkTreeViewDropPosition  *pos)
14220 {
14221   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14222
14223   if (path)
14224     {
14225       if (tree_view->priv->drag_dest_row)
14226         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14227       else
14228         {
14229           if (tree_view->priv->empty_view_drop)
14230             *path = gtk_tree_path_new_from_indices (0, -1);
14231           else
14232             *path = NULL;
14233         }
14234     }
14235
14236   if (pos)
14237     *pos = tree_view->priv->drag_dest_pos;
14238 }
14239
14240 /**
14241  * gtk_tree_view_get_dest_row_at_pos:
14242  * @tree_view: a #GtkTreeView
14243  * @drag_x: the position to determine the destination row for
14244  * @drag_y: the position to determine the destination row for
14245  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14246  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14247  * 
14248  * Determines the destination row for a given position.  @drag_x and
14249  * @drag_y are expected to be in widget coordinates.  This function is only
14250  * meaningful if @tree_view is realized.  Therefore this function will always
14251  * return %FALSE if @tree_view is not realized or does not have a model.
14252  * 
14253  * Return value: whether there is a row at the given position, %TRUE if this
14254  * is indeed the case.
14255  **/
14256 gboolean
14257 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14258                                    gint                     drag_x,
14259                                    gint                     drag_y,
14260                                    GtkTreePath            **path,
14261                                    GtkTreeViewDropPosition *pos)
14262 {
14263   gint cell_y;
14264   gint bin_x, bin_y;
14265   gdouble offset_into_row;
14266   gdouble third;
14267   GdkRectangle cell;
14268   GtkTreeViewColumn *column = NULL;
14269   GtkTreePath *tmp_path = NULL;
14270
14271   /* Note; this function is exported to allow a custom DND
14272    * implementation, so it can't touch TreeViewDragInfo
14273    */
14274
14275   g_return_val_if_fail (tree_view != NULL, FALSE);
14276   g_return_val_if_fail (drag_x >= 0, FALSE);
14277   g_return_val_if_fail (drag_y >= 0, FALSE);
14278
14279   if (path)
14280     *path = NULL;
14281
14282   if (tree_view->priv->bin_window == NULL)
14283     return FALSE;
14284
14285   if (tree_view->priv->tree == NULL)
14286     return FALSE;
14287
14288   /* If in the top third of a row, we drop before that row; if
14289    * in the bottom third, drop after that row; if in the middle,
14290    * and the row has children, drop into the row.
14291    */
14292   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14293                                                      &bin_x, &bin_y);
14294
14295   if (!gtk_tree_view_get_path_at_pos (tree_view,
14296                                       bin_x,
14297                                       bin_y,
14298                                       &tmp_path,
14299                                       &column,
14300                                       NULL,
14301                                       &cell_y))
14302     return FALSE;
14303
14304   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14305                                      &cell);
14306
14307   offset_into_row = cell_y;
14308
14309   if (path)
14310     *path = tmp_path;
14311   else
14312     gtk_tree_path_free (tmp_path);
14313
14314   tmp_path = NULL;
14315
14316   third = cell.height / 3.0;
14317
14318   if (pos)
14319     {
14320       if (offset_into_row < third)
14321         {
14322           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14323         }
14324       else if (offset_into_row < (cell.height / 2.0))
14325         {
14326           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14327         }
14328       else if (offset_into_row < third * 2.0)
14329         {
14330           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14331         }
14332       else
14333         {
14334           *pos = GTK_TREE_VIEW_DROP_AFTER;
14335         }
14336     }
14337
14338   return TRUE;
14339 }
14340
14341
14342
14343 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14344 /**
14345  * gtk_tree_view_create_row_drag_icon:
14346  * @tree_view: a #GtkTreeView
14347  * @path: a #GtkTreePath in @tree_view
14348  *
14349  * Creates a #cairo_surface_t representation of the row at @path.  
14350  * This image is used for a drag icon.
14351  *
14352  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14353  **/
14354 cairo_surface_t *
14355 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14356                                     GtkTreePath  *path)
14357 {
14358   GtkTreeIter   iter;
14359   GtkRBTree    *tree;
14360   GtkRBNode    *node;
14361   GtkStyle *style;
14362   gint cell_offset;
14363   GList *list;
14364   GdkRectangle background_area;
14365   GtkWidget *widget;
14366   gint depth;
14367   /* start drawing inside the black outline */
14368   gint x = 1, y = 1;
14369   cairo_surface_t *surface;
14370   gint bin_window_width;
14371   gboolean is_separator = FALSE;
14372   gboolean rtl;
14373   cairo_t *cr;
14374
14375   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14376   g_return_val_if_fail (path != NULL, NULL);
14377
14378   widget = GTK_WIDGET (tree_view);
14379
14380   if (!gtk_widget_get_realized (widget))
14381     return NULL;
14382
14383   depth = gtk_tree_path_get_depth (path);
14384
14385   _gtk_tree_view_find_node (tree_view,
14386                             path,
14387                             &tree,
14388                             &node);
14389
14390   if (tree == NULL)
14391     return NULL;
14392
14393   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14394                                 &iter,
14395                                 path))
14396     return NULL;
14397
14398   style = gtk_widget_get_style (widget);
14399
14400   is_separator = row_is_separator (tree_view, &iter, NULL);
14401
14402   cell_offset = x;
14403
14404   background_area.y = y;
14405   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14406
14407   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14408
14409   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14410                                                CAIRO_CONTENT_COLOR,
14411                                                bin_window_width + 2,
14412                                                background_area.height + 2);
14413
14414   cr = cairo_create (surface);
14415   gdk_cairo_set_source_color (cr, &style->base [gtk_widget_get_state (widget)]);
14416   cairo_paint (cr);
14417
14418   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14419
14420   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14421       list;
14422       list = (rtl ? list->prev : list->next))
14423     {
14424       GtkTreeViewColumn *column = list->data;
14425       GdkRectangle cell_area;
14426       gint vertical_separator;
14427
14428       if (!gtk_tree_view_column_get_visible (column))
14429         continue;
14430
14431       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14432                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14433                                                node->children?TRUE:FALSE);
14434
14435       background_area.x = cell_offset;
14436       background_area.width = gtk_tree_view_column_get_width (column);
14437
14438       gtk_widget_style_get (widget,
14439                             "vertical-separator", &vertical_separator,
14440                             NULL);
14441
14442       cell_area = background_area;
14443
14444       cell_area.y += vertical_separator / 2;
14445       cell_area.height -= vertical_separator;
14446
14447       if (gtk_tree_view_is_expander_column (tree_view, column))
14448         {
14449           if (!rtl)
14450             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14451           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14452
14453           if (gtk_tree_view_draw_expanders (tree_view))
14454             {
14455               if (!rtl)
14456                 cell_area.x += depth * tree_view->priv->expander_size;
14457               cell_area.width -= depth * tree_view->priv->expander_size;
14458             }
14459         }
14460
14461       if (gtk_tree_view_column_cell_is_visible (column))
14462         {
14463           if (is_separator)
14464             gtk_paint_hline (style,
14465                                    cr,
14466                                    GTK_STATE_NORMAL,
14467                                    widget,
14468                                    NULL,
14469                                    cell_area.x,
14470                                    cell_area.x + cell_area.width,
14471                                    cell_area.y + cell_area.height / 2);
14472           else
14473             _gtk_tree_view_column_cell_render (column,
14474                                                cr,
14475                                                &background_area,
14476                                                &cell_area,
14477                                                0, FALSE);
14478         }
14479       cell_offset += gtk_tree_view_column_get_width (column);
14480     }
14481
14482   cairo_set_source_rgb (cr, 0, 0, 0);
14483   cairo_rectangle (cr, 
14484                    0.5, 0.5, 
14485                    bin_window_width + 1,
14486                    background_area.height + 1);
14487   cairo_set_line_width (cr, 1.0);
14488   cairo_stroke (cr);
14489
14490   cairo_destroy (cr);
14491
14492   cairo_surface_set_device_offset (surface, 2, 2);
14493
14494   return surface;
14495 }
14496
14497
14498 /**
14499  * gtk_tree_view_set_destroy_count_func:
14500  * @tree_view: A #GtkTreeView
14501  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14502  * @data: (allow-none): User data to be passed to @func, or %NULL
14503  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14504  *
14505  * This function should almost never be used.  It is meant for private use by
14506  * ATK for determining the number of visible children that are removed when the
14507  * user collapses a row, or a row is deleted.
14508  **/
14509 void
14510 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14511                                       GtkTreeDestroyCountFunc  func,
14512                                       gpointer                 data,
14513                                       GDestroyNotify           destroy)
14514 {
14515   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14516
14517   if (tree_view->priv->destroy_count_destroy)
14518     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14519
14520   tree_view->priv->destroy_count_func = func;
14521   tree_view->priv->destroy_count_data = data;
14522   tree_view->priv->destroy_count_destroy = destroy;
14523 }
14524
14525
14526 /*
14527  * Interactive search
14528  */
14529
14530 /**
14531  * gtk_tree_view_set_enable_search:
14532  * @tree_view: A #GtkTreeView
14533  * @enable_search: %TRUE, if the user can search interactively
14534  *
14535  * If @enable_search is set, then the user can type in text to search through
14536  * the tree interactively (this is sometimes called "typeahead find").
14537  * 
14538  * Note that even if this is %FALSE, the user can still initiate a search 
14539  * using the "start-interactive-search" key binding.
14540  */
14541 void
14542 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14543                                  gboolean     enable_search)
14544 {
14545   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14546
14547   enable_search = !!enable_search;
14548   
14549   if (tree_view->priv->enable_search != enable_search)
14550     {
14551        tree_view->priv->enable_search = enable_search;
14552        g_object_notify (G_OBJECT (tree_view), "enable-search");
14553     }
14554 }
14555
14556 /**
14557  * gtk_tree_view_get_enable_search:
14558  * @tree_view: A #GtkTreeView
14559  *
14560  * Returns whether or not the tree allows to start interactive searching 
14561  * by typing in text.
14562  *
14563  * Return value: whether or not to let the user search interactively
14564  */
14565 gboolean
14566 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14567 {
14568   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14569
14570   return tree_view->priv->enable_search;
14571 }
14572
14573
14574 /**
14575  * gtk_tree_view_get_search_column:
14576  * @tree_view: A #GtkTreeView
14577  *
14578  * Gets the column searched on by the interactive search code.
14579  *
14580  * Return value: the column the interactive search code searches in.
14581  */
14582 gint
14583 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14584 {
14585   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14586
14587   return (tree_view->priv->search_column);
14588 }
14589
14590 /**
14591  * gtk_tree_view_set_search_column:
14592  * @tree_view: A #GtkTreeView
14593  * @column: the column of the model to search in, or -1 to disable searching
14594  *
14595  * Sets @column as the column where the interactive search code should
14596  * search in for the current model. 
14597  * 
14598  * If the search column is set, users can use the "start-interactive-search"
14599  * key binding to bring up search popup. The enable-search property controls
14600  * whether simply typing text will also start an interactive search.
14601  *
14602  * Note that @column refers to a column of the current model. The search 
14603  * column is reset to -1 when the model is changed.
14604  */
14605 void
14606 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14607                                  gint         column)
14608 {
14609   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14610   g_return_if_fail (column >= -1);
14611
14612   if (tree_view->priv->search_column == column)
14613     return;
14614
14615   tree_view->priv->search_column = column;
14616   g_object_notify (G_OBJECT (tree_view), "search-column");
14617 }
14618
14619 /**
14620  * gtk_tree_view_get_search_equal_func:
14621  * @tree_view: A #GtkTreeView
14622  *
14623  * Returns the compare function currently in use.
14624  *
14625  * Return value: the currently used compare function for the search code.
14626  */
14627
14628 GtkTreeViewSearchEqualFunc
14629 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14630 {
14631   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14632
14633   return tree_view->priv->search_equal_func;
14634 }
14635
14636 /**
14637  * gtk_tree_view_set_search_equal_func:
14638  * @tree_view: A #GtkTreeView
14639  * @search_equal_func: the compare function to use during the search
14640  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14641  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14642  *
14643  * Sets the compare function for the interactive search capabilities; note
14644  * that somewhat like strcmp() returning 0 for equality
14645  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14646  **/
14647 void
14648 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14649                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14650                                      gpointer                    search_user_data,
14651                                      GDestroyNotify              search_destroy)
14652 {
14653   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14654   g_return_if_fail (search_equal_func != NULL);
14655
14656   if (tree_view->priv->search_destroy)
14657     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14658
14659   tree_view->priv->search_equal_func = search_equal_func;
14660   tree_view->priv->search_user_data = search_user_data;
14661   tree_view->priv->search_destroy = search_destroy;
14662   if (tree_view->priv->search_equal_func == NULL)
14663     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14664 }
14665
14666 /**
14667  * gtk_tree_view_get_search_entry:
14668  * @tree_view: A #GtkTreeView
14669  *
14670  * Returns the #GtkEntry which is currently in use as interactive search
14671  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14672  * will be returned.
14673  *
14674  * Return value: (transfer none): the entry currently in use as search entry.
14675  *
14676  * Since: 2.10
14677  */
14678 GtkEntry *
14679 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14680 {
14681   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14682
14683   if (tree_view->priv->search_custom_entry_set)
14684     return GTK_ENTRY (tree_view->priv->search_entry);
14685
14686   return NULL;
14687 }
14688
14689 /**
14690  * gtk_tree_view_set_search_entry:
14691  * @tree_view: A #GtkTreeView
14692  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14693  *
14694  * Sets the entry which the interactive search code will use for this
14695  * @tree_view.  This is useful when you want to provide a search entry
14696  * in our interface at all time at a fixed position.  Passing %NULL for
14697  * @entry will make the interactive search code use the built-in popup
14698  * entry again.
14699  *
14700  * Since: 2.10
14701  */
14702 void
14703 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14704                                 GtkEntry    *entry)
14705 {
14706   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14707   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14708
14709   if (tree_view->priv->search_custom_entry_set)
14710     {
14711       if (tree_view->priv->search_entry_changed_id)
14712         {
14713           g_signal_handler_disconnect (tree_view->priv->search_entry,
14714                                        tree_view->priv->search_entry_changed_id);
14715           tree_view->priv->search_entry_changed_id = 0;
14716         }
14717       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14718                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14719                                             tree_view);
14720
14721       g_object_unref (tree_view->priv->search_entry);
14722     }
14723   else if (tree_view->priv->search_window)
14724     {
14725       gtk_widget_destroy (tree_view->priv->search_window);
14726
14727       tree_view->priv->search_window = NULL;
14728     }
14729
14730   if (entry)
14731     {
14732       tree_view->priv->search_entry = g_object_ref (entry);
14733       tree_view->priv->search_custom_entry_set = TRUE;
14734
14735       if (tree_view->priv->search_entry_changed_id == 0)
14736         {
14737           tree_view->priv->search_entry_changed_id =
14738             g_signal_connect (tree_view->priv->search_entry, "changed",
14739                               G_CALLBACK (gtk_tree_view_search_init),
14740                               tree_view);
14741         }
14742       
14743         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14744                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14745                           tree_view);
14746
14747         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14748     }
14749   else
14750     {
14751       tree_view->priv->search_entry = NULL;
14752       tree_view->priv->search_custom_entry_set = FALSE;
14753     }
14754 }
14755
14756 /**
14757  * gtk_tree_view_set_search_position_func:
14758  * @tree_view: A #GtkTreeView
14759  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14760  *    to use the default search position function
14761  * @data: (allow-none): user data to pass to @func, or %NULL
14762  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14763  *
14764  * Sets the function to use when positioning the search dialog.
14765  *
14766  * Since: 2.10
14767  **/
14768 void
14769 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14770                                         GtkTreeViewSearchPositionFunc  func,
14771                                         gpointer                       user_data,
14772                                         GDestroyNotify                 destroy)
14773 {
14774   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14775
14776   if (tree_view->priv->search_position_destroy)
14777     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14778
14779   tree_view->priv->search_position_func = func;
14780   tree_view->priv->search_position_user_data = user_data;
14781   tree_view->priv->search_position_destroy = destroy;
14782   if (tree_view->priv->search_position_func == NULL)
14783     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14784 }
14785
14786 /**
14787  * gtk_tree_view_get_search_position_func:
14788  * @tree_view: A #GtkTreeView
14789  *
14790  * Returns the positioning function currently in use.
14791  *
14792  * Return value: the currently used function for positioning the search dialog.
14793  *
14794  * Since: 2.10
14795  */
14796 GtkTreeViewSearchPositionFunc
14797 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14798 {
14799   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14800
14801   return tree_view->priv->search_position_func;
14802 }
14803
14804
14805 static void
14806 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14807                                   GtkTreeView *tree_view,
14808                                   GdkDevice   *device)
14809 {
14810   if (tree_view->priv->disable_popdown)
14811     return;
14812
14813   if (tree_view->priv->search_entry_changed_id)
14814     {
14815       g_signal_handler_disconnect (tree_view->priv->search_entry,
14816                                    tree_view->priv->search_entry_changed_id);
14817       tree_view->priv->search_entry_changed_id = 0;
14818     }
14819   if (tree_view->priv->typeselect_flush_timeout)
14820     {
14821       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14822       tree_view->priv->typeselect_flush_timeout = 0;
14823     }
14824         
14825   if (gtk_widget_get_visible (search_dialog))
14826     {
14827       /* send focus-in event */
14828       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14829       gtk_widget_hide (search_dialog);
14830       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14831       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14832     }
14833 }
14834
14835 static void
14836 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14837                                     GtkWidget   *search_dialog,
14838                                     gpointer     user_data)
14839 {
14840   gint x, y;
14841   gint tree_x, tree_y;
14842   gint tree_width, tree_height;
14843   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14844   GdkScreen *screen = gdk_window_get_screen (tree_window);
14845   GtkRequisition requisition;
14846   gint monitor_num;
14847   GdkRectangle monitor;
14848
14849   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14850   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14851
14852   gtk_widget_realize (search_dialog);
14853
14854   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14855   tree_width = gdk_window_get_width (tree_window);
14856   tree_height = gdk_window_get_height (tree_window);
14857   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14858
14859   if (tree_x + tree_width > gdk_screen_get_width (screen))
14860     x = gdk_screen_get_width (screen) - requisition.width;
14861   else if (tree_x + tree_width - requisition.width < 0)
14862     x = 0;
14863   else
14864     x = tree_x + tree_width - requisition.width;
14865
14866   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14867     y = gdk_screen_get_height (screen) - requisition.height;
14868   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14869     y = 0;
14870   else
14871     y = tree_y + tree_height;
14872
14873   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14874 }
14875
14876 static void
14877 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14878                                       GtkMenu  *menu,
14879                                       gpointer  data)
14880 {
14881   GtkTreeView *tree_view = (GtkTreeView *)data;
14882
14883   tree_view->priv->disable_popdown = 1;
14884   g_signal_connect (menu, "hide",
14885                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14886 }
14887
14888 /* Because we're visible but offscreen, we just set a flag in the preedit
14889  * callback.
14890  */
14891 static void
14892 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14893                                       GtkTreeView  *tree_view)
14894 {
14895   tree_view->priv->imcontext_changed = 1;
14896   if (tree_view->priv->typeselect_flush_timeout)
14897     {
14898       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14899       tree_view->priv->typeselect_flush_timeout =
14900         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14901                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14902                        tree_view);
14903     }
14904
14905 }
14906
14907 static void
14908 gtk_tree_view_search_activate (GtkEntry    *entry,
14909                                GtkTreeView *tree_view)
14910 {
14911   GtkTreePath *path;
14912   GtkRBNode *node;
14913   GtkRBTree *tree;
14914
14915   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14916                                     tree_view,
14917                                     gtk_get_current_event_device ());
14918
14919   /* If we have a row selected and it's the cursor row, we activate
14920    * the row XXX */
14921   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14922     {
14923       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14924       
14925       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14926       
14927       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14928         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14929       
14930       gtk_tree_path_free (path);
14931     }
14932 }
14933
14934 static gboolean
14935 gtk_tree_view_real_search_enable_popdown (gpointer data)
14936 {
14937   GtkTreeView *tree_view = (GtkTreeView *)data;
14938
14939   tree_view->priv->disable_popdown = 0;
14940
14941   return FALSE;
14942 }
14943
14944 static void
14945 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14946                                      gpointer   data)
14947 {
14948   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14949 }
14950
14951 static gboolean
14952 gtk_tree_view_search_delete_event (GtkWidget *widget,
14953                                    GdkEventAny *event,
14954                                    GtkTreeView *tree_view)
14955 {
14956   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14957
14958   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14959
14960   return TRUE;
14961 }
14962
14963 static gboolean
14964 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14965                                          GdkEventButton *event,
14966                                          GtkTreeView *tree_view)
14967 {
14968   GdkDevice *keyb_device;
14969
14970   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14971
14972   keyb_device = gdk_device_get_associated_device (event->device);
14973   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14974
14975   if (event->window == tree_view->priv->bin_window)
14976     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14977
14978   return TRUE;
14979 }
14980
14981 static gboolean
14982 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14983                                    GdkEventScroll *event,
14984                                    GtkTreeView *tree_view)
14985 {
14986   gboolean retval = FALSE;
14987
14988   if (event->direction == GDK_SCROLL_UP)
14989     {
14990       gtk_tree_view_search_move (widget, tree_view, TRUE);
14991       retval = TRUE;
14992     }
14993   else if (event->direction == GDK_SCROLL_DOWN)
14994     {
14995       gtk_tree_view_search_move (widget, tree_view, FALSE);
14996       retval = TRUE;
14997     }
14998
14999   /* renew the flush timeout */
15000   if (retval && tree_view->priv->typeselect_flush_timeout
15001       && !tree_view->priv->search_custom_entry_set)
15002     {
15003       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15004       tree_view->priv->typeselect_flush_timeout =
15005         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15006                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15007                        tree_view);
15008     }
15009
15010   return retval;
15011 }
15012
15013 static gboolean
15014 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15015                                       GdkEventKey *event,
15016                                       GtkTreeView *tree_view)
15017 {
15018   gboolean retval = FALSE;
15019
15020   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15021   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15022
15023   /* close window and cancel the search */
15024   if (!tree_view->priv->search_custom_entry_set
15025       && (event->keyval == GDK_KEY_Escape ||
15026           event->keyval == GDK_KEY_Tab ||
15027             event->keyval == GDK_KEY_KP_Tab ||
15028             event->keyval == GDK_KEY_ISO_Left_Tab))
15029     {
15030       gtk_tree_view_search_dialog_hide (widget, tree_view,
15031                                         gdk_event_get_device ((GdkEvent *) event));
15032       return TRUE;
15033     }
15034
15035   /* select previous matching iter */
15036   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15037     {
15038       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15039         gtk_widget_error_bell (widget);
15040
15041       retval = TRUE;
15042     }
15043
15044   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
15045       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15046     {
15047       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15048         gtk_widget_error_bell (widget);
15049
15050       retval = TRUE;
15051     }
15052
15053   /* select next matching iter */
15054   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15055     {
15056       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15057         gtk_widget_error_bell (widget);
15058
15059       retval = TRUE;
15060     }
15061
15062   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
15063       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15064     {
15065       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15066         gtk_widget_error_bell (widget);
15067
15068       retval = TRUE;
15069     }
15070
15071   /* renew the flush timeout */
15072   if (retval && tree_view->priv->typeselect_flush_timeout
15073       && !tree_view->priv->search_custom_entry_set)
15074     {
15075       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15076       tree_view->priv->typeselect_flush_timeout =
15077         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15078                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15079                        tree_view);
15080     }
15081
15082   return retval;
15083 }
15084
15085 /*  this function returns FALSE if there is a search string but
15086  *  nothing was found, and TRUE otherwise.
15087  */
15088 static gboolean
15089 gtk_tree_view_search_move (GtkWidget   *window,
15090                            GtkTreeView *tree_view,
15091                            gboolean     up)
15092 {
15093   gboolean ret;
15094   gint len;
15095   gint count = 0;
15096   const gchar *text;
15097   GtkTreeIter iter;
15098   GtkTreeModel *model;
15099   GtkTreeSelection *selection;
15100
15101   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15102
15103   g_return_val_if_fail (text != NULL, FALSE);
15104
15105   len = strlen (text);
15106
15107   if (up && tree_view->priv->selected_iter == 1)
15108     return strlen (text) < 1;
15109
15110   len = strlen (text);
15111
15112   if (len < 1)
15113     return TRUE;
15114
15115   model = gtk_tree_view_get_model (tree_view);
15116   selection = gtk_tree_view_get_selection (tree_view);
15117
15118   /* search */
15119   gtk_tree_selection_unselect_all (selection);
15120   if (!gtk_tree_model_get_iter_first (model, &iter))
15121     return TRUE;
15122
15123   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15124                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15125
15126   if (ret)
15127     {
15128       /* found */
15129       tree_view->priv->selected_iter += up?(-1):(1);
15130       return TRUE;
15131     }
15132   else
15133     {
15134       /* return to old iter */
15135       count = 0;
15136       gtk_tree_model_get_iter_first (model, &iter);
15137       gtk_tree_view_search_iter (model, selection,
15138                                  &iter, text,
15139                                  &count, tree_view->priv->selected_iter);
15140       return FALSE;
15141     }
15142 }
15143
15144 static gboolean
15145 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15146                                  gint          column,
15147                                  const gchar  *key,
15148                                  GtkTreeIter  *iter,
15149                                  gpointer      search_data)
15150 {
15151   gboolean retval = TRUE;
15152   const gchar *str;
15153   gchar *normalized_string;
15154   gchar *normalized_key;
15155   gchar *case_normalized_string = NULL;
15156   gchar *case_normalized_key = NULL;
15157   GValue value = {0,};
15158   GValue transformed = {0,};
15159
15160   gtk_tree_model_get_value (model, iter, column, &value);
15161
15162   g_value_init (&transformed, G_TYPE_STRING);
15163
15164   if (!g_value_transform (&value, &transformed))
15165     {
15166       g_value_unset (&value);
15167       return TRUE;
15168     }
15169
15170   g_value_unset (&value);
15171
15172   str = g_value_get_string (&transformed);
15173   if (!str)
15174     {
15175       g_value_unset (&transformed);
15176       return TRUE;
15177     }
15178
15179   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15180   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15181
15182   if (normalized_string && normalized_key)
15183     {
15184       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15185       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15186
15187       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15188         retval = FALSE;
15189     }
15190
15191   g_value_unset (&transformed);
15192   g_free (normalized_key);
15193   g_free (normalized_string);
15194   g_free (case_normalized_key);
15195   g_free (case_normalized_string);
15196
15197   return retval;
15198 }
15199
15200 static gboolean
15201 gtk_tree_view_search_iter (GtkTreeModel     *model,
15202                            GtkTreeSelection *selection,
15203                            GtkTreeIter      *iter,
15204                            const gchar      *text,
15205                            gint             *count,
15206                            gint              n)
15207 {
15208   GtkRBTree *tree = NULL;
15209   GtkRBNode *node = NULL;
15210   GtkTreePath *path;
15211
15212   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15213
15214   path = gtk_tree_model_get_path (model, iter);
15215   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15216
15217   do
15218     {
15219       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15220         {
15221           (*count)++;
15222           if (*count == n)
15223             {
15224               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15225                                             TRUE, 0.5, 0.0);
15226               gtk_tree_selection_select_iter (selection, iter);
15227               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15228
15229               if (path)
15230                 gtk_tree_path_free (path);
15231
15232               return TRUE;
15233             }
15234         }
15235
15236       if (node->children)
15237         {
15238           gboolean has_child;
15239           GtkTreeIter tmp;
15240
15241           tree = node->children;
15242           node = tree->root;
15243
15244           while (node->left != tree->nil)
15245             node = node->left;
15246
15247           tmp = *iter;
15248           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15249           gtk_tree_path_down (path);
15250
15251           /* sanity check */
15252           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15253         }
15254       else
15255         {
15256           gboolean done = FALSE;
15257
15258           do
15259             {
15260               node = _gtk_rbtree_next (tree, node);
15261
15262               if (node)
15263                 {
15264                   gboolean has_next;
15265
15266                   has_next = gtk_tree_model_iter_next (model, iter);
15267
15268                   done = TRUE;
15269                   gtk_tree_path_next (path);
15270
15271                   /* sanity check */
15272                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15273                 }
15274               else
15275                 {
15276                   gboolean has_parent;
15277                   GtkTreeIter tmp_iter = *iter;
15278
15279                   node = tree->parent_node;
15280                   tree = tree->parent_tree;
15281
15282                   if (!tree)
15283                     {
15284                       if (path)
15285                         gtk_tree_path_free (path);
15286
15287                       /* we've run out of tree, done with this func */
15288                       return FALSE;
15289                     }
15290
15291                   has_parent = gtk_tree_model_iter_parent (model,
15292                                                            iter,
15293                                                            &tmp_iter);
15294                   gtk_tree_path_up (path);
15295
15296                   /* sanity check */
15297                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15298                 }
15299             }
15300           while (!done);
15301         }
15302     }
15303   while (1);
15304
15305   return FALSE;
15306 }
15307
15308 static void
15309 gtk_tree_view_search_init (GtkWidget   *entry,
15310                            GtkTreeView *tree_view)
15311 {
15312   gint ret;
15313   gint count = 0;
15314   const gchar *text;
15315   GtkTreeIter iter;
15316   GtkTreeModel *model;
15317   GtkTreeSelection *selection;
15318
15319   g_return_if_fail (GTK_IS_ENTRY (entry));
15320   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15321
15322   text = gtk_entry_get_text (GTK_ENTRY (entry));
15323
15324   model = gtk_tree_view_get_model (tree_view);
15325   selection = gtk_tree_view_get_selection (tree_view);
15326
15327   /* search */
15328   gtk_tree_selection_unselect_all (selection);
15329   if (tree_view->priv->typeselect_flush_timeout
15330       && !tree_view->priv->search_custom_entry_set)
15331     {
15332       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15333       tree_view->priv->typeselect_flush_timeout =
15334         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15335                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15336                        tree_view);
15337     }
15338
15339   if (*text == '\0')
15340     return;
15341
15342   if (!gtk_tree_model_get_iter_first (model, &iter))
15343     return;
15344
15345   ret = gtk_tree_view_search_iter (model, selection,
15346                                    &iter, text,
15347                                    &count, 1);
15348
15349   if (ret)
15350     tree_view->priv->selected_iter = 1;
15351 }
15352
15353 void
15354 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15355                                 GtkTreeViewColumn *column,
15356                                 GtkCellEditable   *cell_editable)
15357 {
15358   if (tree_view->priv->edited_column == NULL)
15359     return;
15360
15361   g_return_if_fail (column == tree_view->priv->edited_column);
15362
15363   tree_view->priv->edited_column = NULL;
15364
15365   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15366     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15367
15368   gtk_container_remove (GTK_CONTAINER (tree_view),
15369                         GTK_WIDGET (cell_editable));
15370
15371   /* FIXME should only redraw a single node */
15372   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15373 }
15374
15375 static gboolean
15376 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15377                              GtkTreePath *cursor_path)
15378 {
15379   GtkTreeIter iter;
15380   GdkRectangle cell_area;
15381   GtkTreeViewColumn *focus_column;
15382   gchar *path_string;
15383   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15384   gint retval = FALSE;
15385   GtkRBTree *cursor_tree;
15386   GtkRBNode *cursor_node;
15387
15388   g_assert (tree_view->priv->focus_column);
15389   focus_column = tree_view->priv->focus_column;
15390
15391   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15392     return FALSE;
15393
15394   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15395       cursor_node == NULL)
15396     return FALSE;
15397
15398   path_string = gtk_tree_path_to_string (cursor_path);
15399   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15400
15401   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15402
15403   gtk_tree_view_column_cell_set_cell_data (focus_column,
15404                                            tree_view->priv->model,
15405                                            &iter,
15406                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15407                                            cursor_node->children?TRUE:FALSE);
15408   gtk_tree_view_get_cell_area (tree_view,
15409                                cursor_path,
15410                                focus_column,
15411                                &cell_area);
15412
15413   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15414                               _gtk_tree_view_column_get_context (focus_column),
15415                               GTK_WIDGET (tree_view),
15416                               &cell_area,
15417                               flags))
15418     retval = TRUE;
15419
15420   return retval;
15421 }
15422
15423 void
15424 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15425                              GtkTreeViewColumn *column,
15426                              GtkTreePath       *path,
15427                              GtkCellEditable   *cell_editable,
15428                              GdkRectangle      *cell_area)
15429 {
15430   gint pre_val = tree_view->priv->vadjustment->value;
15431   GtkRequisition requisition;
15432
15433   tree_view->priv->edited_column = column;
15434
15435   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15436   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
15437
15438   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15439                                  &requisition, NULL);
15440
15441   tree_view->priv->draw_keyfocus = TRUE;
15442
15443   if (requisition.height < cell_area->height)
15444     {
15445       gint diff = cell_area->height - requisition.height;
15446       gtk_tree_view_put (tree_view,
15447                          GTK_WIDGET (cell_editable),
15448                          cell_area->x, cell_area->y + diff/2,
15449                          cell_area->width, requisition.height);
15450     }
15451   else
15452     {
15453       gtk_tree_view_put (tree_view,
15454                          GTK_WIDGET (cell_editable),
15455                          cell_area->x, cell_area->y,
15456                          cell_area->width, cell_area->height);
15457     }
15458 }
15459
15460 static void
15461 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15462                             gboolean     cancel_editing)
15463 {
15464   GtkTreeViewColumn *column;
15465
15466   if (tree_view->priv->edited_column == NULL)
15467     return;
15468
15469   /*
15470    * This is very evil. We need to do this, because
15471    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15472    * later on. If gtk_tree_view_row_changed notices
15473    * tree_view->priv->edited_column != NULL, it'll call
15474    * gtk_tree_view_stop_editing again. Bad things will happen then.
15475    *
15476    * Please read that again if you intend to modify anything here.
15477    */
15478
15479   column = tree_view->priv->edited_column;
15480   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15481   tree_view->priv->edited_column = NULL;
15482 }
15483
15484
15485 /**
15486  * gtk_tree_view_set_hover_selection:
15487  * @tree_view: a #GtkTreeView
15488  * @hover: %TRUE to enable hover selection mode
15489  *
15490  * Enables of disables the hover selection mode of @tree_view.
15491  * Hover selection makes the selected row follow the pointer.
15492  * Currently, this works only for the selection modes 
15493  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15494  * 
15495  * Since: 2.6
15496  **/
15497 void     
15498 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15499                                    gboolean     hover)
15500 {
15501   hover = hover != FALSE;
15502
15503   if (hover != tree_view->priv->hover_selection)
15504     {
15505       tree_view->priv->hover_selection = hover;
15506
15507       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15508     }
15509 }
15510
15511 /**
15512  * gtk_tree_view_get_hover_selection:
15513  * @tree_view: a #GtkTreeView
15514  * 
15515  * Returns whether hover selection mode is turned on for @tree_view.
15516  * 
15517  * Return value: %TRUE if @tree_view is in hover selection mode
15518  *
15519  * Since: 2.6 
15520  **/
15521 gboolean 
15522 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15523 {
15524   return tree_view->priv->hover_selection;
15525 }
15526
15527 /**
15528  * gtk_tree_view_set_hover_expand:
15529  * @tree_view: a #GtkTreeView
15530  * @expand: %TRUE to enable hover selection mode
15531  *
15532  * Enables of disables the hover expansion mode of @tree_view.
15533  * Hover expansion makes rows expand or collapse if the pointer 
15534  * moves over them.
15535  * 
15536  * Since: 2.6
15537  **/
15538 void     
15539 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15540                                 gboolean     expand)
15541 {
15542   expand = expand != FALSE;
15543
15544   if (expand != tree_view->priv->hover_expand)
15545     {
15546       tree_view->priv->hover_expand = expand;
15547
15548       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15549     }
15550 }
15551
15552 /**
15553  * gtk_tree_view_get_hover_expand:
15554  * @tree_view: a #GtkTreeView
15555  * 
15556  * Returns whether hover expansion mode is turned on for @tree_view.
15557  * 
15558  * Return value: %TRUE if @tree_view is in hover expansion mode
15559  *
15560  * Since: 2.6 
15561  **/
15562 gboolean 
15563 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15564 {
15565   return tree_view->priv->hover_expand;
15566 }
15567
15568 /**
15569  * gtk_tree_view_set_rubber_banding:
15570  * @tree_view: a #GtkTreeView
15571  * @enable: %TRUE to enable rubber banding
15572  *
15573  * Enables or disables rubber banding in @tree_view.  If the selection mode
15574  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15575  * multiple rows by dragging the mouse.
15576  * 
15577  * Since: 2.10
15578  **/
15579 void
15580 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15581                                   gboolean     enable)
15582 {
15583   enable = enable != FALSE;
15584
15585   if (enable != tree_view->priv->rubber_banding_enable)
15586     {
15587       tree_view->priv->rubber_banding_enable = enable;
15588
15589       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15590     }
15591 }
15592
15593 /**
15594  * gtk_tree_view_get_rubber_banding:
15595  * @tree_view: a #GtkTreeView
15596  * 
15597  * Returns whether rubber banding is turned on for @tree_view.  If the
15598  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15599  * user to select multiple rows by dragging the mouse.
15600  * 
15601  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15602  *
15603  * Since: 2.10
15604  **/
15605 gboolean
15606 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15607 {
15608   return tree_view->priv->rubber_banding_enable;
15609 }
15610
15611 /**
15612  * gtk_tree_view_is_rubber_banding_active:
15613  * @tree_view: a #GtkTreeView
15614  * 
15615  * Returns whether a rubber banding operation is currently being done
15616  * in @tree_view.
15617  *
15618  * Return value: %TRUE if a rubber banding operation is currently being
15619  * done in @tree_view.
15620  *
15621  * Since: 2.12
15622  **/
15623 gboolean
15624 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15625 {
15626   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15627
15628   if (tree_view->priv->rubber_banding_enable
15629       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15630     return TRUE;
15631
15632   return FALSE;
15633 }
15634
15635 /**
15636  * gtk_tree_view_get_row_separator_func:
15637  * @tree_view: a #GtkTreeView
15638  * 
15639  * Returns the current row separator function.
15640  * 
15641  * Return value: the current row separator function.
15642  *
15643  * Since: 2.6
15644  **/
15645 GtkTreeViewRowSeparatorFunc 
15646 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15647 {
15648   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15649
15650   return tree_view->priv->row_separator_func;
15651 }
15652
15653 /**
15654  * gtk_tree_view_set_row_separator_func:
15655  * @tree_view: a #GtkTreeView
15656  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15657  * @data: (allow-none): user data to pass to @func, or %NULL
15658  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15659  * 
15660  * Sets the row separator function, which is used to determine
15661  * whether a row should be drawn as a separator. If the row separator
15662  * function is %NULL, no separators are drawn. This is the default value.
15663  *
15664  * Since: 2.6
15665  **/
15666 void
15667 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15668                                       GtkTreeViewRowSeparatorFunc  func,
15669                                       gpointer                     data,
15670                                       GDestroyNotify               destroy)
15671 {
15672   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15673
15674   if (tree_view->priv->row_separator_destroy)
15675     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15676
15677   tree_view->priv->row_separator_func = func;
15678   tree_view->priv->row_separator_data = data;
15679   tree_view->priv->row_separator_destroy = destroy;
15680
15681   /* Have the tree recalculate heights */
15682   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15683   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15684 }
15685
15686   
15687 static void
15688 gtk_tree_view_grab_notify (GtkWidget *widget,
15689                            gboolean   was_grabbed)
15690 {
15691   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15692
15693   tree_view->priv->in_grab = !was_grabbed;
15694
15695   if (!was_grabbed)
15696     {
15697       tree_view->priv->pressed_button = -1;
15698
15699       if (tree_view->priv->rubber_band_status)
15700         gtk_tree_view_stop_rubber_band (tree_view);
15701     }
15702 }
15703
15704 static void
15705 gtk_tree_view_state_changed (GtkWidget      *widget,
15706                              GtkStateType    previous_state)
15707 {
15708   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15709
15710   if (gtk_widget_get_realized (widget))
15711     {
15712       gdk_window_set_background (tree_view->priv->bin_window,
15713                                  &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
15714     }
15715
15716   gtk_widget_queue_draw (widget);
15717 }
15718
15719 /**
15720  * gtk_tree_view_get_grid_lines:
15721  * @tree_view: a #GtkTreeView
15722  *
15723  * Returns which grid lines are enabled in @tree_view.
15724  *
15725  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15726  * are enabled.
15727  *
15728  * Since: 2.10
15729  */
15730 GtkTreeViewGridLines
15731 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15732 {
15733   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15734
15735   return tree_view->priv->grid_lines;
15736 }
15737
15738 /**
15739  * gtk_tree_view_set_grid_lines:
15740  * @tree_view: a #GtkTreeView
15741  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15742  * enable.
15743  *
15744  * Sets which grid lines to draw in @tree_view.
15745  *
15746  * Since: 2.10
15747  */
15748 void
15749 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15750                               GtkTreeViewGridLines   grid_lines)
15751 {
15752   GtkTreeViewPrivate *priv;
15753   GtkWidget *widget;
15754   GtkTreeViewGridLines old_grid_lines;
15755
15756   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15757
15758   priv = tree_view->priv;
15759   widget = GTK_WIDGET (tree_view);
15760
15761   old_grid_lines = priv->grid_lines;
15762   priv->grid_lines = grid_lines;
15763   
15764   if (gtk_widget_get_realized (widget))
15765     {
15766       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15767           priv->grid_line_width)
15768         {
15769           priv->grid_line_width = 0;
15770         }
15771       
15772       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15773           !priv->grid_line_width)
15774         {
15775           gint8 *dash_list;
15776
15777           gtk_widget_style_get (widget,
15778                                 "grid-line-width", &priv->grid_line_width,
15779                                 "grid-line-pattern", (gchar *)&dash_list,
15780                                 NULL);
15781       
15782           if (dash_list)
15783             {
15784               priv->grid_line_dashes[0] = dash_list[0];
15785               if (dash_list[0])
15786                 priv->grid_line_dashes[1] = dash_list[1];
15787               
15788               g_free (dash_list);
15789             }
15790           else
15791             {
15792               priv->grid_line_dashes[0] = 1;
15793               priv->grid_line_dashes[1] = 1;
15794             }
15795         }      
15796     }
15797
15798   if (old_grid_lines != grid_lines)
15799     {
15800       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15801       
15802       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15803     }
15804 }
15805
15806 /**
15807  * gtk_tree_view_get_enable_tree_lines:
15808  * @tree_view: a #GtkTreeView.
15809  *
15810  * Returns whether or not tree lines are drawn in @tree_view.
15811  *
15812  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15813  * otherwise.
15814  *
15815  * Since: 2.10
15816  */
15817 gboolean
15818 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15819 {
15820   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15821
15822   return tree_view->priv->tree_lines_enabled;
15823 }
15824
15825 /**
15826  * gtk_tree_view_set_enable_tree_lines:
15827  * @tree_view: a #GtkTreeView
15828  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15829  *
15830  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15831  * This does not have any visible effects for lists.
15832  *
15833  * Since: 2.10
15834  */
15835 void
15836 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15837                                      gboolean     enabled)
15838 {
15839   GtkTreeViewPrivate *priv;
15840   GtkWidget *widget;
15841   gboolean was_enabled;
15842
15843   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15844
15845   enabled = enabled != FALSE;
15846
15847   priv = tree_view->priv;
15848   widget = GTK_WIDGET (tree_view);
15849
15850   was_enabled = priv->tree_lines_enabled;
15851
15852   priv->tree_lines_enabled = enabled;
15853
15854   if (gtk_widget_get_realized (widget))
15855     {
15856       if (!enabled && priv->tree_line_width)
15857         {
15858           priv->tree_line_width = 0;
15859         }
15860       
15861       if (enabled && !priv->tree_line_width)
15862         {
15863           gint8 *dash_list;
15864           gtk_widget_style_get (widget,
15865                                 "tree-line-width", &priv->tree_line_width,
15866                                 "tree-line-pattern", (gchar *)&dash_list,
15867                                 NULL);
15868           
15869           if (dash_list)
15870             {
15871               priv->tree_line_dashes[0] = dash_list[0];
15872               if (dash_list[0])
15873                 priv->tree_line_dashes[1] = dash_list[1];
15874               
15875               g_free (dash_list);
15876             }
15877           else
15878             {
15879               priv->tree_line_dashes[0] = 1;
15880               priv->tree_line_dashes[1] = 1;
15881             }
15882         }
15883     }
15884
15885   if (was_enabled != enabled)
15886     {
15887       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15888
15889       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15890     }
15891 }
15892
15893
15894 /**
15895  * gtk_tree_view_set_show_expanders:
15896  * @tree_view: a #GtkTreeView
15897  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15898  *
15899  * Sets whether to draw and enable expanders and indent child rows in
15900  * @tree_view.  When disabled there will be no expanders visible in trees
15901  * and there will be no way to expand and collapse rows by default.  Also
15902  * note that hiding the expanders will disable the default indentation.  You
15903  * can set a custom indentation in this case using
15904  * gtk_tree_view_set_level_indentation().
15905  * This does not have any visible effects for lists.
15906  *
15907  * Since: 2.12
15908  */
15909 void
15910 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15911                                   gboolean     enabled)
15912 {
15913   gboolean was_enabled;
15914
15915   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15916
15917   enabled = enabled != FALSE;
15918   was_enabled = tree_view->priv->show_expanders;
15919
15920   tree_view->priv->show_expanders = enabled == TRUE;
15921
15922   if (enabled != was_enabled)
15923     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15924 }
15925
15926 /**
15927  * gtk_tree_view_get_show_expanders:
15928  * @tree_view: a #GtkTreeView.
15929  *
15930  * Returns whether or not expanders are drawn in @tree_view.
15931  *
15932  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15933  * otherwise.
15934  *
15935  * Since: 2.12
15936  */
15937 gboolean
15938 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15939 {
15940   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15941
15942   return tree_view->priv->show_expanders;
15943 }
15944
15945 /**
15946  * gtk_tree_view_set_level_indentation:
15947  * @tree_view: a #GtkTreeView
15948  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15949  *
15950  * Sets the amount of extra indentation for child levels to use in @tree_view
15951  * in addition to the default indentation.  The value should be specified in
15952  * pixels, a value of 0 disables this feature and in this case only the default
15953  * indentation will be used.
15954  * This does not have any visible effects for lists.
15955  *
15956  * Since: 2.12
15957  */
15958 void
15959 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15960                                      gint         indentation)
15961 {
15962   tree_view->priv->level_indentation = indentation;
15963
15964   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15965 }
15966
15967 /**
15968  * gtk_tree_view_get_level_indentation:
15969  * @tree_view: a #GtkTreeView.
15970  *
15971  * Returns the amount, in pixels, of extra indentation for child levels
15972  * in @tree_view.
15973  *
15974  * Return value: the amount of extra indentation for child levels in
15975  * @tree_view.  A return value of 0 means that this feature is disabled.
15976  *
15977  * Since: 2.12
15978  */
15979 gint
15980 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15981 {
15982   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15983
15984   return tree_view->priv->level_indentation;
15985 }
15986
15987 /**
15988  * gtk_tree_view_set_tooltip_row:
15989  * @tree_view: a #GtkTreeView
15990  * @tooltip: a #GtkTooltip
15991  * @path: a #GtkTreePath
15992  *
15993  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15994  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15995  * See also gtk_tooltip_set_tip_area().
15996  *
15997  * Since: 2.12
15998  */
15999 void
16000 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16001                                GtkTooltip  *tooltip,
16002                                GtkTreePath *path)
16003 {
16004   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16005   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16006
16007   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16008 }
16009
16010 /**
16011  * gtk_tree_view_set_tooltip_cell:
16012  * @tree_view: a #GtkTreeView
16013  * @tooltip: a #GtkTooltip
16014  * @path: (allow-none): a #GtkTreePath or %NULL
16015  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16016  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16017  *
16018  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16019  * in common.  For example if @path is %NULL and @column is set, the tip
16020  * area will be set to the full area covered by @column.  See also
16021  * gtk_tooltip_set_tip_area().
16022  *
16023  * Note that if @path is not specified and @cell is set and part of a column
16024  * containing the expander, the tooltip might not show and hide at the correct
16025  * position.  In such cases @path must be set to the current node under the
16026  * mouse cursor for this function to operate correctly.
16027  *
16028  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16029  *
16030  * Since: 2.12
16031  */
16032 void
16033 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16034                                 GtkTooltip        *tooltip,
16035                                 GtkTreePath       *path,
16036                                 GtkTreeViewColumn *column,
16037                                 GtkCellRenderer   *cell)
16038 {
16039   GtkAllocation allocation;
16040   GdkRectangle rect;
16041
16042   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16043   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16044   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16045   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16046
16047   /* Determine x values. */
16048   if (column && cell)
16049     {
16050       GdkRectangle tmp;
16051       gint start, width;
16052
16053       /* We always pass in path here, whether it is NULL or not.
16054        * For cells in expander columns path must be specified so that
16055        * we can correctly account for the indentation.  This also means
16056        * that the tooltip is constrained vertically by the "Determine y
16057        * values" code below; this is not a real problem since cells actually
16058        * don't stretch vertically in constrast to columns.
16059        */
16060       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16061       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16062
16063       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16064                                                          tmp.x + start, 0,
16065                                                          &rect.x, NULL);
16066       rect.width = width;
16067     }
16068   else if (column)
16069     {
16070       GdkRectangle tmp;
16071
16072       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16073       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16074                                                          tmp.x, 0,
16075                                                          &rect.x, NULL);
16076       rect.width = tmp.width;
16077     }
16078   else
16079     {
16080       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16081       rect.x = 0;
16082       rect.width = allocation.width;
16083     }
16084
16085   /* Determine y values. */
16086   if (path)
16087     {
16088       GdkRectangle tmp;
16089
16090       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16091       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16092                                                          0, tmp.y,
16093                                                          NULL, &rect.y);
16094       rect.height = tmp.height;
16095     }
16096   else
16097     {
16098       rect.y = 0;
16099       rect.height = tree_view->priv->vadjustment->page_size;
16100     }
16101
16102   gtk_tooltip_set_tip_area (tooltip, &rect);
16103 }
16104
16105 /**
16106  * gtk_tree_view_get_tooltip_context:
16107  * @tree_view: a #GtkTreeView
16108  * @x: the x coordinate (relative to widget coordinates)
16109  * @y: the y coordinate (relative to widget coordinates)
16110  * @keyboard_tip: whether this is a keyboard tooltip or not
16111  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
16112  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16113  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16114  *
16115  * This function is supposed to be used in a #GtkWidget::query-tooltip
16116  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16117  * which are received in the signal handler, should be passed to this
16118  * function without modification.
16119  *
16120  * The return value indicates whether there is a tree view row at the given
16121  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16122  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16123  * @model, @path and @iter which have been provided will be set to point to
16124  * that row and the corresponding model.  @x and @y will always be converted
16125  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16126  *
16127  * Return value: whether or not the given tooltip context points to a row.
16128  *
16129  * Since: 2.12
16130  */
16131 gboolean
16132 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16133                                    gint          *x,
16134                                    gint          *y,
16135                                    gboolean       keyboard_tip,
16136                                    GtkTreeModel **model,
16137                                    GtkTreePath  **path,
16138                                    GtkTreeIter   *iter)
16139 {
16140   GtkTreePath *tmppath = NULL;
16141
16142   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16143   g_return_val_if_fail (x != NULL, FALSE);
16144   g_return_val_if_fail (y != NULL, FALSE);
16145
16146   if (keyboard_tip)
16147     {
16148       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16149
16150       if (!tmppath)
16151         return FALSE;
16152     }
16153   else
16154     {
16155       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16156                                                          x, y);
16157
16158       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16159                                           &tmppath, NULL, NULL, NULL))
16160         return FALSE;
16161     }
16162
16163   if (model)
16164     *model = gtk_tree_view_get_model (tree_view);
16165
16166   if (iter)
16167     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16168                              iter, tmppath);
16169
16170   if (path)
16171     *path = tmppath;
16172   else
16173     gtk_tree_path_free (tmppath);
16174
16175   return TRUE;
16176 }
16177
16178 static gboolean
16179 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16180                                     gint        x,
16181                                     gint        y,
16182                                     gboolean    keyboard_tip,
16183                                     GtkTooltip *tooltip,
16184                                     gpointer    data)
16185 {
16186   GValue value = { 0, };
16187   GValue transformed = { 0, };
16188   GtkTreeIter iter;
16189   GtkTreePath *path;
16190   GtkTreeModel *model;
16191   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16192
16193   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16194                                           &x, &y,
16195                                           keyboard_tip,
16196                                           &model, &path, &iter))
16197     return FALSE;
16198
16199   gtk_tree_model_get_value (model, &iter,
16200                             tree_view->priv->tooltip_column, &value);
16201
16202   g_value_init (&transformed, G_TYPE_STRING);
16203
16204   if (!g_value_transform (&value, &transformed))
16205     {
16206       g_value_unset (&value);
16207       gtk_tree_path_free (path);
16208
16209       return FALSE;
16210     }
16211
16212   g_value_unset (&value);
16213
16214   if (!g_value_get_string (&transformed))
16215     {
16216       g_value_unset (&transformed);
16217       gtk_tree_path_free (path);
16218
16219       return FALSE;
16220     }
16221
16222   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16223   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16224
16225   gtk_tree_path_free (path);
16226   g_value_unset (&transformed);
16227
16228   return TRUE;
16229 }
16230
16231 /**
16232  * gtk_tree_view_set_tooltip_column:
16233  * @tree_view: a #GtkTreeView
16234  * @column: an integer, which is a valid column number for @tree_view's model
16235  *
16236  * If you only plan to have simple (text-only) tooltips on full rows, you
16237  * can use this function to have #GtkTreeView handle these automatically
16238  * for you. @column should be set to the column in @tree_view's model
16239  * containing the tooltip texts, or -1 to disable this feature.
16240  *
16241  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
16242  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16243  *
16244  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16245  * so &amp;, &lt;, etc have to be escaped in the text.
16246  *
16247  * Since: 2.12
16248  */
16249 void
16250 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16251                                   gint         column)
16252 {
16253   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16254
16255   if (column == tree_view->priv->tooltip_column)
16256     return;
16257
16258   if (column == -1)
16259     {
16260       g_signal_handlers_disconnect_by_func (tree_view,
16261                                             gtk_tree_view_set_tooltip_query_cb,
16262                                             NULL);
16263       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16264     }
16265   else
16266     {
16267       if (tree_view->priv->tooltip_column == -1)
16268         {
16269           g_signal_connect (tree_view, "query-tooltip",
16270                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16271           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16272         }
16273     }
16274
16275   tree_view->priv->tooltip_column = column;
16276   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16277 }
16278
16279 /**
16280  * gtk_tree_view_get_tooltip_column:
16281  * @tree_view: a #GtkTreeView
16282  *
16283  * Returns the column of @tree_view's model which is being used for
16284  * displaying tooltips on @tree_view's rows.
16285  *
16286  * Return value: the index of the tooltip column that is currently being
16287  * used, or -1 if this is disabled.
16288  *
16289  * Since: 2.12
16290  */
16291 gint
16292 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16293 {
16294   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16295
16296   return tree_view->priv->tooltip_column;
16297 }