]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
f45c0a18d7aaf746303f454013cff6d7c998a853
[~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 "gtkprivate.h"
49 #include "gtkwidgetprivate.h"
50
51
52 /**
53  * SECTION:gtktreeview
54  * @Short_description: A widget for displaying both trees and lists
55  * @Title: GtkTreeView
56  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
57  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
58  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
59  *   #GtkCellRendererText, #GtkCellRendererToggle
60  *
61  * Widget that displays any object that implements the #GtkTreeModel interface.
62  *
63  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
64  * overview</link> for an overview of all the objects and data types related
65  * to the tree widget and how they work together.
66  *
67  * Several different coordinate systems are exposed in the GtkTreeView API.
68  * These are:
69  *
70  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
71  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
72  * <varlistentry><term>Widget coordinates</term>
73  * <listitem>
74  * <para>
75  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
76  * </para>
77  * </listitem>
78  * </varlistentry>
79  * <varlistentry><term>Bin window coordinates</term>
80  * <listitem>
81  * <para>
82  * Coordinates relative to the window that GtkTreeView renders to.
83  * </para>
84  * </listitem>
85  * </varlistentry>
86  * <varlistentry><term>Tree coordinates</term>
87  * <listitem>
88  * <para>
89  * Coordinates relative to the entire scrollable area of GtkTreeView. These
90  * coordinates start at (0, 0) for row 0 of the tree.
91  * </para>
92  * </listitem>
93  * </varlistentry>
94  * </variablelist>
95  *
96  * Several functions are available for converting between the different
97  * coordinate systems.  The most common translations are between widget and bin
98  * window coordinates and between bin window and tree coordinates. For the
99  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
100  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
101  * (and vice versa).
102  *
103  * <refsect2 id="GtkTreeView-BUILDER-UI">
104  * <title>GtkTreeView as GtkBuildable</title>
105  * The GtkTreeView implementation of the GtkBuildable interface accepts
106  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
107  * internal #GtkTreeSelection in UI definitions.
108  * <example>
109  * <title>A UI definition fragment with GtkTreeView</title>
110  * <programlisting><![CDATA[
111  * <object class="GtkTreeView" id="treeview">
112  *   <property name="model">liststore1</property>
113  *   <child>
114  *     <object class="GtkTreeViewColumn" id="test-column">
115  *       <property name="title">Test</property>
116  *       <child>
117  *         <object class="GtkCellRendererText" id="test-renderer"/>
118  *         <attributes>
119  *           <attribute name="text">1</attribute>
120  *         </attributes>
121  *       </child>
122  *     </object>
123  *   </child>
124  *   <child internal-child="selection">
125  *     <object class="GtkTreeSelection" id="selection">
126  *       <signal name="changed" handler="on_treeview_selection_changed"/>
127  *     </object>
128  *   </child>
129  * </object>
130  * ]]></programlisting>
131  * </example>
132  * </refsect2>
133  */
134
135
136 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
137 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
138 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
139 #define SCROLL_EDGE_SIZE 15
140 #define EXPANDER_EXTRA_PADDING 4
141 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
142 #define AUTO_EXPAND_TIMEOUT 500
143
144 /* The "background" areas of all rows/cells add up to cover the entire tree.
145  * The background includes all inter-row and inter-cell spacing.
146  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
147  * i.e. just the cells, no spacing.
148  */
149
150 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
151 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
152
153 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
154  * vice versa.
155  */
156 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
157 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
158
159 /* This is in bin_window coordinates */
160 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
161 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
162
163 #define ROW_HEIGHT(tree_view,height) \
164   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
165
166
167 typedef struct _GtkTreeViewChild GtkTreeViewChild;
168 struct _GtkTreeViewChild
169 {
170   GtkWidget *widget;
171   gint x;
172   gint y;
173   gint width;
174   gint height;
175 };
176
177
178 typedef struct _TreeViewDragInfo TreeViewDragInfo;
179 struct _TreeViewDragInfo
180 {
181   GdkModifierType start_button_mask;
182   GtkTargetList *_unused_source_target_list;
183   GdkDragAction source_actions;
184
185   GtkTargetList *_unused_dest_target_list;
186
187   guint source_set : 1;
188   guint dest_set : 1;
189 };
190
191
192 /* Signals */
193 enum
194 {
195   ROW_ACTIVATED,
196   TEST_EXPAND_ROW,
197   TEST_COLLAPSE_ROW,
198   ROW_EXPANDED,
199   ROW_COLLAPSED,
200   COLUMNS_CHANGED,
201   CURSOR_CHANGED,
202   MOVE_CURSOR,
203   SELECT_ALL,
204   UNSELECT_ALL,
205   SELECT_CURSOR_ROW,
206   TOGGLE_CURSOR_ROW,
207   EXPAND_COLLAPSE_CURSOR_ROW,
208   SELECT_CURSOR_PARENT,
209   START_INTERACTIVE_SEARCH,
210   LAST_SIGNAL
211 };
212
213 /* Properties */
214 enum {
215   PROP_0,
216   PROP_MODEL,
217   PROP_HADJUSTMENT,
218   PROP_VADJUSTMENT,
219   PROP_HSCROLL_POLICY,
220   PROP_VSCROLL_POLICY,
221   PROP_HEADERS_VISIBLE,
222   PROP_HEADERS_CLICKABLE,
223   PROP_EXPANDER_COLUMN,
224   PROP_REORDERABLE,
225   PROP_RULES_HINT,
226   PROP_ENABLE_SEARCH,
227   PROP_SEARCH_COLUMN,
228   PROP_FIXED_HEIGHT_MODE,
229   PROP_HOVER_SELECTION,
230   PROP_HOVER_EXPAND,
231   PROP_SHOW_EXPANDERS,
232   PROP_LEVEL_INDENTATION,
233   PROP_RUBBER_BANDING,
234   PROP_ENABLE_GRID_LINES,
235   PROP_ENABLE_TREE_LINES,
236   PROP_TOOLTIP_COLUMN
237 };
238
239 /* object signals */
240 static void     gtk_tree_view_finalize             (GObject          *object);
241 static void     gtk_tree_view_set_property         (GObject         *object,
242                                                     guint            prop_id,
243                                                     const GValue    *value,
244                                                     GParamSpec      *pspec);
245 static void     gtk_tree_view_get_property         (GObject         *object,
246                                                     guint            prop_id,
247                                                     GValue          *value,
248                                                     GParamSpec      *pspec);
249
250 /* gtkwidget signals */
251 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
252 static void     gtk_tree_view_realize              (GtkWidget        *widget);
253 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
254 static void     gtk_tree_view_map                  (GtkWidget        *widget);
255 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
256                                                     gint             *minimum,
257                                                     gint             *natural);
258 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
259                                                     gint             *minimum,
260                                                     gint             *natural);
261 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
262                                                     GtkRequisition   *requisition);
263 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
264                                                     GtkAllocation    *allocation);
265 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
266                                                     cairo_t          *cr);
267 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
268                                                     GdkEventKey      *event);
269 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
270                                                     GdkEventKey      *event);
271 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
272                                                     GdkEventMotion   *event);
273 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
274                                                     GdkEventCrossing *event);
275 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
276                                                     GdkEventCrossing *event);
277 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
278                                                     GdkEventButton   *event);
279 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
280                                                     GdkEventButton   *event);
281 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
282                                                     GdkEventGrabBroken *event);
283 #if 0
284 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
285                                                     GdkEventConfigure *event);
286 #endif
287
288 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
289                                                     GtkWidget        *child);
290 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
291                                                     GdkEventFocus    *event);
292 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
293                                                     GtkDirectionType  direction);
294 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
295 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
296                                                     GtkStyle         *previous_style);
297 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
298                                                     gboolean          was_grabbed);
299 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
300                                                     GtkStateType      previous_state);
301
302 /* container signals */
303 static void     gtk_tree_view_remove               (GtkContainer     *container,
304                                                     GtkWidget        *widget);
305 static void     gtk_tree_view_forall               (GtkContainer     *container,
306                                                     gboolean          include_internals,
307                                                     GtkCallback       callback,
308                                                     gpointer          callback_data);
309
310 /* Source side drag signals */
311 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
312                                             GdkDragContext   *context);
313 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
314                                             GdkDragContext   *context);
315 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
316                                             GdkDragContext   *context,
317                                             GtkSelectionData *selection_data,
318                                             guint             info,
319                                             guint             time);
320 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
321                                             GdkDragContext   *context);
322
323 /* Target side drag signals */
324 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
325                                                   GdkDragContext   *context,
326                                                   guint             time);
327 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
328                                                   GdkDragContext   *context,
329                                                   gint              x,
330                                                   gint              y,
331                                                   guint             time);
332 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
333                                                   GdkDragContext   *context,
334                                                   gint              x,
335                                                   gint              y,
336                                                   guint             time);
337 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
338                                                   GdkDragContext   *context,
339                                                   gint              x,
340                                                   gint              y,
341                                                   GtkSelectionData *selection_data,
342                                                   guint             info,
343                                                   guint             time);
344
345 /* tree_model signals */
346 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
347                                                            GtkAdjustment   *adjustment);
348 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
349                                                            GtkAdjustment   *adjustment);
350 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
351                                                            GtkMovementStep  step,
352                                                            gint             count);
353 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
354 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
355 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
356                                                            gboolean         start_editing);
357 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
358 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
359                                                                gboolean         logical,
360                                                                gboolean         expand,
361                                                                gboolean         open_all);
362 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
363 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
364                                                            GtkTreePath     *path,
365                                                            GtkTreeIter     *iter,
366                                                            gpointer         data);
367 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
368                                                            GtkTreePath     *path,
369                                                            GtkTreeIter     *iter,
370                                                            gpointer         data);
371 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
372                                                            GtkTreePath     *path,
373                                                            GtkTreeIter     *iter,
374                                                            gpointer         data);
375 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
376                                                            GtkTreePath     *path,
377                                                            gpointer         data);
378 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
379                                                            GtkTreePath     *parent,
380                                                            GtkTreeIter     *iter,
381                                                            gint            *new_order,
382                                                            gpointer         data);
383
384 /* Incremental reflow */
385 static gboolean validate_row             (GtkTreeView *tree_view,
386                                           GtkRBTree   *tree,
387                                           GtkRBNode   *node,
388                                           GtkTreeIter *iter,
389                                           GtkTreePath *path);
390 static void     validate_visible_area    (GtkTreeView *tree_view);
391 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
392 static gboolean do_validate_rows         (GtkTreeView *tree_view,
393                                           gboolean     size_request);
394 static gboolean validate_rows            (GtkTreeView *tree_view);
395 static gboolean presize_handler_callback (gpointer     data);
396 static void     install_presize_handler  (GtkTreeView *tree_view);
397 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
398 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
399                                              GtkTreePath *path,
400                                              gint         offset);
401 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
402 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
403 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
404
405 /* Internal functions */
406 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
407                                                               GtkTreeViewColumn  *column);
408 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
409                                                               guint               keyval,
410                                                               guint               modmask,
411                                                               gboolean            add_shifted_binding,
412                                                               GtkMovementStep     step,
413                                                               gint                count);
414 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
415                                                               GtkRBTree          *tree);
416 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
417                                                               GtkTreePath        *path,
418                                                               const GdkRectangle *clip_rect);
419 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
420                                                               GtkRBTree          *tree,
421                                                               GtkRBNode          *node);
422 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
423                                                               cairo_t            *cr,
424                                                               GtkRBTree          *tree,
425                                                               GtkRBNode          *node,
426                                                               gint                x,
427                                                               gint                y);
428 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
429                                                               GtkRBTree          *tree,
430                                                               gint               *x1,
431                                                               gint               *x2);
432 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
433                                                               gint                i,
434                                                               gint               *x);
435 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
436                                                               GtkTreeView        *tree_view);
437 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
438                                                               GtkRBTree          *tree,
439                                                               GtkTreeIter        *iter,
440                                                               gint                depth,
441                                                               gboolean            recurse);
442 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
443                                                               GtkRBTree          *tree,
444                                                               GtkRBNode          *node);
445 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
446                                                               GtkTreeViewColumn  *column,
447                                                               gboolean            focus_to_cell);
448 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
449                                                               GdkEventMotion     *event);
450 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
451 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
452                                                               gint                count);
453 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
454                                                               gint                count);
455 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
456                                                               gint                count);
457 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
458                                                               gint                count);
459 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
460                                                               GtkTreePath        *path,
461                                                               GtkRBTree          *tree,
462                                                               GtkRBNode          *node,
463                                                               gboolean            animate);
464 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
465                                                               GtkTreePath        *path,
466                                                               GtkRBTree          *tree,
467                                                               GtkRBNode          *node,
468                                                               gboolean            open_all,
469                                                               gboolean            animate);
470 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
471                                                               GtkTreePath        *path,
472                                                               gboolean            clear_and_select,
473                                                               gboolean            clamp_node);
474 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
475 static void     column_sizing_notify                         (GObject            *object,
476                                                               GParamSpec         *pspec,
477                                                               gpointer            data);
478 static gboolean expand_collapse_timeout                      (gpointer            data);
479 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
480                                                               GtkRBTree          *tree,
481                                                               GtkRBNode          *node,
482                                                               gboolean            expand);
483 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
484 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
485 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
486 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
487 static void     update_prelight                              (GtkTreeView        *tree_view,
488                                                               int                 x,
489                                                               int                 y);
490
491 /* interactive search */
492 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
493 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
494                                                          GtkTreeView      *tree_view,
495                                                          GdkDevice        *device);
496 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
497                                                          GtkWidget        *search_dialog,
498                                                          gpointer          user_data);
499 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
500                                                          GtkMenu          *menu,
501                                                          gpointer          data);
502 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
503                                                          GtkTreeView      *tree_view);
504 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
505                                                          GtkTreeView      *tree_view);
506 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
507 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
508                                                          gpointer          data);
509 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
510                                                          GdkEventAny      *event,
511                                                          GtkTreeView      *tree_view);
512 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
513                                                          GdkEventButton   *event,
514                                                          GtkTreeView      *tree_view);
515 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
516                                                          GdkEventScroll   *event,
517                                                          GtkTreeView      *tree_view);
518 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
519                                                          GdkEventKey      *event,
520                                                          GtkTreeView      *tree_view);
521 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
522                                                          GtkTreeView      *tree_view,
523                                                          gboolean          up);
524 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
525                                                          gint              column,
526                                                          const gchar      *key,
527                                                          GtkTreeIter      *iter,
528                                                          gpointer          search_data);
529 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
530                                                          GtkTreeSelection *selection,
531                                                          GtkTreeIter      *iter,
532                                                          const gchar      *text,
533                                                          gint             *count,
534                                                          gint              n);
535 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
536                                                          GtkTreeView      *tree_view);
537 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
538                                                          GtkWidget        *child_widget,
539                                                          gint              x,
540                                                          gint              y,
541                                                          gint              width,
542                                                          gint              height);
543 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
544                                                          GtkTreePath      *cursor_path);
545 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
546                                               GtkTreeViewColumn *column,
547                                               GtkTreePath       *path,
548                                               GtkCellEditable   *cell_editable,
549                                               GdkRectangle      *cell_area,
550                                               GdkEvent          *event,
551                                               guint              flags);
552 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
553                                                          gboolean     cancel_editing);
554 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
555                                                              GdkDevice   *device,
556                                                              gboolean     keybinding);
557 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
558 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
559                                                          GtkTreeViewColumn *column,
560                                                          gint               drop_position);
561
562 /* GtkBuildable */
563 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
564                                                             GtkBuilder        *builder,
565                                                             GObject           *child,
566                                                             const gchar       *type);
567 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
568                                                             GtkBuilder        *builder,
569                                                             const gchar       *childname);
570 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
571
572
573 static gboolean scroll_row_timeout                   (gpointer     data);
574 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
575 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
576
577 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
578
579 \f
580
581 /* GType Methods
582  */
583
584 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
585                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
586                                                 gtk_tree_view_buildable_init)
587                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
588
589 static void
590 gtk_tree_view_class_init (GtkTreeViewClass *class)
591 {
592   GObjectClass *o_class;
593   GtkWidgetClass *widget_class;
594   GtkContainerClass *container_class;
595   GtkBindingSet *binding_set;
596
597   binding_set = gtk_binding_set_by_class (class);
598
599   o_class = (GObjectClass *) class;
600   widget_class = (GtkWidgetClass *) class;
601   container_class = (GtkContainerClass *) class;
602
603   /* GObject signals */
604   o_class->set_property = gtk_tree_view_set_property;
605   o_class->get_property = gtk_tree_view_get_property;
606   o_class->finalize = gtk_tree_view_finalize;
607
608   /* GtkWidget signals */
609   widget_class->destroy = gtk_tree_view_destroy;
610   widget_class->map = gtk_tree_view_map;
611   widget_class->realize = gtk_tree_view_realize;
612   widget_class->unrealize = gtk_tree_view_unrealize;
613   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
614   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
615   widget_class->size_allocate = gtk_tree_view_size_allocate;
616   widget_class->button_press_event = gtk_tree_view_button_press;
617   widget_class->button_release_event = gtk_tree_view_button_release;
618   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
619   /*widget_class->configure_event = gtk_tree_view_configure;*/
620   widget_class->motion_notify_event = gtk_tree_view_motion;
621   widget_class->draw = gtk_tree_view_draw;
622   widget_class->key_press_event = gtk_tree_view_key_press;
623   widget_class->key_release_event = gtk_tree_view_key_release;
624   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
625   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
626   widget_class->focus_out_event = gtk_tree_view_focus_out;
627   widget_class->drag_begin = gtk_tree_view_drag_begin;
628   widget_class->drag_end = gtk_tree_view_drag_end;
629   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
630   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
631   widget_class->drag_leave = gtk_tree_view_drag_leave;
632   widget_class->drag_motion = gtk_tree_view_drag_motion;
633   widget_class->drag_drop = gtk_tree_view_drag_drop;
634   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
635   widget_class->focus = gtk_tree_view_focus;
636   widget_class->grab_focus = gtk_tree_view_grab_focus;
637   widget_class->style_set = gtk_tree_view_style_set;
638   widget_class->grab_notify = gtk_tree_view_grab_notify;
639   widget_class->state_changed = gtk_tree_view_state_changed;
640
641   /* GtkContainer signals */
642   container_class->remove = gtk_tree_view_remove;
643   container_class->forall = gtk_tree_view_forall;
644   container_class->set_focus_child = gtk_tree_view_set_focus_child;
645
646   class->move_cursor = gtk_tree_view_real_move_cursor;
647   class->select_all = gtk_tree_view_real_select_all;
648   class->unselect_all = gtk_tree_view_real_unselect_all;
649   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
650   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
651   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
652   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
653   class->start_interactive_search = gtk_tree_view_start_interactive_search;
654
655   /* Properties */
656
657   g_object_class_install_property (o_class,
658                                    PROP_MODEL,
659                                    g_param_spec_object ("model",
660                                                         P_("TreeView Model"),
661                                                         P_("The model for the tree view"),
662                                                         GTK_TYPE_TREE_MODEL,
663                                                         GTK_PARAM_READWRITE));
664
665   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
666   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
667   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
668   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
669
670   g_object_class_install_property (o_class,
671                                    PROP_HEADERS_VISIBLE,
672                                    g_param_spec_boolean ("headers-visible",
673                                                          P_("Headers Visible"),
674                                                          P_("Show the column header buttons"),
675                                                          TRUE,
676                                                          GTK_PARAM_READWRITE));
677
678   g_object_class_install_property (o_class,
679                                    PROP_HEADERS_CLICKABLE,
680                                    g_param_spec_boolean ("headers-clickable",
681                                                          P_("Headers Clickable"),
682                                                          P_("Column headers respond to click events"),
683                                                          TRUE,
684                                                          GTK_PARAM_READWRITE));
685
686   g_object_class_install_property (o_class,
687                                    PROP_EXPANDER_COLUMN,
688                                    g_param_spec_object ("expander-column",
689                                                         P_("Expander Column"),
690                                                         P_("Set the column for the expander column"),
691                                                         GTK_TYPE_TREE_VIEW_COLUMN,
692                                                         GTK_PARAM_READWRITE));
693
694   g_object_class_install_property (o_class,
695                                    PROP_REORDERABLE,
696                                    g_param_spec_boolean ("reorderable",
697                                                          P_("Reorderable"),
698                                                          P_("View is reorderable"),
699                                                          FALSE,
700                                                          GTK_PARAM_READWRITE));
701
702   g_object_class_install_property (o_class,
703                                    PROP_RULES_HINT,
704                                    g_param_spec_boolean ("rules-hint",
705                                                          P_("Rules Hint"),
706                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
707                                                          FALSE,
708                                                          GTK_PARAM_READWRITE));
709
710     g_object_class_install_property (o_class,
711                                      PROP_ENABLE_SEARCH,
712                                      g_param_spec_boolean ("enable-search",
713                                                            P_("Enable Search"),
714                                                            P_("View allows user to search through columns interactively"),
715                                                            TRUE,
716                                                            GTK_PARAM_READWRITE));
717
718     g_object_class_install_property (o_class,
719                                      PROP_SEARCH_COLUMN,
720                                      g_param_spec_int ("search-column",
721                                                        P_("Search Column"),
722                                                        P_("Model column to search through during interactive search"),
723                                                        -1,
724                                                        G_MAXINT,
725                                                        -1,
726                                                        GTK_PARAM_READWRITE));
727
728     /**
729      * GtkTreeView:fixed-height-mode:
730      *
731      * Setting the ::fixed-height-mode property to %TRUE speeds up 
732      * #GtkTreeView by assuming that all rows have the same height. 
733      * Only enable this option if all rows are the same height.  
734      * Please see gtk_tree_view_set_fixed_height_mode() for more 
735      * information on this option.
736      *
737      * Since: 2.4
738      **/
739     g_object_class_install_property (o_class,
740                                      PROP_FIXED_HEIGHT_MODE,
741                                      g_param_spec_boolean ("fixed-height-mode",
742                                                            P_("Fixed Height Mode"),
743                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
744                                                            FALSE,
745                                                            GTK_PARAM_READWRITE));
746     
747     /**
748      * GtkTreeView:hover-selection:
749      * 
750      * Enables or disables the hover selection mode of @tree_view.
751      * Hover selection makes the selected row follow the pointer.
752      * Currently, this works only for the selection modes 
753      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
754      *
755      * This mode is primarily intended for treeviews in popups, e.g.
756      * in #GtkComboBox or #GtkEntryCompletion.
757      *
758      * Since: 2.6
759      */
760     g_object_class_install_property (o_class,
761                                      PROP_HOVER_SELECTION,
762                                      g_param_spec_boolean ("hover-selection",
763                                                            P_("Hover Selection"),
764                                                            P_("Whether the selection should follow the pointer"),
765                                                            FALSE,
766                                                            GTK_PARAM_READWRITE));
767
768     /**
769      * GtkTreeView:hover-expand:
770      * 
771      * Enables or disables the hover expansion mode of @tree_view.
772      * Hover expansion makes rows expand or collapse if the pointer moves 
773      * over them.
774      *
775      * This mode is primarily intended for treeviews in popups, e.g.
776      * in #GtkComboBox or #GtkEntryCompletion.
777      *
778      * Since: 2.6
779      */
780     g_object_class_install_property (o_class,
781                                      PROP_HOVER_EXPAND,
782                                      g_param_spec_boolean ("hover-expand",
783                                                            P_("Hover Expand"),
784                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
785                                                            FALSE,
786                                                            GTK_PARAM_READWRITE));
787
788     /**
789      * GtkTreeView:show-expanders:
790      *
791      * %TRUE if the view has expanders.
792      *
793      * Since: 2.12
794      */
795     g_object_class_install_property (o_class,
796                                      PROP_SHOW_EXPANDERS,
797                                      g_param_spec_boolean ("show-expanders",
798                                                            P_("Show Expanders"),
799                                                            P_("View has expanders"),
800                                                            TRUE,
801                                                            GTK_PARAM_READWRITE));
802
803     /**
804      * GtkTreeView:level-indentation:
805      *
806      * Extra indentation for each level.
807      *
808      * Since: 2.12
809      */
810     g_object_class_install_property (o_class,
811                                      PROP_LEVEL_INDENTATION,
812                                      g_param_spec_int ("level-indentation",
813                                                        P_("Level Indentation"),
814                                                        P_("Extra indentation for each level"),
815                                                        0,
816                                                        G_MAXINT,
817                                                        0,
818                                                        GTK_PARAM_READWRITE));
819
820     g_object_class_install_property (o_class,
821                                      PROP_RUBBER_BANDING,
822                                      g_param_spec_boolean ("rubber-banding",
823                                                            P_("Rubber Banding"),
824                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
825                                                            FALSE,
826                                                            GTK_PARAM_READWRITE));
827
828     g_object_class_install_property (o_class,
829                                      PROP_ENABLE_GRID_LINES,
830                                      g_param_spec_enum ("enable-grid-lines",
831                                                         P_("Enable Grid Lines"),
832                                                         P_("Whether grid lines should be drawn in the tree view"),
833                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
834                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
835                                                         GTK_PARAM_READWRITE));
836
837     g_object_class_install_property (o_class,
838                                      PROP_ENABLE_TREE_LINES,
839                                      g_param_spec_boolean ("enable-tree-lines",
840                                                            P_("Enable Tree Lines"),
841                                                            P_("Whether tree lines should be drawn in the tree view"),
842                                                            FALSE,
843                                                            GTK_PARAM_READWRITE));
844
845     g_object_class_install_property (o_class,
846                                      PROP_TOOLTIP_COLUMN,
847                                      g_param_spec_int ("tooltip-column",
848                                                        P_("Tooltip Column"),
849                                                        P_("The column in the model containing the tooltip texts for the rows"),
850                                                        -1,
851                                                        G_MAXINT,
852                                                        -1,
853                                                        GTK_PARAM_READWRITE));
854
855   /* Style properties */
856 #define _TREE_VIEW_EXPANDER_SIZE 12
857 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
858 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
859
860   gtk_widget_class_install_style_property (widget_class,
861                                            g_param_spec_int ("expander-size",
862                                                              P_("Expander Size"),
863                                                              P_("Size of the expander arrow"),
864                                                              0,
865                                                              G_MAXINT,
866                                                              _TREE_VIEW_EXPANDER_SIZE,
867                                                              GTK_PARAM_READABLE));
868
869   gtk_widget_class_install_style_property (widget_class,
870                                            g_param_spec_int ("vertical-separator",
871                                                              P_("Vertical Separator Width"),
872                                                              P_("Vertical space between cells.  Must be an even number"),
873                                                              0,
874                                                              G_MAXINT,
875                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
876                                                              GTK_PARAM_READABLE));
877
878   gtk_widget_class_install_style_property (widget_class,
879                                            g_param_spec_int ("horizontal-separator",
880                                                              P_("Horizontal Separator Width"),
881                                                              P_("Horizontal space between cells.  Must be an even number"),
882                                                              0,
883                                                              G_MAXINT,
884                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
885                                                              GTK_PARAM_READABLE));
886
887   gtk_widget_class_install_style_property (widget_class,
888                                            g_param_spec_boolean ("allow-rules",
889                                                                  P_("Allow Rules"),
890                                                                  P_("Allow drawing of alternating color rows"),
891                                                                  TRUE,
892                                                                  GTK_PARAM_READABLE));
893
894   gtk_widget_class_install_style_property (widget_class,
895                                            g_param_spec_boolean ("indent-expanders",
896                                                                  P_("Indent Expanders"),
897                                                                  P_("Make the expanders indented"),
898                                                                  TRUE,
899                                                                  GTK_PARAM_READABLE));
900
901   gtk_widget_class_install_style_property (widget_class,
902                                            g_param_spec_boxed ("even-row-color",
903                                                                P_("Even Row Color"),
904                                                                P_("Color to use for even rows"),
905                                                                GDK_TYPE_COLOR,
906                                                                GTK_PARAM_READABLE));
907
908   gtk_widget_class_install_style_property (widget_class,
909                                            g_param_spec_boxed ("odd-row-color",
910                                                                P_("Odd Row Color"),
911                                                                P_("Color to use for odd rows"),
912                                                                GDK_TYPE_COLOR,
913                                                                GTK_PARAM_READABLE));
914
915   gtk_widget_class_install_style_property (widget_class,
916                                            g_param_spec_int ("grid-line-width",
917                                                              P_("Grid line width"),
918                                                              P_("Width, in pixels, of the tree view grid lines"),
919                                                              0, G_MAXINT, 1,
920                                                              GTK_PARAM_READABLE));
921
922   gtk_widget_class_install_style_property (widget_class,
923                                            g_param_spec_int ("tree-line-width",
924                                                              P_("Tree line width"),
925                                                              P_("Width, in pixels, of the tree view lines"),
926                                                              0, G_MAXINT, 1,
927                                                              GTK_PARAM_READABLE));
928
929   gtk_widget_class_install_style_property (widget_class,
930                                            g_param_spec_string ("grid-line-pattern",
931                                                                 P_("Grid line pattern"),
932                                                                 P_("Dash pattern used to draw the tree view grid lines"),
933                                                                 "\1\1",
934                                                                 GTK_PARAM_READABLE));
935
936   gtk_widget_class_install_style_property (widget_class,
937                                            g_param_spec_string ("tree-line-pattern",
938                                                                 P_("Tree line pattern"),
939                                                                 P_("Dash pattern used to draw the tree view lines"),
940                                                                 "\1\1",
941                                                                 GTK_PARAM_READABLE));
942
943   /* Signals */
944   /**
945    * GtkTreeView::row-activated:
946    * @tree_view: the object on which the signal is emitted
947    * @path: the #GtkTreePath for the activated row
948    * @column: the #GtkTreeViewColumn in which the activation occurred
949    *
950    * The "row-activated" signal is emitted when the method
951    * gtk_tree_view_row_activated() is called or the user double clicks 
952    * a treeview row. It is also emitted when a non-editable row is 
953    * selected and one of the keys: Space, Shift+Space, Return or 
954    * Enter is pressed.
955    * 
956    * For selection handling refer to the <link linkend="TreeWidget">tree 
957    * widget conceptual overview</link> as well as #GtkTreeSelection.
958    */
959   tree_view_signals[ROW_ACTIVATED] =
960     g_signal_new (I_("row-activated"),
961                   G_TYPE_FROM_CLASS (o_class),
962                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
963                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
964                   NULL, NULL,
965                   _gtk_marshal_VOID__BOXED_OBJECT,
966                   G_TYPE_NONE, 2,
967                   GTK_TYPE_TREE_PATH,
968                   GTK_TYPE_TREE_VIEW_COLUMN);
969
970   /**
971    * GtkTreeView::test-expand-row:
972    * @tree_view: the object on which the signal is emitted
973    * @iter: the tree iter of the row to expand
974    * @path: a tree path that points to the row 
975    * 
976    * The given row is about to be expanded (show its children nodes). Use this
977    * signal if you need to control the expandability of individual rows.
978    *
979    * Returns: %FALSE to allow expansion, %TRUE to reject
980    */
981   tree_view_signals[TEST_EXPAND_ROW] =
982     g_signal_new (I_("test-expand-row"),
983                   G_TYPE_FROM_CLASS (o_class),
984                   G_SIGNAL_RUN_LAST,
985                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
986                   _gtk_boolean_handled_accumulator, NULL,
987                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
988                   G_TYPE_BOOLEAN, 2,
989                   GTK_TYPE_TREE_ITER,
990                   GTK_TYPE_TREE_PATH);
991
992   /**
993    * GtkTreeView::test-collapse-row:
994    * @tree_view: the object on which the signal is emitted
995    * @iter: the tree iter of the row to collapse
996    * @path: a tree path that points to the row 
997    * 
998    * The given row is about to be collapsed (hide its children nodes). Use this
999    * signal if you need to control the collapsibility of individual rows.
1000    *
1001    * Returns: %FALSE to allow collapsing, %TRUE to reject
1002    */
1003   tree_view_signals[TEST_COLLAPSE_ROW] =
1004     g_signal_new (I_("test-collapse-row"),
1005                   G_TYPE_FROM_CLASS (o_class),
1006                   G_SIGNAL_RUN_LAST,
1007                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1008                   _gtk_boolean_handled_accumulator, NULL,
1009                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1010                   G_TYPE_BOOLEAN, 2,
1011                   GTK_TYPE_TREE_ITER,
1012                   GTK_TYPE_TREE_PATH);
1013
1014   /**
1015    * GtkTreeView::row-expanded:
1016    * @tree_view: the object on which the signal is emitted
1017    * @iter: the tree iter of the expanded row
1018    * @path: a tree path that points to the row 
1019    * 
1020    * The given row has been expanded (child nodes are shown).
1021    */
1022   tree_view_signals[ROW_EXPANDED] =
1023     g_signal_new (I_("row-expanded"),
1024                   G_TYPE_FROM_CLASS (o_class),
1025                   G_SIGNAL_RUN_LAST,
1026                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1027                   NULL, NULL,
1028                   _gtk_marshal_VOID__BOXED_BOXED,
1029                   G_TYPE_NONE, 2,
1030                   GTK_TYPE_TREE_ITER,
1031                   GTK_TYPE_TREE_PATH);
1032
1033   /**
1034    * GtkTreeView::row-collapsed:
1035    * @tree_view: the object on which the signal is emitted
1036    * @iter: the tree iter of the collapsed row
1037    * @path: a tree path that points to the row 
1038    * 
1039    * The given row has been collapsed (child nodes are hidden).
1040    */
1041   tree_view_signals[ROW_COLLAPSED] =
1042     g_signal_new (I_("row-collapsed"),
1043                   G_TYPE_FROM_CLASS (o_class),
1044                   G_SIGNAL_RUN_LAST,
1045                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1046                   NULL, NULL,
1047                   _gtk_marshal_VOID__BOXED_BOXED,
1048                   G_TYPE_NONE, 2,
1049                   GTK_TYPE_TREE_ITER,
1050                   GTK_TYPE_TREE_PATH);
1051
1052   /**
1053    * GtkTreeView::columns-changed:
1054    * @tree_view: the object on which the signal is emitted 
1055    * 
1056    * The number of columns of the treeview has changed.
1057    */
1058   tree_view_signals[COLUMNS_CHANGED] =
1059     g_signal_new (I_("columns-changed"),
1060                   G_TYPE_FROM_CLASS (o_class),
1061                   G_SIGNAL_RUN_LAST,
1062                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1063                   NULL, NULL,
1064                   _gtk_marshal_VOID__VOID,
1065                   G_TYPE_NONE, 0);
1066
1067   /**
1068    * GtkTreeView::cursor-changed:
1069    * @tree_view: the object on which the signal is emitted
1070    * 
1071    * The position of the cursor (focused cell) has changed.
1072    */
1073   tree_view_signals[CURSOR_CHANGED] =
1074     g_signal_new (I_("cursor-changed"),
1075                   G_TYPE_FROM_CLASS (o_class),
1076                   G_SIGNAL_RUN_LAST,
1077                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1078                   NULL, NULL,
1079                   _gtk_marshal_VOID__VOID,
1080                   G_TYPE_NONE, 0);
1081
1082   tree_view_signals[MOVE_CURSOR] =
1083     g_signal_new (I_("move-cursor"),
1084                   G_TYPE_FROM_CLASS (o_class),
1085                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1086                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1087                   NULL, NULL,
1088                   _gtk_marshal_BOOLEAN__ENUM_INT,
1089                   G_TYPE_BOOLEAN, 2,
1090                   GTK_TYPE_MOVEMENT_STEP,
1091                   G_TYPE_INT);
1092
1093   tree_view_signals[SELECT_ALL] =
1094     g_signal_new (I_("select-all"),
1095                   G_TYPE_FROM_CLASS (o_class),
1096                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1097                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1098                   NULL, NULL,
1099                   _gtk_marshal_BOOLEAN__VOID,
1100                   G_TYPE_BOOLEAN, 0);
1101
1102   tree_view_signals[UNSELECT_ALL] =
1103     g_signal_new (I_("unselect-all"),
1104                   G_TYPE_FROM_CLASS (o_class),
1105                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1106                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1107                   NULL, NULL,
1108                   _gtk_marshal_BOOLEAN__VOID,
1109                   G_TYPE_BOOLEAN, 0);
1110
1111   tree_view_signals[SELECT_CURSOR_ROW] =
1112     g_signal_new (I_("select-cursor-row"),
1113                   G_TYPE_FROM_CLASS (o_class),
1114                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1115                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1116                   NULL, NULL,
1117                   _gtk_marshal_BOOLEAN__BOOLEAN,
1118                   G_TYPE_BOOLEAN, 1,
1119                   G_TYPE_BOOLEAN);
1120
1121   tree_view_signals[TOGGLE_CURSOR_ROW] =
1122     g_signal_new (I_("toggle-cursor-row"),
1123                   G_TYPE_FROM_CLASS (o_class),
1124                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1125                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1126                   NULL, NULL,
1127                   _gtk_marshal_BOOLEAN__VOID,
1128                   G_TYPE_BOOLEAN, 0);
1129
1130   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1131     g_signal_new (I_("expand-collapse-cursor-row"),
1132                   G_TYPE_FROM_CLASS (o_class),
1133                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1134                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1135                   NULL, NULL,
1136                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1137                   G_TYPE_BOOLEAN, 3,
1138                   G_TYPE_BOOLEAN,
1139                   G_TYPE_BOOLEAN,
1140                   G_TYPE_BOOLEAN);
1141
1142   tree_view_signals[SELECT_CURSOR_PARENT] =
1143     g_signal_new (I_("select-cursor-parent"),
1144                   G_TYPE_FROM_CLASS (o_class),
1145                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1146                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1147                   NULL, NULL,
1148                   _gtk_marshal_BOOLEAN__VOID,
1149                   G_TYPE_BOOLEAN, 0);
1150
1151   tree_view_signals[START_INTERACTIVE_SEARCH] =
1152     g_signal_new (I_("start-interactive-search"),
1153                   G_TYPE_FROM_CLASS (o_class),
1154                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1155                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1156                   NULL, NULL,
1157                   _gtk_marshal_BOOLEAN__VOID,
1158                   G_TYPE_BOOLEAN, 0);
1159
1160   /* Key bindings */
1161   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1162                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1163   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1164                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1165
1166   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1167                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1168   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1169                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1170
1171   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1172                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1173
1174   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1175                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1176
1177   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1178                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1179   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1180                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1181
1182   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1183                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1184   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1185                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1186
1187   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1188                                   GTK_MOVEMENT_PAGES, -1);
1189   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1190                                   GTK_MOVEMENT_PAGES, -1);
1191
1192   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1193                                   GTK_MOVEMENT_PAGES, 1);
1194   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1195                                   GTK_MOVEMENT_PAGES, 1);
1196
1197
1198   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1199                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1200                                 G_TYPE_INT, 1);
1201
1202   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1203                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1204                                 G_TYPE_INT, -1);
1205
1206   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1207                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1208                                 G_TYPE_INT, 1);
1209
1210   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1211                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1212                                 G_TYPE_INT, -1);
1213
1214   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1215                                 "move-cursor", 2,
1216                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1217                                 G_TYPE_INT, 1);
1218
1219   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1220                                 "move-cursor", 2,
1221                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1222                                 G_TYPE_INT, -1);
1223
1224   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1225                                 "move-cursor", 2,
1226                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1227                                 G_TYPE_INT, 1);
1228
1229   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1230                                 "move-cursor", 2,
1231                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1232                                 G_TYPE_INT, -1);
1233
1234   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1235   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1236
1237   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1238   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1239
1240   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1241   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1242
1243   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1244                                 G_TYPE_BOOLEAN, TRUE);
1245   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1246                                 G_TYPE_BOOLEAN, TRUE);
1247
1248   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1249                                 G_TYPE_BOOLEAN, TRUE);
1250   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1251                                 G_TYPE_BOOLEAN, TRUE);
1252   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1253                                 G_TYPE_BOOLEAN, TRUE);
1254   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1255                                 G_TYPE_BOOLEAN, TRUE);
1256   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1257                                 G_TYPE_BOOLEAN, TRUE);
1258
1259   /* expand and collapse rows */
1260   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1261                                 G_TYPE_BOOLEAN, TRUE,
1262                                 G_TYPE_BOOLEAN, TRUE,
1263                                 G_TYPE_BOOLEAN, FALSE);
1264
1265   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1266                                 "expand-collapse-cursor-row", 3,
1267                                 G_TYPE_BOOLEAN, TRUE,
1268                                 G_TYPE_BOOLEAN, TRUE,
1269                                 G_TYPE_BOOLEAN, TRUE);
1270   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1271                                 "expand-collapse-cursor-row", 3,
1272                                 G_TYPE_BOOLEAN, TRUE,
1273                                 G_TYPE_BOOLEAN, TRUE,
1274                                 G_TYPE_BOOLEAN, TRUE);
1275
1276   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1277                                 "expand-collapse-cursor-row", 3,
1278                                 G_TYPE_BOOLEAN, TRUE,
1279                                 G_TYPE_BOOLEAN, FALSE,
1280                                 G_TYPE_BOOLEAN, FALSE);
1281   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1282                                 "expand-collapse-cursor-row", 3,
1283                                 G_TYPE_BOOLEAN, TRUE,
1284                                 G_TYPE_BOOLEAN, FALSE,
1285                                 G_TYPE_BOOLEAN, FALSE);
1286
1287   /* Not doable on US keyboards */
1288   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1289                                 G_TYPE_BOOLEAN, TRUE,
1290                                 G_TYPE_BOOLEAN, TRUE,
1291                                 G_TYPE_BOOLEAN, TRUE);
1292   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1293                                 G_TYPE_BOOLEAN, TRUE,
1294                                 G_TYPE_BOOLEAN, TRUE,
1295                                 G_TYPE_BOOLEAN, FALSE);
1296   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1297                                 G_TYPE_BOOLEAN, TRUE,
1298                                 G_TYPE_BOOLEAN, TRUE,
1299                                 G_TYPE_BOOLEAN, TRUE);
1300   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1301                                 G_TYPE_BOOLEAN, TRUE,
1302                                 G_TYPE_BOOLEAN, TRUE,
1303                                 G_TYPE_BOOLEAN, TRUE);
1304   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1305                                 "expand-collapse-cursor-row", 3,
1306                                 G_TYPE_BOOLEAN, FALSE,
1307                                 G_TYPE_BOOLEAN, TRUE,
1308                                 G_TYPE_BOOLEAN, TRUE);
1309   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1310                                 "expand-collapse-cursor-row", 3,
1311                                 G_TYPE_BOOLEAN, FALSE,
1312                                 G_TYPE_BOOLEAN, TRUE,
1313                                 G_TYPE_BOOLEAN, TRUE);
1314   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1315                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1316                                 "expand-collapse-cursor-row", 3,
1317                                 G_TYPE_BOOLEAN, FALSE,
1318                                 G_TYPE_BOOLEAN, TRUE,
1319                                 G_TYPE_BOOLEAN, TRUE);
1320   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1321                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1322                                 "expand-collapse-cursor-row", 3,
1323                                 G_TYPE_BOOLEAN, FALSE,
1324                                 G_TYPE_BOOLEAN, TRUE,
1325                                 G_TYPE_BOOLEAN, TRUE);
1326
1327   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1328                                 G_TYPE_BOOLEAN, TRUE,
1329                                 G_TYPE_BOOLEAN, FALSE,
1330                                 G_TYPE_BOOLEAN, FALSE);
1331   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1332                                 G_TYPE_BOOLEAN, TRUE,
1333                                 G_TYPE_BOOLEAN, FALSE,
1334                                 G_TYPE_BOOLEAN, TRUE);
1335   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1336                                 G_TYPE_BOOLEAN, TRUE,
1337                                 G_TYPE_BOOLEAN, FALSE,
1338                                 G_TYPE_BOOLEAN, FALSE);
1339   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1340                                 G_TYPE_BOOLEAN, TRUE,
1341                                 G_TYPE_BOOLEAN, FALSE,
1342                                 G_TYPE_BOOLEAN, TRUE);
1343   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1344                                 "expand-collapse-cursor-row", 3,
1345                                 G_TYPE_BOOLEAN, FALSE,
1346                                 G_TYPE_BOOLEAN, FALSE,
1347                                 G_TYPE_BOOLEAN, TRUE);
1348   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1349                                 "expand-collapse-cursor-row", 3,
1350                                 G_TYPE_BOOLEAN, FALSE,
1351                                 G_TYPE_BOOLEAN, FALSE,
1352                                 G_TYPE_BOOLEAN, TRUE);
1353   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1354                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1355                                 "expand-collapse-cursor-row", 3,
1356                                 G_TYPE_BOOLEAN, FALSE,
1357                                 G_TYPE_BOOLEAN, FALSE,
1358                                 G_TYPE_BOOLEAN, TRUE);
1359   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1360                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1361                                 "expand-collapse-cursor-row", 3,
1362                                 G_TYPE_BOOLEAN, FALSE,
1363                                 G_TYPE_BOOLEAN, FALSE,
1364                                 G_TYPE_BOOLEAN, TRUE);
1365
1366   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1367   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1368
1369   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1370
1371   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1372
1373   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1374 }
1375
1376 static void
1377 gtk_tree_view_init (GtkTreeView *tree_view)
1378 {
1379   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1380
1381   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1382   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1383
1384   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1385                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1386                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1387
1388   /* We need some padding */
1389   tree_view->priv->dy = 0;
1390   tree_view->priv->cursor_offset = 0;
1391   tree_view->priv->n_columns = 0;
1392   tree_view->priv->header_height = 1;
1393   tree_view->priv->x_drag = 0;
1394   tree_view->priv->drag_pos = -1;
1395   tree_view->priv->header_has_focus = FALSE;
1396   tree_view->priv->pressed_button = -1;
1397   tree_view->priv->press_start_x = -1;
1398   tree_view->priv->press_start_y = -1;
1399   tree_view->priv->reorderable = FALSE;
1400   tree_view->priv->presize_handler_timer = 0;
1401   tree_view->priv->scroll_sync_timer = 0;
1402   tree_view->priv->fixed_height = -1;
1403   tree_view->priv->fixed_height_mode = FALSE;
1404   tree_view->priv->fixed_height_check = 0;
1405   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1406   tree_view->priv->enable_search = TRUE;
1407   tree_view->priv->search_column = -1;
1408   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1409   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1410   tree_view->priv->search_custom_entry_set = FALSE;
1411   tree_view->priv->typeselect_flush_timeout = 0;
1412   tree_view->priv->init_hadjust_value = TRUE;    
1413   tree_view->priv->width = 0;
1414           
1415   tree_view->priv->hover_selection = FALSE;
1416   tree_view->priv->hover_expand = FALSE;
1417
1418   tree_view->priv->level_indentation = 0;
1419
1420   tree_view->priv->rubber_banding_enable = FALSE;
1421
1422   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1423   tree_view->priv->tree_lines_enabled = FALSE;
1424
1425   tree_view->priv->tooltip_column = -1;
1426
1427   tree_view->priv->post_validation_flag = FALSE;
1428
1429   tree_view->priv->last_button_x = -1;
1430   tree_view->priv->last_button_y = -1;
1431
1432   tree_view->priv->event_last_x = -10000;
1433   tree_view->priv->event_last_y = -10000;
1434
1435   gtk_tree_view_set_vadjustment (tree_view, NULL);
1436   gtk_tree_view_set_hadjustment (tree_view, NULL);
1437 }
1438
1439 \f
1440
1441 /* GObject Methods
1442  */
1443
1444 static void
1445 gtk_tree_view_set_property (GObject         *object,
1446                             guint            prop_id,
1447                             const GValue    *value,
1448                             GParamSpec      *pspec)
1449 {
1450   GtkTreeView *tree_view;
1451
1452   tree_view = GTK_TREE_VIEW (object);
1453
1454   switch (prop_id)
1455     {
1456     case PROP_MODEL:
1457       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1458       break;
1459     case PROP_HADJUSTMENT:
1460       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1461       break;
1462     case PROP_VADJUSTMENT:
1463       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1464       break;
1465     case PROP_HSCROLL_POLICY:
1466       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1467       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1468       break;
1469     case PROP_VSCROLL_POLICY:
1470       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1471       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1472       break;
1473     case PROP_HEADERS_VISIBLE:
1474       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1475       break;
1476     case PROP_HEADERS_CLICKABLE:
1477       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1478       break;
1479     case PROP_EXPANDER_COLUMN:
1480       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1481       break;
1482     case PROP_REORDERABLE:
1483       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1484       break;
1485     case PROP_RULES_HINT:
1486       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1487       break;
1488     case PROP_ENABLE_SEARCH:
1489       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1490       break;
1491     case PROP_SEARCH_COLUMN:
1492       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1493       break;
1494     case PROP_FIXED_HEIGHT_MODE:
1495       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1496       break;
1497     case PROP_HOVER_SELECTION:
1498       tree_view->priv->hover_selection = g_value_get_boolean (value);
1499       break;
1500     case PROP_HOVER_EXPAND:
1501       tree_view->priv->hover_expand = g_value_get_boolean (value);
1502       break;
1503     case PROP_SHOW_EXPANDERS:
1504       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1505       break;
1506     case PROP_LEVEL_INDENTATION:
1507       tree_view->priv->level_indentation = g_value_get_int (value);
1508       break;
1509     case PROP_RUBBER_BANDING:
1510       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1511       break;
1512     case PROP_ENABLE_GRID_LINES:
1513       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1514       break;
1515     case PROP_ENABLE_TREE_LINES:
1516       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1517       break;
1518     case PROP_TOOLTIP_COLUMN:
1519       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1520       break;
1521     default:
1522       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1523       break;
1524     }
1525 }
1526
1527 static void
1528 gtk_tree_view_get_property (GObject    *object,
1529                             guint       prop_id,
1530                             GValue     *value,
1531                             GParamSpec *pspec)
1532 {
1533   GtkTreeView *tree_view;
1534
1535   tree_view = GTK_TREE_VIEW (object);
1536
1537   switch (prop_id)
1538     {
1539     case PROP_MODEL:
1540       g_value_set_object (value, tree_view->priv->model);
1541       break;
1542     case PROP_HADJUSTMENT:
1543       g_value_set_object (value, tree_view->priv->hadjustment);
1544       break;
1545     case PROP_VADJUSTMENT:
1546       g_value_set_object (value, tree_view->priv->vadjustment);
1547       break;
1548     case PROP_HSCROLL_POLICY:
1549       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1550       break;
1551     case PROP_VSCROLL_POLICY:
1552       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1553       break;
1554     case PROP_HEADERS_VISIBLE:
1555       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1556       break;
1557     case PROP_HEADERS_CLICKABLE:
1558       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1559       break;
1560     case PROP_EXPANDER_COLUMN:
1561       g_value_set_object (value, tree_view->priv->expander_column);
1562       break;
1563     case PROP_REORDERABLE:
1564       g_value_set_boolean (value, tree_view->priv->reorderable);
1565       break;
1566     case PROP_RULES_HINT:
1567       g_value_set_boolean (value, tree_view->priv->has_rules);
1568       break;
1569     case PROP_ENABLE_SEARCH:
1570       g_value_set_boolean (value, tree_view->priv->enable_search);
1571       break;
1572     case PROP_SEARCH_COLUMN:
1573       g_value_set_int (value, tree_view->priv->search_column);
1574       break;
1575     case PROP_FIXED_HEIGHT_MODE:
1576       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1577       break;
1578     case PROP_HOVER_SELECTION:
1579       g_value_set_boolean (value, tree_view->priv->hover_selection);
1580       break;
1581     case PROP_HOVER_EXPAND:
1582       g_value_set_boolean (value, tree_view->priv->hover_expand);
1583       break;
1584     case PROP_SHOW_EXPANDERS:
1585       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1586       break;
1587     case PROP_LEVEL_INDENTATION:
1588       g_value_set_int (value, tree_view->priv->level_indentation);
1589       break;
1590     case PROP_RUBBER_BANDING:
1591       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1592       break;
1593     case PROP_ENABLE_GRID_LINES:
1594       g_value_set_enum (value, tree_view->priv->grid_lines);
1595       break;
1596     case PROP_ENABLE_TREE_LINES:
1597       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1598       break;
1599     case PROP_TOOLTIP_COLUMN:
1600       g_value_set_int (value, tree_view->priv->tooltip_column);
1601       break;
1602     default:
1603       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1604       break;
1605     }
1606 }
1607
1608 static void
1609 gtk_tree_view_finalize (GObject *object)
1610 {
1611   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1612 }
1613
1614
1615 static GtkBuildableIface *parent_buildable_iface;
1616
1617 static void
1618 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1619 {
1620   parent_buildable_iface = g_type_interface_peek_parent (iface);
1621   iface->add_child = gtk_tree_view_buildable_add_child;
1622   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1623 }
1624
1625 static void
1626 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1627                                    GtkBuilder  *builder,
1628                                    GObject     *child,
1629                                    const gchar *type)
1630 {
1631   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1632 }
1633
1634 static GObject *
1635 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1636                                             GtkBuilder        *builder,
1637                                             const gchar       *childname)
1638 {
1639     if (strcmp (childname, "selection") == 0)
1640       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1641     
1642     return parent_buildable_iface->get_internal_child (buildable,
1643                                                        builder,
1644                                                        childname);
1645 }
1646
1647 /* GtkWidget Methods
1648  */
1649
1650 static void
1651 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1652 {
1653   _gtk_rbtree_free (tree_view->priv->tree);
1654   
1655   tree_view->priv->tree = NULL;
1656   tree_view->priv->button_pressed_node = NULL;
1657   tree_view->priv->button_pressed_tree = NULL;
1658   tree_view->priv->prelight_tree = NULL;
1659   tree_view->priv->prelight_node = NULL;
1660   tree_view->priv->expanded_collapsed_node = NULL;
1661   tree_view->priv->expanded_collapsed_tree = NULL;
1662 }
1663
1664 static void
1665 gtk_tree_view_destroy (GtkWidget *widget)
1666 {
1667   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1668   GList *list;
1669
1670   gtk_tree_view_stop_editing (tree_view, TRUE);
1671
1672   if (tree_view->priv->columns != NULL)
1673     {
1674       list = tree_view->priv->columns;
1675       while (list)
1676         {
1677           GtkTreeViewColumn *column;
1678           column = GTK_TREE_VIEW_COLUMN (list->data);
1679           list = list->next;
1680           gtk_tree_view_remove_column (tree_view, column);
1681         }
1682       tree_view->priv->columns = NULL;
1683     }
1684
1685   if (tree_view->priv->tree != NULL)
1686     {
1687       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1688
1689       gtk_tree_view_free_rbtree (tree_view);
1690     }
1691
1692   if (tree_view->priv->selection != NULL)
1693     {
1694       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1695       g_object_unref (tree_view->priv->selection);
1696       tree_view->priv->selection = NULL;
1697     }
1698
1699   if (tree_view->priv->scroll_to_path != NULL)
1700     {
1701       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1702       tree_view->priv->scroll_to_path = NULL;
1703     }
1704
1705   if (tree_view->priv->drag_dest_row != NULL)
1706     {
1707       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1708       tree_view->priv->drag_dest_row = NULL;
1709     }
1710
1711   if (tree_view->priv->top_row != NULL)
1712     {
1713       gtk_tree_row_reference_free (tree_view->priv->top_row);
1714       tree_view->priv->top_row = NULL;
1715     }
1716
1717   if (tree_view->priv->column_drop_func_data &&
1718       tree_view->priv->column_drop_func_data_destroy)
1719     {
1720       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1721       tree_view->priv->column_drop_func_data = NULL;
1722     }
1723
1724   if (tree_view->priv->destroy_count_destroy &&
1725       tree_view->priv->destroy_count_data)
1726     {
1727       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1728       tree_view->priv->destroy_count_data = NULL;
1729     }
1730
1731   gtk_tree_row_reference_free (tree_view->priv->cursor);
1732   tree_view->priv->cursor = NULL;
1733
1734   gtk_tree_row_reference_free (tree_view->priv->anchor);
1735   tree_view->priv->anchor = NULL;
1736
1737   /* destroy interactive search dialog */
1738   if (tree_view->priv->search_window)
1739     {
1740       gtk_widget_destroy (tree_view->priv->search_window);
1741       tree_view->priv->search_window = NULL;
1742       tree_view->priv->search_entry = NULL;
1743       if (tree_view->priv->typeselect_flush_timeout)
1744         {
1745           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1746           tree_view->priv->typeselect_flush_timeout = 0;
1747         }
1748     }
1749
1750   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1751     {
1752       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1753       tree_view->priv->search_user_data = NULL;
1754     }
1755
1756   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1757     {
1758       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1759       tree_view->priv->search_position_user_data = NULL;
1760     }
1761
1762   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1763     {
1764       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1765       tree_view->priv->row_separator_data = NULL;
1766     }
1767   
1768   gtk_tree_view_set_model (tree_view, NULL);
1769
1770   if (tree_view->priv->hadjustment)
1771     {
1772       g_object_unref (tree_view->priv->hadjustment);
1773       tree_view->priv->hadjustment = NULL;
1774     }
1775   if (tree_view->priv->vadjustment)
1776     {
1777       g_object_unref (tree_view->priv->vadjustment);
1778       tree_view->priv->vadjustment = NULL;
1779     }
1780
1781   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
1782 }
1783
1784 /* GtkWidget::map helper */
1785 static void
1786 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1787 {
1788   GList *list;
1789
1790   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
1791
1792   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1793     {
1794       GtkTreeViewColumn *column;
1795
1796       for (list = tree_view->priv->columns; list; list = list->next)
1797         {
1798           column = list->data;
1799           if (gtk_widget_get_visible (column->button) &&
1800               !gtk_widget_get_mapped (column->button))
1801             gtk_widget_map (column->button);
1802         }
1803       for (list = tree_view->priv->columns; list; list = list->next)
1804         {
1805           column = list->data;
1806           if (column->visible == FALSE)
1807             continue;
1808           if (column->resizable)
1809             {
1810               gdk_window_raise (column->window);
1811               gdk_window_show (column->window);
1812             }
1813           else
1814             gdk_window_hide (column->window);
1815         }
1816       gdk_window_show (tree_view->priv->header_window);
1817     }
1818 }
1819
1820 static void
1821 gtk_tree_view_map (GtkWidget *widget)
1822 {
1823   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1824   GList *tmp_list;
1825
1826   gtk_widget_set_mapped (widget, TRUE);
1827
1828   tmp_list = tree_view->priv->children;
1829   while (tmp_list)
1830     {
1831       GtkTreeViewChild *child = tmp_list->data;
1832       tmp_list = tmp_list->next;
1833
1834       if (gtk_widget_get_visible (child->widget))
1835         {
1836           if (!gtk_widget_get_mapped (child->widget))
1837             gtk_widget_map (child->widget);
1838         }
1839     }
1840   gdk_window_show (tree_view->priv->bin_window);
1841
1842   gtk_tree_view_map_buttons (tree_view);
1843
1844   gdk_window_show (gtk_widget_get_window (widget));
1845 }
1846
1847 static void
1848 gtk_tree_view_realize (GtkWidget *widget)
1849 {
1850   GtkAllocation allocation;
1851   GtkStyle *style;
1852   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1853   GdkWindow *window;
1854   GdkWindowAttr attributes;
1855   GList *tmp_list;
1856   gint attributes_mask;
1857
1858   gtk_widget_set_realized (widget, TRUE);
1859
1860   gtk_widget_get_allocation (widget, &allocation);
1861
1862   /* Make the main, clipping window */
1863   attributes.window_type = GDK_WINDOW_CHILD;
1864   attributes.x = allocation.x;
1865   attributes.y = allocation.y;
1866   attributes.width = allocation.width;
1867   attributes.height = allocation.height;
1868   attributes.wclass = GDK_INPUT_OUTPUT;
1869   attributes.visual = gtk_widget_get_visual (widget);
1870   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1871
1872   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1873
1874   window = gdk_window_new (gtk_widget_get_parent_window (widget),
1875                            &attributes, attributes_mask);
1876   gtk_widget_set_window (widget, window);
1877   gdk_window_set_user_data (window, widget);
1878
1879   gtk_widget_get_allocation (widget, &allocation);
1880
1881   /* Make the window for the tree */
1882   attributes.x = 0;
1883   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1884   attributes.width = MAX (tree_view->priv->width, allocation.width);
1885   attributes.height = allocation.height;
1886   attributes.event_mask = (GDK_EXPOSURE_MASK |
1887                            GDK_SCROLL_MASK |
1888                            GDK_POINTER_MOTION_MASK |
1889                            GDK_ENTER_NOTIFY_MASK |
1890                            GDK_LEAVE_NOTIFY_MASK |
1891                            GDK_BUTTON_PRESS_MASK |
1892                            GDK_BUTTON_RELEASE_MASK |
1893                            gtk_widget_get_events (widget));
1894
1895   tree_view->priv->bin_window = gdk_window_new (window,
1896                                                 &attributes, attributes_mask);
1897   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1898
1899   gtk_widget_get_allocation (widget, &allocation);
1900
1901   /* Make the column header window */
1902   attributes.x = 0;
1903   attributes.y = 0;
1904   attributes.width = MAX (tree_view->priv->width, allocation.width);
1905   attributes.height = tree_view->priv->header_height;
1906   attributes.event_mask = (GDK_EXPOSURE_MASK |
1907                            GDK_SCROLL_MASK |
1908                            GDK_ENTER_NOTIFY_MASK |
1909                            GDK_LEAVE_NOTIFY_MASK |
1910                            GDK_BUTTON_PRESS_MASK |
1911                            GDK_BUTTON_RELEASE_MASK |
1912                            GDK_KEY_PRESS_MASK |
1913                            GDK_KEY_RELEASE_MASK |
1914                            gtk_widget_get_events (widget));
1915
1916   tree_view->priv->header_window = gdk_window_new (window,
1917                                                    &attributes, attributes_mask);
1918   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1919
1920   /* Add them all up. */
1921   gtk_widget_style_attach (widget);
1922   style = gtk_widget_get_style (widget);
1923   gdk_window_set_background (tree_view->priv->bin_window,
1924                              &style->base[gtk_widget_get_state (widget)]);
1925   gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1926
1927   tmp_list = tree_view->priv->children;
1928   while (tmp_list)
1929     {
1930       GtkTreeViewChild *child = tmp_list->data;
1931       tmp_list = tmp_list->next;
1932
1933       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1934     }
1935
1936   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1937     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1938
1939   /* Need to call those here, since they create GCs */
1940   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1941   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1942
1943   install_presize_handler (tree_view); 
1944 }
1945
1946 static void
1947 gtk_tree_view_unrealize (GtkWidget *widget)
1948 {
1949   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1950   GtkTreeViewPrivate *priv = tree_view->priv;
1951   GList *list;
1952
1953   if (priv->scroll_timeout != 0)
1954     {
1955       g_source_remove (priv->scroll_timeout);
1956       priv->scroll_timeout = 0;
1957     }
1958
1959   if (priv->auto_expand_timeout != 0)
1960     {
1961       g_source_remove (priv->auto_expand_timeout);
1962       priv->auto_expand_timeout = 0;
1963     }
1964
1965   if (priv->open_dest_timeout != 0)
1966     {
1967       g_source_remove (priv->open_dest_timeout);
1968       priv->open_dest_timeout = 0;
1969     }
1970
1971   remove_expand_collapse_timeout (tree_view);
1972   
1973   if (priv->presize_handler_timer != 0)
1974     {
1975       g_source_remove (priv->presize_handler_timer);
1976       priv->presize_handler_timer = 0;
1977     }
1978
1979   if (priv->validate_rows_timer != 0)
1980     {
1981       g_source_remove (priv->validate_rows_timer);
1982       priv->validate_rows_timer = 0;
1983     }
1984
1985   if (priv->scroll_sync_timer != 0)
1986     {
1987       g_source_remove (priv->scroll_sync_timer);
1988       priv->scroll_sync_timer = 0;
1989     }
1990
1991   if (priv->typeselect_flush_timeout)
1992     {
1993       g_source_remove (priv->typeselect_flush_timeout);
1994       priv->typeselect_flush_timeout = 0;
1995     }
1996   
1997   for (list = priv->columns; list; list = list->next)
1998     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1999
2000   gdk_window_set_user_data (priv->bin_window, NULL);
2001   gdk_window_destroy (priv->bin_window);
2002   priv->bin_window = NULL;
2003
2004   gdk_window_set_user_data (priv->header_window, NULL);
2005   gdk_window_destroy (priv->header_window);
2006   priv->header_window = NULL;
2007
2008   if (priv->drag_window)
2009     {
2010       gdk_window_set_user_data (priv->drag_window, NULL);
2011       gdk_window_destroy (priv->drag_window);
2012       priv->drag_window = NULL;
2013     }
2014
2015   if (priv->drag_highlight_window)
2016     {
2017       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2018       gdk_window_destroy (priv->drag_highlight_window);
2019       priv->drag_highlight_window = NULL;
2020     }
2021
2022   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2023 }
2024
2025 /* GtkWidget::size_request helper */
2026 static void
2027 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2028 {
2029   GList *list;
2030
2031   tree_view->priv->header_height = 0;
2032
2033   if (tree_view->priv->model)
2034     {
2035       for (list = tree_view->priv->columns; list; list = list->next)
2036         {
2037           GtkRequisition requisition;
2038           GtkTreeViewColumn *column = list->data;
2039
2040           if (column->button == NULL)
2041             continue;
2042
2043           column = list->data;
2044
2045           gtk_widget_get_preferred_size (column->button, &requisition, NULL);
2046           column->button_request = requisition.width;
2047           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2048         }
2049     }
2050 }
2051
2052
2053 /* Called only by ::size_request */
2054 static void
2055 gtk_tree_view_update_size (GtkTreeView *tree_view)
2056 {
2057   GList *list;
2058   GtkTreeViewColumn *column;
2059   gint i;
2060
2061   if (tree_view->priv->model == NULL)
2062     {
2063       tree_view->priv->width = 0;
2064       tree_view->priv->prev_width = 0;                   
2065       tree_view->priv->height = 0;
2066       return;
2067     }
2068
2069   tree_view->priv->prev_width = tree_view->priv->width;  
2070   tree_view->priv->width = 0;
2071
2072   /* keep this in sync with size_allocate below */
2073   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2074     {
2075       gint real_requested_width = 0;
2076       column = list->data;
2077       if (!column->visible)
2078         continue;
2079
2080       if (column->use_resized_width)
2081         {
2082           real_requested_width = column->resized_width;
2083         }
2084       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2085         {
2086           real_requested_width = column->fixed_width;
2087         }
2088       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2089         {
2090           real_requested_width = MAX (column->requested_width, column->button_request);
2091         }
2092       else
2093         {
2094           real_requested_width = column->requested_width;
2095         }
2096
2097       if (column->min_width != -1)
2098         real_requested_width = MAX (real_requested_width, column->min_width);
2099       if (column->max_width != -1)
2100         real_requested_width = MIN (real_requested_width, column->max_width);
2101
2102       tree_view->priv->width += real_requested_width;
2103     }
2104
2105   if (tree_view->priv->tree == NULL)
2106     tree_view->priv->height = 0;
2107   else
2108     tree_view->priv->height = tree_view->priv->tree->root->offset;
2109 }
2110
2111 static void
2112 gtk_tree_view_size_request (GtkWidget      *widget,
2113                             GtkRequisition *requisition)
2114 {
2115   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2116   GList *tmp_list;
2117
2118   /* we validate some rows initially just to make sure we have some size. 
2119    * In practice, with a lot of static lists, this should get a good width.
2120    */
2121   do_validate_rows (tree_view, FALSE);
2122   gtk_tree_view_size_request_columns (tree_view);
2123   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2124
2125   requisition->width = tree_view->priv->width;
2126   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2127
2128   tmp_list = tree_view->priv->children;
2129 }
2130
2131 static void
2132 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2133                                    gint      *minimum,
2134                                    gint      *natural)
2135 {
2136   GtkRequisition requisition;
2137
2138   gtk_tree_view_size_request (widget, &requisition);
2139
2140   *minimum = *natural = requisition.width;
2141 }
2142
2143 static void
2144 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2145                                     gint      *minimum,
2146                                     gint      *natural)
2147 {
2148   GtkRequisition requisition;
2149
2150   gtk_tree_view_size_request (widget, &requisition);
2151
2152   *minimum = *natural = requisition.height;
2153 }
2154
2155 static int
2156 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2157 {
2158   int width = 0;
2159   GList *list;
2160   gboolean rtl;
2161
2162   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2163   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2164        list->data != tree_view->priv->expander_column;
2165        list = (rtl ? list->prev : list->next))
2166     {
2167       GtkTreeViewColumn *column = list->data;
2168
2169       width += column->width;
2170     }
2171
2172   return width;
2173 }
2174
2175 static void
2176 invalidate_column (GtkTreeView       *tree_view,
2177                    GtkTreeViewColumn *column)
2178 {
2179   gint column_offset = 0;
2180   GList *list;
2181   GtkWidget *widget = GTK_WIDGET (tree_view);
2182   gboolean rtl;
2183
2184   if (!gtk_widget_get_realized (widget))
2185     return;
2186
2187   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2188   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2189        list;
2190        list = (rtl ? list->prev : list->next))
2191     {
2192       GtkTreeViewColumn *tmpcolumn = list->data;
2193       if (tmpcolumn == column)
2194         {
2195           GtkAllocation allocation;
2196           GdkRectangle invalid_rect;
2197
2198           gtk_widget_get_allocation (widget, &allocation);
2199           invalid_rect.x = column_offset;
2200           invalid_rect.y = 0;
2201           invalid_rect.width = column->width;
2202           invalid_rect.height = allocation.height;
2203
2204           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2205           break;
2206         }
2207       
2208       column_offset += tmpcolumn->width;
2209     }
2210 }
2211
2212 static void
2213 invalidate_last_column (GtkTreeView *tree_view)
2214 {
2215   GList *last_column;
2216   gboolean rtl;
2217
2218   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2219
2220   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2221        last_column;
2222        last_column = (rtl ? last_column->next : last_column->prev))
2223     {
2224       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2225         {
2226           invalidate_column (tree_view, last_column->data);
2227           return;
2228         }
2229     }
2230 }
2231
2232 static gint
2233 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2234                                                     GtkTreeViewColumn *column)
2235 {
2236   gint real_requested_width;
2237
2238   if (column->use_resized_width)
2239     {
2240       real_requested_width = column->resized_width;
2241     }
2242   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2243     {
2244       real_requested_width = column->fixed_width;
2245     }
2246   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2247     {
2248       real_requested_width = MAX (column->requested_width, column->button_request);
2249     }
2250   else
2251     {
2252       real_requested_width = column->requested_width;
2253       if (real_requested_width < 0)
2254         real_requested_width = 0;
2255     }
2256
2257   if (column->min_width != -1)
2258     real_requested_width = MAX (real_requested_width, column->min_width);
2259   if (column->max_width != -1)
2260     real_requested_width = MIN (real_requested_width, column->max_width);
2261
2262   return real_requested_width;
2263 }
2264
2265 /* GtkWidget::size_allocate helper */
2266 static void
2267 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2268                                      gboolean  *width_changed)
2269 {
2270   GtkTreeView *tree_view;
2271   GList *list, *first_column, *last_column;
2272   GtkTreeViewColumn *column;
2273   GtkAllocation allocation;
2274   GtkAllocation widget_allocation;
2275   gint width = 0;
2276   gint extra, extra_per_column, extra_for_last;
2277   gint full_requested_width = 0;
2278   gint number_of_expand_columns = 0;
2279   gboolean column_changed = FALSE;
2280   gboolean rtl;
2281   gboolean update_expand;
2282   
2283   tree_view = GTK_TREE_VIEW (widget);
2284
2285   for (last_column = g_list_last (tree_view->priv->columns);
2286        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2287        last_column = last_column->prev)
2288     ;
2289   if (last_column == NULL)
2290     return;
2291
2292   for (first_column = g_list_first (tree_view->priv->columns);
2293        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2294        first_column = first_column->next)
2295     ;
2296
2297   allocation.y = 0;
2298   allocation.height = tree_view->priv->header_height;
2299
2300   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2301
2302   /* find out how many extra space and expandable columns we have */
2303   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2304     {
2305       column = (GtkTreeViewColumn *)list->data;
2306
2307       if (!column->visible)
2308         continue;
2309
2310       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2311
2312       if (column->expand)
2313         number_of_expand_columns++;
2314     }
2315
2316   /* Only update the expand value if the width of the widget has changed,
2317    * or the number of expand columns has changed, or if there are no expand
2318    * columns, or if we didn't have an size-allocation yet after the
2319    * last validated node.
2320    */
2321   update_expand = (width_changed && *width_changed == TRUE)
2322       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2323       || number_of_expand_columns == 0
2324       || tree_view->priv->post_validation_flag == TRUE;
2325
2326   tree_view->priv->post_validation_flag = FALSE;
2327
2328   gtk_widget_get_allocation (widget, &widget_allocation);
2329   if (!update_expand)
2330     {
2331       extra = tree_view->priv->last_extra_space;
2332       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2333     }
2334   else
2335     {
2336       extra = MAX (widget_allocation.width - full_requested_width, 0);
2337       extra_for_last = 0;
2338
2339       tree_view->priv->last_extra_space = extra;
2340     }
2341
2342   if (number_of_expand_columns > 0)
2343     extra_per_column = extra/number_of_expand_columns;
2344   else
2345     extra_per_column = 0;
2346
2347   if (update_expand)
2348     {
2349       tree_view->priv->last_extra_space_per_column = extra_per_column;
2350       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2351     }
2352
2353   for (list = (rtl ? last_column : first_column); 
2354        list != (rtl ? first_column->prev : last_column->next);
2355        list = (rtl ? list->prev : list->next)) 
2356     {
2357       gint real_requested_width = 0;
2358       gint old_width;
2359
2360       column = list->data;
2361       old_width = column->width;
2362
2363       if (!column->visible)
2364         continue;
2365
2366       /* We need to handle the dragged button specially.
2367        */
2368       if (column == tree_view->priv->drag_column)
2369         {
2370           GtkAllocation drag_allocation;
2371
2372           drag_allocation.x = 0;
2373           drag_allocation.y = 0;
2374           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2375           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2376           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2377                                     &drag_allocation);
2378           width += drag_allocation.width;
2379           continue;
2380         }
2381
2382       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2383
2384       allocation.x = width;
2385       column->width = real_requested_width;
2386
2387       if (column->expand)
2388         {
2389           if (number_of_expand_columns == 1)
2390             {
2391               /* We add the remander to the last column as
2392                * */
2393               column->width += extra;
2394             }
2395           else
2396             {
2397               column->width += extra_per_column;
2398               extra -= extra_per_column;
2399               number_of_expand_columns --;
2400             }
2401         }
2402       else if (number_of_expand_columns == 0 &&
2403                list == last_column)
2404         {
2405           column->width += extra;
2406         }
2407
2408       /* In addition to expand, the last column can get even more
2409        * extra space so all available space is filled up.
2410        */
2411       if (extra_for_last > 0 && list == last_column)
2412         column->width += extra_for_last;
2413
2414       g_object_notify (G_OBJECT (column), "width");
2415
2416       allocation.width = column->width;
2417       width += column->width;
2418
2419       if (column->width > old_width)
2420         column_changed = TRUE;
2421
2422       gtk_widget_size_allocate (column->button, &allocation);
2423
2424       if (column->window)
2425         gdk_window_move_resize (column->window,
2426                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2427                                 allocation.y,
2428                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2429     }
2430
2431   /* We change the width here.  The user might have been resizing columns,
2432    * so the total width of the tree view changes.
2433    */
2434   tree_view->priv->width = width;
2435   if (width_changed)
2436     *width_changed = TRUE;
2437
2438   if (column_changed)
2439     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2440 }
2441
2442
2443 static void
2444 gtk_tree_view_size_allocate (GtkWidget     *widget,
2445                              GtkAllocation *allocation)
2446 {
2447   GtkAllocation widget_allocation;
2448   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2449   GList *tmp_list;
2450   gboolean width_changed = FALSE;
2451   gint old_width;
2452
2453   gtk_widget_get_allocation (widget, &widget_allocation);
2454   old_width = widget_allocation.width;
2455   if (allocation->width != widget_allocation.width)
2456     width_changed = TRUE;
2457
2458   gtk_widget_set_allocation (widget, allocation);
2459
2460   tmp_list = tree_view->priv->children;
2461
2462   while (tmp_list)
2463     {
2464       GtkAllocation allocation;
2465
2466       GtkTreeViewChild *child = tmp_list->data;
2467       tmp_list = tmp_list->next;
2468
2469       /* totally ignore our child's requisition */
2470       allocation.x = child->x;
2471       allocation.y = child->y;
2472       allocation.width = child->width;
2473       allocation.height = child->height;
2474       gtk_widget_size_allocate (child->widget, &allocation);
2475     }
2476
2477   /* We size-allocate the columns first because the width of the
2478    * tree view (used in updating the adjustments below) might change.
2479    */
2480   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2481
2482   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2483   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2484                                 allocation->width);
2485   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2486                                      allocation->width * 0.9);
2487   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2488                                      allocation->width * 0.1);
2489   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2490   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2491                             MAX (tree_view->priv->hadjustment->page_size,
2492                                  tree_view->priv->width));
2493   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2494
2495   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2496     {
2497       if (allocation->width < tree_view->priv->width)
2498         {
2499           if (tree_view->priv->init_hadjust_value)
2500             {
2501               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2502                                         MAX (tree_view->priv->width -
2503                                              allocation->width, 0));
2504               tree_view->priv->init_hadjust_value = FALSE;
2505             }
2506           else if (allocation->width != old_width)
2507             {
2508               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2509                                         CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width,
2510                                                0,
2511                                                tree_view->priv->width - allocation->width));
2512             }
2513           else
2514             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2515                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value),
2516                                              0,
2517                                              tree_view->priv->width - allocation->width));
2518         }
2519       else
2520         {
2521           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2522           tree_view->priv->init_hadjust_value = TRUE;
2523         }
2524     }
2525   else
2526     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2527       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2528                                 MAX (tree_view->priv->width -
2529                                      allocation->width, 0));
2530
2531   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2532   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2533                                 allocation->height -
2534                                 TREE_VIEW_HEADER_HEIGHT (tree_view));
2535   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2536                                      tree_view->priv->vadjustment->page_size * 0.1);
2537   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2538                                      tree_view->priv->vadjustment->page_size * 0.9);
2539   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2540   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2541                             MAX (tree_view->priv->vadjustment->page_size,
2542                                  tree_view->priv->height));
2543   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2544
2545   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2546   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2547     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2548   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2549     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2550                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2551   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2552     gtk_tree_view_top_row_to_dy (tree_view);
2553   else
2554     gtk_tree_view_dy_to_top_row (tree_view);
2555   
2556   if (gtk_widget_get_realized (widget))
2557     {
2558       gdk_window_move_resize (gtk_widget_get_window (widget),
2559                               allocation->x, allocation->y,
2560                               allocation->width, allocation->height);
2561       gdk_window_move_resize (tree_view->priv->header_window,
2562                               - (gint) tree_view->priv->hadjustment->value,
2563                               0,
2564                               MAX (tree_view->priv->width, allocation->width),
2565                               tree_view->priv->header_height);
2566       gdk_window_move_resize (tree_view->priv->bin_window,
2567                               - (gint) tree_view->priv->hadjustment->value,
2568                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2569                               MAX (tree_view->priv->width, allocation->width),
2570                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2571     }
2572
2573   if (tree_view->priv->tree == NULL)
2574     invalidate_empty_focus (tree_view);
2575
2576   if (gtk_widget_get_realized (widget))
2577     {
2578       gboolean has_expand_column = FALSE;
2579       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2580         {
2581           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2582             {
2583               has_expand_column = TRUE;
2584               break;
2585             }
2586         }
2587
2588       if (width_changed && tree_view->priv->expander_column)
2589         {
2590           /* Might seem awkward, but is the best heuristic I could come up
2591            * with.  Only if the width of the columns before the expander
2592            * changes, we will update the prelight status.  It is this
2593            * width that makes the expander move vertically.  Always updating
2594            * prelight status causes trouble with hover selections.
2595            */
2596           gint width_before_expander;
2597
2598           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2599
2600           if (tree_view->priv->prev_width_before_expander
2601               != width_before_expander)
2602               update_prelight (tree_view,
2603                                tree_view->priv->event_last_x,
2604                                tree_view->priv->event_last_y);
2605
2606           tree_view->priv->prev_width_before_expander = width_before_expander;
2607         }
2608
2609       /* This little hack only works if we have an LTR locale, and no column has the  */
2610       if (width_changed)
2611         {
2612           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2613               ! has_expand_column)
2614             invalidate_last_column (tree_view);
2615           else
2616             gtk_widget_queue_draw (widget);
2617         }
2618     }
2619 }
2620
2621 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2622 static void
2623 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2624 {
2625   GtkWidget *widget = GTK_WIDGET (tree_view);
2626
2627   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2628     gtk_widget_grab_focus (widget);
2629   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2630 }
2631
2632 static inline gboolean
2633 row_is_separator (GtkTreeView *tree_view,
2634                   GtkTreeIter *iter,
2635                   GtkTreePath *path)
2636 {
2637   gboolean is_separator = FALSE;
2638
2639   if (tree_view->priv->row_separator_func)
2640     {
2641       GtkTreeIter tmpiter;
2642
2643       if (iter)
2644         tmpiter = *iter;
2645       else
2646         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2647
2648       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2649                                                           &tmpiter,
2650                                                           tree_view->priv->row_separator_data);
2651     }
2652
2653   return is_separator;
2654 }
2655
2656 static gboolean
2657 gtk_tree_view_button_press (GtkWidget      *widget,
2658                             GdkEventButton *event)
2659 {
2660   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2661   GList *list;
2662   GtkTreeViewColumn *column = NULL;
2663   gint i;
2664   GdkRectangle background_area;
2665   GdkRectangle cell_area;
2666   gint vertical_separator;
2667   gint horizontal_separator;
2668   gboolean path_is_selectable;
2669   gboolean rtl;
2670
2671   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2672   gtk_tree_view_stop_editing (tree_view, FALSE);
2673   gtk_widget_style_get (widget,
2674                         "vertical-separator", &vertical_separator,
2675                         "horizontal-separator", &horizontal_separator,
2676                         NULL);
2677
2678
2679   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2680    * we're done handling the button press.
2681    */
2682
2683   if (event->window == tree_view->priv->bin_window)
2684     {
2685       GtkRBNode *node;
2686       GtkRBTree *tree;
2687       GtkTreePath *path;
2688       gchar *path_string;
2689       gint depth;
2690       gint new_y;
2691       gint y_offset;
2692       gint dval;
2693       gint pre_val, aft_val;
2694       GtkTreeViewColumn *column = NULL;
2695       GtkCellRenderer *focus_cell = NULL;
2696       gint column_handled_click = FALSE;
2697       gboolean row_double_click = FALSE;
2698       gboolean rtl;
2699       gboolean node_selected;
2700
2701       /* Empty tree? */
2702       if (tree_view->priv->tree == NULL)
2703         {
2704           grab_focus_and_unset_draw_keyfocus (tree_view);
2705           return TRUE;
2706         }
2707
2708       /* are we in an arrow? */
2709       if (tree_view->priv->prelight_node &&
2710           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2711           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2712         {
2713           if (event->button == 1)
2714             {
2715               gtk_grab_add (widget);
2716               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2717               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2718               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2719                                               tree_view->priv->prelight_tree,
2720                                               tree_view->priv->prelight_node);
2721             }
2722
2723           grab_focus_and_unset_draw_keyfocus (tree_view);
2724           return TRUE;
2725         }
2726
2727       /* find the node that was clicked */
2728       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2729       if (new_y < 0)
2730         new_y = 0;
2731       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2732
2733       if (node == NULL)
2734         {
2735           /* We clicked in dead space */
2736           grab_focus_and_unset_draw_keyfocus (tree_view);
2737           return TRUE;
2738         }
2739
2740       /* Get the path and the node */
2741       path = _gtk_tree_view_find_path (tree_view, tree, node);
2742       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2743
2744       if (!path_is_selectable)
2745         {
2746           gtk_tree_path_free (path);
2747           grab_focus_and_unset_draw_keyfocus (tree_view);
2748           return TRUE;
2749         }
2750
2751       depth = gtk_tree_path_get_depth (path);
2752       background_area.y = y_offset + event->y;
2753       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2754       background_area.x = 0;
2755
2756
2757       /* Let the column have a chance at selecting it. */
2758       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2759       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2760            list; list = (rtl ? list->prev : list->next))
2761         {
2762           GtkTreeViewColumn *candidate = list->data;
2763
2764           if (!candidate->visible)
2765             continue;
2766
2767           background_area.width = candidate->width;
2768           if ((background_area.x > (gint) event->x) ||
2769               (background_area.x + background_area.width <= (gint) event->x))
2770             {
2771               background_area.x += background_area.width;
2772               continue;
2773             }
2774
2775           /* we found the focus column */
2776           column = candidate;
2777           cell_area = background_area;
2778           cell_area.width -= horizontal_separator;
2779           cell_area.height -= vertical_separator;
2780           cell_area.x += horizontal_separator/2;
2781           cell_area.y += vertical_separator/2;
2782           if (gtk_tree_view_is_expander_column (tree_view, column))
2783             {
2784               if (!rtl)
2785                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2786               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2787
2788               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2789                 {
2790                   if (!rtl)
2791                     cell_area.x += depth * tree_view->priv->expander_size;
2792                   cell_area.width -= depth * tree_view->priv->expander_size;
2793                 }
2794             }
2795           break;
2796         }
2797
2798       if (column == NULL)
2799         {
2800           gtk_tree_path_free (path);
2801           grab_focus_and_unset_draw_keyfocus (tree_view);
2802           return FALSE;
2803         }
2804
2805       tree_view->priv->focus_column = column;
2806
2807       /* decide if we edit */
2808       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2809           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2810         {
2811           GtkTreePath *anchor;
2812           GtkTreeIter iter;
2813
2814           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2815           gtk_tree_view_column_cell_set_cell_data (column,
2816                                                    tree_view->priv->model,
2817                                                    &iter,
2818                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2819                                                    node->children?TRUE:FALSE);
2820
2821           if (tree_view->priv->anchor)
2822             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2823           else
2824             anchor = NULL;
2825
2826           if ((anchor && !gtk_tree_path_compare (anchor, path))
2827               || !_gtk_tree_view_column_has_editable_cell (column))
2828             {
2829               GtkCellEditable *cell_editable = NULL;
2830
2831               /* FIXME: get the right flags */
2832               guint flags = 0;
2833
2834               path_string = gtk_tree_path_to_string (path);
2835
2836               if (_gtk_tree_view_column_cell_event (column,
2837                                                     &cell_editable,
2838                                                     (GdkEvent *)event,
2839                                                     path_string,
2840                                                     &background_area,
2841                                                     &cell_area, flags))
2842                 {
2843                   if (cell_editable != NULL)
2844                     {
2845                       gint left, right;
2846                       GdkRectangle area;
2847
2848                       area = cell_area;
2849                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2850
2851                       area.x += left;
2852                       area.width -= right + left;
2853
2854                       gtk_tree_view_real_start_editing (tree_view,
2855                                                         column,
2856                                                         path,
2857                                                         cell_editable,
2858                                                         &area,
2859                                                         (GdkEvent *)event,
2860                                                         flags);
2861                       g_free (path_string);
2862                       gtk_tree_path_free (path);
2863                       gtk_tree_path_free (anchor);
2864                       return TRUE;
2865                     }
2866                   column_handled_click = TRUE;
2867                 }
2868               g_free (path_string);
2869             }
2870           if (anchor)
2871             gtk_tree_path_free (anchor);
2872         }
2873
2874       /* select */
2875       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2876       pre_val = tree_view->priv->vadjustment->value;
2877
2878       /* we only handle selection modifications on the first button press
2879        */
2880       if (event->type == GDK_BUTTON_PRESS)
2881         {
2882           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2883             tree_view->priv->ctrl_pressed = TRUE;
2884           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2885             tree_view->priv->shift_pressed = TRUE;
2886
2887           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2888           if (focus_cell)
2889             gtk_tree_view_column_focus_cell (column, focus_cell);
2890
2891           if (event->state & GDK_CONTROL_MASK)
2892             {
2893               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2894               gtk_tree_view_real_toggle_cursor_row (tree_view);
2895             }
2896           else if (event->state & GDK_SHIFT_MASK)
2897             {
2898               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2899               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2900             }
2901           else
2902             {
2903               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2904             }
2905
2906           tree_view->priv->ctrl_pressed = FALSE;
2907           tree_view->priv->shift_pressed = FALSE;
2908         }
2909
2910       /* the treeview may have been scrolled because of _set_cursor,
2911        * correct here
2912        */
2913
2914       aft_val = tree_view->priv->vadjustment->value;
2915       dval = pre_val - aft_val;
2916
2917       cell_area.y += dval;
2918       background_area.y += dval;
2919
2920       /* Save press to possibly begin a drag
2921        */
2922       if (!column_handled_click &&
2923           !tree_view->priv->in_grab &&
2924           tree_view->priv->pressed_button < 0)
2925         {
2926           tree_view->priv->pressed_button = event->button;
2927           tree_view->priv->press_start_x = event->x;
2928           tree_view->priv->press_start_y = event->y;
2929
2930           if (tree_view->priv->rubber_banding_enable
2931               && !node_selected
2932               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2933             {
2934               tree_view->priv->press_start_y += tree_view->priv->dy;
2935               tree_view->priv->rubber_band_x = event->x;
2936               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2937               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2938
2939               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2940                 tree_view->priv->rubber_band_ctrl = TRUE;
2941               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2942                 tree_view->priv->rubber_band_shift = TRUE;
2943             }
2944         }
2945
2946       /* Test if a double click happened on the same row. */
2947       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2948         {
2949           int double_click_time, double_click_distance;
2950
2951           g_object_get (gtk_settings_get_default (),
2952                         "gtk-double-click-time", &double_click_time,
2953                         "gtk-double-click-distance", &double_click_distance,
2954                         NULL);
2955
2956           /* Same conditions as _gdk_event_button_generate */
2957           if (tree_view->priv->last_button_x != -1 &&
2958               (event->time < tree_view->priv->last_button_time + double_click_time) &&
2959               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2960               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2961             {
2962               /* We do no longer compare paths of this row and the
2963                * row clicked previously.  We use the double click
2964                * distance to decide whether this is a valid click,
2965                * allowing the mouse to slightly move over another row.
2966                */
2967               row_double_click = TRUE;
2968
2969               tree_view->priv->last_button_time = 0;
2970               tree_view->priv->last_button_x = -1;
2971               tree_view->priv->last_button_y = -1;
2972             }
2973           else
2974             {
2975               tree_view->priv->last_button_time = event->time;
2976               tree_view->priv->last_button_x = event->x;
2977               tree_view->priv->last_button_y = event->y;
2978             }
2979         }
2980
2981       if (row_double_click)
2982         {
2983           gtk_grab_remove (widget);
2984           gtk_tree_view_row_activated (tree_view, path, column);
2985
2986           if (tree_view->priv->pressed_button == event->button)
2987             tree_view->priv->pressed_button = -1;
2988         }
2989
2990       gtk_tree_path_free (path);
2991
2992       /* If we activated the row through a double click we don't want to grab
2993        * focus back, as moving focus to another widget is pretty common.
2994        */
2995       if (!row_double_click)
2996         grab_focus_and_unset_draw_keyfocus (tree_view);
2997
2998       return TRUE;
2999     }
3000
3001   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3002    */
3003   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3004     {
3005       column = list->data;
3006       if (event->window == column->window &&
3007           column->resizable &&
3008           column->window)
3009         {
3010           GtkAllocation button_allocation;
3011           gpointer drag_data;
3012
3013           if (event->type == GDK_2BUTTON_PRESS &&
3014               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3015             {
3016               column->use_resized_width = FALSE;
3017               _gtk_tree_view_column_autosize (tree_view, column);
3018               return TRUE;
3019             }
3020
3021           if (gdk_pointer_grab (column->window, FALSE,
3022                                 GDK_POINTER_MOTION_HINT_MASK |
3023                                 GDK_BUTTON1_MOTION_MASK |
3024                                 GDK_BUTTON_RELEASE_MASK,
3025                                 NULL, NULL, event->time))
3026             return FALSE;
3027
3028           gtk_grab_add (widget);
3029           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3030           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
3031
3032           /* block attached dnd signal handler */
3033           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3034           if (drag_data)
3035             g_signal_handlers_block_matched (widget,
3036                                              G_SIGNAL_MATCH_DATA,
3037                                              0, 0, NULL, NULL,
3038                                              drag_data);
3039
3040           gtk_widget_get_allocation (column->button, &button_allocation);
3041           tree_view->priv->drag_pos = i;
3042           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
3043
3044           if (!gtk_widget_has_focus (widget))
3045             gtk_widget_grab_focus (widget);
3046
3047           return TRUE;
3048         }
3049     }
3050   return FALSE;
3051 }
3052
3053 /* GtkWidget::button_release_event helper */
3054 static gboolean
3055 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3056                                           GdkEventButton *event)
3057 {
3058   GtkTreeView *tree_view;
3059   GList *l;
3060   gboolean rtl;
3061
3062   tree_view = GTK_TREE_VIEW (widget);
3063
3064   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3065   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
3066   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
3067
3068   /* Move the button back */
3069   g_object_ref (tree_view->priv->drag_column->button);
3070   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
3071   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
3072   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
3073   g_object_unref (tree_view->priv->drag_column->button);
3074   gtk_widget_queue_resize (widget);
3075   if (tree_view->priv->drag_column->resizable)
3076     {
3077       gdk_window_raise (tree_view->priv->drag_column->window);
3078       gdk_window_show (tree_view->priv->drag_column->window);
3079     }
3080   else
3081     gdk_window_hide (tree_view->priv->drag_column->window);
3082
3083   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
3084
3085   if (rtl)
3086     {
3087       if (tree_view->priv->cur_reorder &&
3088           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3089         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3090                                          tree_view->priv->cur_reorder->right_column);
3091     }
3092   else
3093     {
3094       if (tree_view->priv->cur_reorder &&
3095           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3096         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3097                                          tree_view->priv->cur_reorder->left_column);
3098     }
3099   tree_view->priv->drag_column = NULL;
3100   gdk_window_hide (tree_view->priv->drag_window);
3101
3102   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3103     g_slice_free (GtkTreeViewColumnReorder, l->data);
3104   g_list_free (tree_view->priv->column_drag_info);
3105   tree_view->priv->column_drag_info = NULL;
3106   tree_view->priv->cur_reorder = NULL;
3107
3108   if (tree_view->priv->drag_highlight_window)
3109     gdk_window_hide (tree_view->priv->drag_highlight_window);
3110
3111   /* Reset our flags */
3112   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3113   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
3114
3115   return TRUE;
3116 }
3117
3118 /* GtkWidget::button_release_event helper */
3119 static gboolean
3120 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3121                                             GdkEventButton *event)
3122 {
3123   GtkTreeView *tree_view;
3124   gpointer drag_data;
3125
3126   tree_view = GTK_TREE_VIEW (widget);
3127
3128   tree_view->priv->drag_pos = -1;
3129
3130   /* unblock attached dnd signal handler */
3131   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3132   if (drag_data)
3133     g_signal_handlers_unblock_matched (widget,
3134                                        G_SIGNAL_MATCH_DATA,
3135                                        0, 0, NULL, NULL,
3136                                        drag_data);
3137
3138   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3139   gtk_grab_remove (widget);
3140   gdk_display_pointer_ungrab (gdk_window_get_display (event->window),
3141                               event->time);
3142   return TRUE;
3143 }
3144
3145 static gboolean
3146 gtk_tree_view_button_release (GtkWidget      *widget,
3147                               GdkEventButton *event)
3148 {
3149   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3150
3151   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3152     return gtk_tree_view_button_release_drag_column (widget, event);
3153
3154   if (tree_view->priv->rubber_band_status)
3155     gtk_tree_view_stop_rubber_band (tree_view);
3156
3157   if (tree_view->priv->pressed_button == event->button)
3158     tree_view->priv->pressed_button = -1;
3159
3160   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3161     return gtk_tree_view_button_release_column_resize (widget, event);
3162
3163   if (tree_view->priv->button_pressed_node == NULL)
3164     return FALSE;
3165
3166   if (event->button == 1)
3167     {
3168       gtk_grab_remove (widget);
3169       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3170           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3171         {
3172           GtkTreePath *path = NULL;
3173
3174           path = _gtk_tree_view_find_path (tree_view,
3175                                            tree_view->priv->button_pressed_tree,
3176                                            tree_view->priv->button_pressed_node);
3177           /* Actually activate the node */
3178           if (tree_view->priv->button_pressed_node->children == NULL)
3179             gtk_tree_view_real_expand_row (tree_view, path,
3180                                            tree_view->priv->button_pressed_tree,
3181                                            tree_view->priv->button_pressed_node,
3182                                            FALSE, TRUE);
3183           else
3184             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3185                                              tree_view->priv->button_pressed_tree,
3186                                              tree_view->priv->button_pressed_node, TRUE);
3187           gtk_tree_path_free (path);
3188         }
3189
3190       tree_view->priv->button_pressed_tree = NULL;
3191       tree_view->priv->button_pressed_node = NULL;
3192     }
3193
3194   return TRUE;
3195 }
3196
3197 static gboolean
3198 gtk_tree_view_grab_broken (GtkWidget          *widget,
3199                            GdkEventGrabBroken *event)
3200 {
3201   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3202
3203   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3204     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3205
3206   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3207     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3208
3209   return TRUE;
3210 }
3211
3212 #if 0
3213 static gboolean
3214 gtk_tree_view_configure (GtkWidget *widget,
3215                          GdkEventConfigure *event)
3216 {
3217   GtkTreeView *tree_view;
3218
3219   tree_view = GTK_TREE_VIEW (widget);
3220   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3221
3222   return FALSE;
3223 }
3224 #endif
3225
3226 /* GtkWidget::motion_event function set.
3227  */
3228
3229 static gboolean
3230 coords_are_over_arrow (GtkTreeView *tree_view,
3231                        GtkRBTree   *tree,
3232                        GtkRBNode   *node,
3233                        /* these are in bin window coords */
3234                        gint         x,
3235                        gint         y)
3236 {
3237   GdkRectangle arrow;
3238   gint x2;
3239
3240   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3241     return FALSE;
3242
3243   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3244     return FALSE;
3245
3246   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3247
3248   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3249
3250   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3251
3252   arrow.width = x2 - arrow.x;
3253
3254   return (x >= arrow.x &&
3255           x < (arrow.x + arrow.width) &&
3256           y >= arrow.y &&
3257           y < (arrow.y + arrow.height));
3258 }
3259
3260 static gboolean
3261 auto_expand_timeout (gpointer data)
3262 {
3263   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3264   GtkTreePath *path;
3265
3266   if (tree_view->priv->prelight_node)
3267     {
3268       path = _gtk_tree_view_find_path (tree_view,
3269                                        tree_view->priv->prelight_tree,
3270                                        tree_view->priv->prelight_node);   
3271
3272       if (tree_view->priv->prelight_node->children)
3273         gtk_tree_view_collapse_row (tree_view, path);
3274       else
3275         gtk_tree_view_expand_row (tree_view, path, FALSE);
3276
3277       gtk_tree_path_free (path);
3278     }
3279
3280   tree_view->priv->auto_expand_timeout = 0;
3281
3282   return FALSE;
3283 }
3284
3285 static void
3286 remove_auto_expand_timeout (GtkTreeView *tree_view)
3287 {
3288   if (tree_view->priv->auto_expand_timeout != 0)
3289     {
3290       g_source_remove (tree_view->priv->auto_expand_timeout);
3291       tree_view->priv->auto_expand_timeout = 0;
3292     }
3293 }
3294
3295 static void
3296 do_prelight (GtkTreeView *tree_view,
3297              GtkRBTree   *tree,
3298              GtkRBNode   *node,
3299              /* these are in bin_window coords */
3300              gint         x,
3301              gint         y)
3302 {
3303   if (tree_view->priv->prelight_tree == tree &&
3304       tree_view->priv->prelight_node == node)
3305     {
3306       /*  We are still on the same node,
3307           but we might need to take care of the arrow  */
3308
3309       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3310         {
3311           gboolean over_arrow;
3312           gboolean flag_set;
3313
3314           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3315           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3316                                              GTK_TREE_VIEW_ARROW_PRELIT);
3317
3318           if (over_arrow != flag_set)
3319             {
3320               if (over_arrow)
3321                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3322                                         GTK_TREE_VIEW_ARROW_PRELIT);
3323               else
3324                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3325                                           GTK_TREE_VIEW_ARROW_PRELIT);
3326
3327               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3328             }
3329         }
3330
3331       return;
3332     }
3333
3334   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3335     {
3336       /*  Unprelight the old node and arrow  */
3337
3338       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3339                              GTK_RBNODE_IS_PRELIT);
3340
3341       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3342           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3343         {
3344           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3345           
3346           gtk_tree_view_queue_draw_arrow (tree_view,
3347                                           tree_view->priv->prelight_tree,
3348                                           tree_view->priv->prelight_node);
3349         }
3350
3351       _gtk_tree_view_queue_draw_node (tree_view,
3352                                       tree_view->priv->prelight_tree,
3353                                       tree_view->priv->prelight_node,
3354                                       NULL);
3355     }
3356
3357
3358   if (tree_view->priv->hover_expand)
3359     remove_auto_expand_timeout (tree_view);
3360
3361   /*  Set the new prelight values  */
3362   tree_view->priv->prelight_node = node;
3363   tree_view->priv->prelight_tree = tree;
3364
3365   if (!node || !tree)
3366     return;
3367
3368   /*  Prelight the new node and arrow  */
3369
3370   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3371       && coords_are_over_arrow (tree_view, tree, node, x, y))
3372     {
3373       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3374
3375       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3376     }
3377
3378   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3379
3380   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3381
3382   if (tree_view->priv->hover_expand)
3383     {
3384       tree_view->priv->auto_expand_timeout = 
3385         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3386     }
3387 }
3388
3389 static void
3390 prelight_or_select (GtkTreeView *tree_view,
3391                     GtkRBTree   *tree,
3392                     GtkRBNode   *node,
3393                     /* these are in bin_window coords */
3394                     gint         x,
3395                     gint         y)
3396 {
3397   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3398   
3399   if (tree_view->priv->hover_selection &&
3400       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3401       !(tree_view->priv->edited_column &&
3402         tree_view->priv->edited_column->editable_widget))
3403     {
3404       if (node)
3405         {
3406           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3407             {
3408               GtkTreePath *path;
3409               
3410               path = _gtk_tree_view_find_path (tree_view, tree, node);
3411               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3412               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3413                 {
3414                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3415                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3416                 }
3417               gtk_tree_path_free (path);
3418             }
3419         }
3420
3421       else if (mode == GTK_SELECTION_SINGLE)
3422         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3423     }
3424
3425     do_prelight (tree_view, tree, node, x, y);
3426 }
3427
3428 static void
3429 ensure_unprelighted (GtkTreeView *tree_view)
3430 {
3431   do_prelight (tree_view,
3432                NULL, NULL,
3433                -1000, -1000); /* coords not possibly over an arrow */
3434
3435   g_assert (tree_view->priv->prelight_node == NULL);
3436 }
3437
3438 static void
3439 update_prelight (GtkTreeView *tree_view,
3440                  gint         x,
3441                  gint         y)
3442 {
3443   int new_y;
3444   GtkRBTree *tree;
3445   GtkRBNode *node;
3446
3447   if (tree_view->priv->tree == NULL)
3448     return;
3449
3450   if (x == -10000)
3451     {
3452       ensure_unprelighted (tree_view);
3453       return;
3454     }
3455
3456   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3457   if (new_y < 0)
3458     new_y = 0;
3459
3460   _gtk_rbtree_find_offset (tree_view->priv->tree,
3461                            new_y, &tree, &node);
3462
3463   if (node)
3464     prelight_or_select (tree_view, tree, node, x, y);
3465 }
3466
3467
3468
3469
3470 /* Our motion arrow is either a box (in the case of the original spot)
3471  * or an arrow.  It is expander_size wide.
3472  */
3473 /*
3474  * 11111111111111
3475  * 01111111111110
3476  * 00111111111100
3477  * 00011111111000
3478  * 00001111110000
3479  * 00000111100000
3480  * 00000111100000
3481  * 00000111100000
3482  * ~ ~ ~ ~ ~ ~ ~
3483  * 00000111100000
3484  * 00000111100000
3485  * 00000111100000
3486  * 00001111110000
3487  * 00011111111000
3488  * 00111111111100
3489  * 01111111111110
3490  * 11111111111111
3491  */
3492
3493 static void
3494 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3495 {
3496   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3497   GtkWidget *widget = GTK_WIDGET (tree_view);
3498   cairo_surface_t *mask_image;
3499   cairo_region_t *mask_region;
3500   gint x;
3501   gint y;
3502   gint width;
3503   gint height;
3504   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3505   GdkWindowAttr attributes;
3506   guint attributes_mask;
3507   cairo_t *cr;
3508
3509   if (!reorder ||
3510       reorder->left_column == tree_view->priv->drag_column ||
3511       reorder->right_column == tree_view->priv->drag_column)
3512     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3513   else if (reorder->left_column || reorder->right_column)
3514     {
3515       GtkAllocation left_allocation, right_allocation;
3516       GdkRectangle visible_rect;
3517
3518       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3519       if (reorder->left_column)
3520         {
3521           gtk_widget_get_allocation (reorder->left_column->button, &left_allocation);
3522           x = left_allocation.x + left_allocation.width;
3523         }
3524       else
3525         {
3526           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
3527           x = right_allocation.x;
3528         }
3529
3530       if (x < visible_rect.x)
3531         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3532       else if (x > visible_rect.x + visible_rect.width)
3533         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3534       else
3535         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3536     }
3537
3538   /* We want to draw the rectangle over the initial location. */
3539   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3540     {
3541       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3542         {
3543           GtkAllocation drag_allocation;
3544
3545           if (tree_view->priv->drag_highlight_window)
3546             {
3547               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3548                                         NULL);
3549               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3550             }
3551
3552           attributes.window_type = GDK_WINDOW_CHILD;
3553           attributes.wclass = GDK_INPUT_OUTPUT;
3554           attributes.x = tree_view->priv->drag_column_x;
3555           attributes.y = 0;
3556           gtk_widget_get_allocation (tree_view->priv->drag_column->button, &drag_allocation);
3557           width = attributes.width = drag_allocation.width;
3558           height = attributes.height = drag_allocation.height;
3559           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3560           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3561           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3562           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3563           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3564
3565           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3566           cr = cairo_create (mask_image);
3567
3568           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3569           cairo_stroke (cr);
3570           cairo_destroy (cr);
3571
3572           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3573           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3574                                            mask_region, 0, 0);
3575
3576           cairo_region_destroy (mask_region);
3577           cairo_surface_destroy (mask_image);
3578
3579           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3580         }
3581     }
3582   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3583     {
3584       GtkAllocation button_allocation;
3585
3586       width = tree_view->priv->expander_size;
3587
3588       /* Get x, y, width, height of arrow */
3589       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3590       if (reorder->left_column)
3591         {
3592           gtk_widget_get_allocation (reorder->left_column->button, &button_allocation);
3593           x += button_allocation.x + button_allocation.width - width/2;
3594           height = button_allocation.height;
3595         }
3596       else
3597         {
3598           gtk_widget_get_allocation (reorder->right_column->button, &button_allocation);
3599           x += button_allocation.x - width/2;
3600           height = button_allocation.height;
3601         }
3602       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3603       height += tree_view->priv->expander_size;
3604
3605       /* Create the new window */
3606       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3607         {
3608           if (tree_view->priv->drag_highlight_window)
3609             {
3610               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3611                                         NULL);
3612               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3613             }
3614
3615           attributes.window_type = GDK_WINDOW_TEMP;
3616           attributes.wclass = GDK_INPUT_OUTPUT;
3617           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3618           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3619           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3620           attributes.x = x;
3621           attributes.y = y;
3622           attributes.width = width;
3623           attributes.height = height;
3624           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3625                                                                    &attributes, attributes_mask);
3626           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3627
3628           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3629
3630           cr = cairo_create (mask_image);
3631           cairo_move_to (cr, 0, 0);
3632           cairo_line_to (cr, width, 0);
3633           cairo_line_to (cr, width / 2., width / 2);
3634           cairo_move_to (cr, 0, height);
3635           cairo_line_to (cr, width, height);
3636           cairo_line_to (cr, width / 2., height - width / 2.);
3637           cairo_fill (cr);
3638           cairo_destroy (cr);
3639
3640           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3641           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3642                                            mask_region, 0, 0);
3643
3644           cairo_region_destroy (mask_region);
3645           cairo_surface_destroy (mask_image);
3646         }
3647
3648       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3649       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3650     }
3651   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3652            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3653     {
3654       GtkAllocation allocation;
3655
3656       width = tree_view->priv->expander_size;
3657
3658       /* Get x, y, width, height of arrow */
3659       width = width/2; /* remember, the arrow only takes half the available width */
3660       gdk_window_get_origin (gtk_widget_get_window (widget),
3661                              &x, &y);
3662       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3663         {
3664           gtk_widget_get_allocation (widget, &allocation);
3665           x += allocation.width - width;
3666         }
3667
3668       if (reorder->left_column)
3669         {
3670           gtk_widget_get_allocation (reorder->left_column->button, &allocation);
3671           height = allocation.height;
3672         }
3673       else
3674         {
3675           gtk_widget_get_allocation (reorder->right_column->button, &allocation);
3676           height = allocation.height;
3677         }
3678
3679       y -= tree_view->priv->expander_size;
3680       height += 2*tree_view->priv->expander_size;
3681
3682       /* Create the new window */
3683       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3684           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3685         {
3686           if (tree_view->priv->drag_highlight_window)
3687             {
3688               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3689                                         NULL);
3690               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3691             }
3692
3693           attributes.window_type = GDK_WINDOW_TEMP;
3694           attributes.wclass = GDK_INPUT_OUTPUT;
3695           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3696           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3697           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3698           attributes.x = x;
3699           attributes.y = y;
3700           attributes.width = width;
3701           attributes.height = height;
3702           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3703           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3704
3705           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3706
3707           cr = cairo_create (mask_image);
3708           /* mirror if we're on the left */
3709           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3710             {
3711               cairo_translate (cr, width, 0);
3712               cairo_scale (cr, -1, 1);
3713             }
3714           cairo_move_to (cr, 0, 0);
3715           cairo_line_to (cr, width, width);
3716           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3717           cairo_move_to (cr, 0, height);
3718           cairo_line_to (cr, width, height - width);
3719           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3720           cairo_fill (cr);
3721           cairo_destroy (cr);
3722
3723           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3724           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3725                                            mask_region, 0, 0);
3726
3727           cairo_region_destroy (mask_region);
3728           cairo_surface_destroy (mask_image);
3729         }
3730
3731       tree_view->priv->drag_column_window_state = arrow_type;
3732       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3733    }
3734   else
3735     {
3736       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3737       gdk_window_hide (tree_view->priv->drag_highlight_window);
3738       return;
3739     }
3740
3741   gdk_window_show (tree_view->priv->drag_highlight_window);
3742   gdk_window_raise (tree_view->priv->drag_highlight_window);
3743 }
3744
3745 static gboolean
3746 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3747                                     GdkEventMotion *event)
3748 {
3749   gint x;
3750   gint new_width;
3751   GtkTreeViewColumn *column;
3752   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3753
3754   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3755
3756   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3757     gtk_widget_get_pointer (widget, &x, NULL);
3758   else
3759     x = event->x;
3760
3761   if (tree_view->priv->hadjustment)
3762     x += tree_view->priv->hadjustment->value;
3763
3764   new_width = gtk_tree_view_new_column_width (tree_view,
3765                                               tree_view->priv->drag_pos, &x);
3766   if (x != tree_view->priv->x_drag &&
3767       (new_width != column->fixed_width))
3768     {
3769       column->use_resized_width = TRUE;
3770       column->resized_width = new_width;
3771       if (column->expand)
3772         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3773       gtk_widget_queue_resize (widget);
3774     }
3775
3776   return FALSE;
3777 }
3778
3779
3780 static void
3781 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3782 {
3783   GtkTreeViewColumnReorder *reorder = NULL;
3784   GList *list;
3785   gint mouse_x;
3786
3787   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3788   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3789     {
3790       reorder = (GtkTreeViewColumnReorder *) list->data;
3791       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3792         break;
3793       reorder = NULL;
3794     }
3795
3796   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3797       return;*/
3798
3799   tree_view->priv->cur_reorder = reorder;
3800   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3801 }
3802
3803 static void
3804 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3805 {
3806   GdkRectangle visible_rect;
3807   gint y;
3808   gint offset;
3809
3810   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3811   y += tree_view->priv->dy;
3812
3813   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3814
3815   /* see if we are near the edge. */
3816   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3817   if (offset > 0)
3818     {
3819       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3820       if (offset < 0)
3821         return;
3822     }
3823
3824   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3825                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3826 }
3827
3828 static gboolean
3829 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3830 {
3831   GdkRectangle visible_rect;
3832   gint x;
3833   gint offset;
3834
3835   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3836
3837   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3838
3839   /* See if we are near the edge. */
3840   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3841   if (offset > 0)
3842     {
3843       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3844       if (offset < 0)
3845         return TRUE;
3846     }
3847   offset = offset/3;
3848
3849   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3850                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3851
3852   return TRUE;
3853
3854 }
3855
3856 static gboolean
3857 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3858                                   GdkEventMotion *event)
3859 {
3860   GtkAllocation allocation, button_allocation;
3861   GtkTreeView *tree_view = (GtkTreeView *) widget;
3862   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3863   gint x, y;
3864
3865   /* Sanity Check */
3866   if ((column == NULL) ||
3867       (event->window != tree_view->priv->drag_window))
3868     return FALSE;
3869
3870   /* Handle moving the header */
3871   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3872   gtk_widget_get_allocation (widget, &allocation);
3873   gtk_widget_get_allocation (column->button, &button_allocation);
3874   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3875              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
3876   gdk_window_move (tree_view->priv->drag_window, x, y);
3877   
3878   /* autoscroll, if needed */
3879   gtk_tree_view_horizontal_autoscroll (tree_view);
3880   /* Update the current reorder position and arrow; */
3881   gtk_tree_view_update_current_reorder (tree_view);
3882
3883   return TRUE;
3884 }
3885
3886 static void
3887 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3888 {
3889   remove_scroll_timeout (tree_view);
3890   gtk_grab_remove (GTK_WIDGET (tree_view));
3891
3892   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3893     {
3894       GtkTreePath *tmp_path;
3895
3896       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3897
3898       /* The anchor path should be set to the start path */
3899       tmp_path = _gtk_tree_view_find_path (tree_view,
3900                                            tree_view->priv->rubber_band_start_tree,
3901                                            tree_view->priv->rubber_band_start_node);
3902
3903       if (tree_view->priv->anchor)
3904         gtk_tree_row_reference_free (tree_view->priv->anchor);
3905
3906       tree_view->priv->anchor =
3907         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3908                                           tree_view->priv->model,
3909                                           tmp_path);
3910
3911       gtk_tree_path_free (tmp_path);
3912
3913       /* ... and the cursor to the end path */
3914       tmp_path = _gtk_tree_view_find_path (tree_view,
3915                                            tree_view->priv->rubber_band_end_tree,
3916                                            tree_view->priv->rubber_band_end_node);
3917       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3918       gtk_tree_path_free (tmp_path);
3919
3920       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3921     }
3922
3923   /* Clear status variables */
3924   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3925   tree_view->priv->rubber_band_shift = 0;
3926   tree_view->priv->rubber_band_ctrl = 0;
3927
3928   tree_view->priv->rubber_band_start_node = NULL;
3929   tree_view->priv->rubber_band_start_tree = NULL;
3930   tree_view->priv->rubber_band_end_node = NULL;
3931   tree_view->priv->rubber_band_end_tree = NULL;
3932 }
3933
3934 static void
3935 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3936                                                  GtkRBTree   *start_tree,
3937                                                  GtkRBNode   *start_node,
3938                                                  GtkRBTree   *end_tree,
3939                                                  GtkRBNode   *end_node,
3940                                                  gboolean     select,
3941                                                  gboolean     skip_start,
3942                                                  gboolean     skip_end)
3943 {
3944   if (start_node == end_node)
3945     return;
3946
3947   /* We skip the first node and jump inside the loop */
3948   if (skip_start)
3949     goto skip_first;
3950
3951   do
3952     {
3953       /* Small optimization by assuming insensitive nodes are never
3954        * selected.
3955        */
3956       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3957         {
3958           GtkTreePath *path;
3959           gboolean selectable;
3960
3961           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3962           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3963           gtk_tree_path_free (path);
3964
3965           if (!selectable)
3966             goto node_not_selectable;
3967         }
3968
3969       if (select)
3970         {
3971           if (tree_view->priv->rubber_band_shift)
3972             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3973           else if (tree_view->priv->rubber_band_ctrl)
3974             {
3975               /* Toggle the selection state */
3976               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3977                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3978               else
3979                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3980             }
3981           else
3982             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3983         }
3984       else
3985         {
3986           /* Mirror the above */
3987           if (tree_view->priv->rubber_band_shift)
3988             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3989           else if (tree_view->priv->rubber_band_ctrl)
3990             {
3991               /* Toggle the selection state */
3992               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3993                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3994               else
3995                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3996             }
3997           else
3998             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3999         }
4000
4001       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4002
4003 node_not_selectable:
4004       if (start_node == end_node)
4005         break;
4006
4007 skip_first:
4008
4009       if (start_node->children)
4010         {
4011           start_tree = start_node->children;
4012           start_node = start_tree->root;
4013           while (start_node->left != start_tree->nil)
4014             start_node = start_node->left;
4015         }
4016       else
4017         {
4018           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4019
4020           if (!start_tree)
4021             /* Ran out of tree */
4022             break;
4023         }
4024
4025       if (skip_end && start_node == end_node)
4026         break;
4027     }
4028   while (TRUE);
4029 }
4030
4031 static void
4032 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4033 {
4034   GtkRBTree *start_tree, *end_tree;
4035   GtkRBNode *start_node, *end_node;
4036
4037   _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);
4038   _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);
4039
4040   /* Handle the start area first */
4041   if (!tree_view->priv->rubber_band_start_node)
4042     {
4043       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4044                                                        start_tree,
4045                                                        start_node,
4046                                                        end_tree,
4047                                                        end_node,
4048                                                        TRUE,
4049                                                        FALSE,
4050                                                        FALSE);
4051     }
4052   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4053            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4054     {
4055       /* New node is above the old one; selection became bigger */
4056       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4057                                                        start_tree,
4058                                                        start_node,
4059                                                        tree_view->priv->rubber_band_start_tree,
4060                                                        tree_view->priv->rubber_band_start_node,
4061                                                        TRUE,
4062                                                        FALSE,
4063                                                        TRUE);
4064     }
4065   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4066            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4067     {
4068       /* New node is below the old one; selection became smaller */
4069       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4070                                                        tree_view->priv->rubber_band_start_tree,
4071                                                        tree_view->priv->rubber_band_start_node,
4072                                                        start_tree,
4073                                                        start_node,
4074                                                        FALSE,
4075                                                        FALSE,
4076                                                        TRUE);
4077     }
4078
4079   tree_view->priv->rubber_band_start_tree = start_tree;
4080   tree_view->priv->rubber_band_start_node = start_node;
4081
4082   /* Next, handle the end area */
4083   if (!tree_view->priv->rubber_band_end_node)
4084     {
4085       /* In the event this happens, start_node was also NULL; this case is
4086        * handled above.
4087        */
4088     }
4089   else if (!end_node)
4090     {
4091       /* Find the last node in the tree */
4092       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4093                                &end_tree, &end_node);
4094
4095       /* Selection reached end of the tree */
4096       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4097                                                        tree_view->priv->rubber_band_end_tree,
4098                                                        tree_view->priv->rubber_band_end_node,
4099                                                        end_tree,
4100                                                        end_node,
4101                                                        TRUE,
4102                                                        TRUE,
4103                                                        FALSE);
4104     }
4105   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4106            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4107     {
4108       /* New node is below the old one; selection became bigger */
4109       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4110                                                        tree_view->priv->rubber_band_end_tree,
4111                                                        tree_view->priv->rubber_band_end_node,
4112                                                        end_tree,
4113                                                        end_node,
4114                                                        TRUE,
4115                                                        TRUE,
4116                                                        FALSE);
4117     }
4118   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4119            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4120     {
4121       /* New node is above the old one; selection became smaller */
4122       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4123                                                        end_tree,
4124                                                        end_node,
4125                                                        tree_view->priv->rubber_band_end_tree,
4126                                                        tree_view->priv->rubber_band_end_node,
4127                                                        FALSE,
4128                                                        TRUE,
4129                                                        FALSE);
4130     }
4131
4132   tree_view->priv->rubber_band_end_tree = end_tree;
4133   tree_view->priv->rubber_band_end_node = end_node;
4134 }
4135
4136 static void
4137 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4138 {
4139   gint x, y;
4140   GdkRectangle old_area;
4141   GdkRectangle new_area;
4142   GdkRectangle common;
4143   cairo_region_t *invalid_region;
4144
4145   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4146   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4147   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4148   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4149
4150   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4151
4152   x = MAX (x, 0);
4153   y = MAX (y, 0) + tree_view->priv->dy;
4154
4155   new_area.x = MIN (tree_view->priv->press_start_x, x);
4156   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4157   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4158   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4159
4160   invalid_region = cairo_region_create_rectangle (&old_area);
4161   cairo_region_union_rectangle (invalid_region, &new_area);
4162
4163   gdk_rectangle_intersect (&old_area, &new_area, &common);
4164   if (common.width > 2 && common.height > 2)
4165     {
4166       cairo_region_t *common_region;
4167
4168       /* make sure the border is invalidated */
4169       common.x += 1;
4170       common.y += 1;
4171       common.width -= 2;
4172       common.height -= 2;
4173
4174       common_region = cairo_region_create_rectangle (&common);
4175
4176       cairo_region_subtract (invalid_region, common_region);
4177       cairo_region_destroy (common_region);
4178     }
4179
4180   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4181
4182   cairo_region_destroy (invalid_region);
4183
4184   tree_view->priv->rubber_band_x = x;
4185   tree_view->priv->rubber_band_y = y;
4186
4187   gtk_tree_view_update_rubber_band_selection (tree_view);
4188 }
4189
4190 static void
4191 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4192                                  cairo_t      *cr)
4193 {
4194   GdkRectangle rect;
4195   GtkStyle *style;
4196
4197   cairo_save (cr);
4198
4199   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4200   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4201   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4202   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4203
4204   cairo_set_line_width (cr, 1.0);
4205
4206   style = gtk_widget_get_style (GTK_WIDGET (tree_view));
4207
4208   gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
4209
4210   gdk_cairo_rectangle (cr, &rect);
4211   cairo_clip (cr);
4212   cairo_paint_with_alpha (cr, 0.25);
4213
4214   cairo_rectangle (cr,
4215                    rect.x + 0.5, rect.y + 0.5,
4216                    rect.width - 1, rect.height - 1);
4217   cairo_stroke (cr);
4218
4219   cairo_restore (cr);
4220 }
4221
4222 static gboolean
4223 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4224                                  GdkEventMotion *event)
4225 {
4226   GtkTreeView *tree_view;
4227   GtkRBTree *tree;
4228   GtkRBNode *node;
4229   gint new_y;
4230
4231   tree_view = (GtkTreeView *) widget;
4232
4233   if (tree_view->priv->tree == NULL)
4234     return FALSE;
4235
4236   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4237     {
4238       gtk_grab_add (GTK_WIDGET (tree_view));
4239       gtk_tree_view_update_rubber_band (tree_view);
4240
4241       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4242     }
4243   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4244     {
4245       gtk_tree_view_update_rubber_band (tree_view);
4246
4247       add_scroll_timeout (tree_view);
4248     }
4249
4250   /* only check for an initiated drag when a button is pressed */
4251   if (tree_view->priv->pressed_button >= 0
4252       && !tree_view->priv->rubber_band_status)
4253     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4254
4255   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4256   if (new_y < 0)
4257     new_y = 0;
4258
4259   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4260
4261   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4262   if ((tree_view->priv->button_pressed_node != NULL) &&
4263       (tree_view->priv->button_pressed_node != node))
4264     node = NULL;
4265
4266   tree_view->priv->event_last_x = event->x;
4267   tree_view->priv->event_last_y = event->y;
4268
4269   prelight_or_select (tree_view, tree, node, event->x, event->y);
4270
4271   return TRUE;
4272 }
4273
4274 static gboolean
4275 gtk_tree_view_motion (GtkWidget      *widget,
4276                       GdkEventMotion *event)
4277 {
4278   GtkTreeView *tree_view;
4279
4280   tree_view = (GtkTreeView *) widget;
4281
4282   /* Resizing a column */
4283   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4284     return gtk_tree_view_motion_resize_column (widget, event);
4285
4286   /* Drag column */
4287   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4288     return gtk_tree_view_motion_drag_column (widget, event);
4289
4290   /* Sanity check it */
4291   if (event->window == tree_view->priv->bin_window)
4292     return gtk_tree_view_motion_bin_window (widget, event);
4293
4294   return FALSE;
4295 }
4296
4297 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4298  * the tree is empty.
4299  */
4300 static void
4301 invalidate_empty_focus (GtkTreeView *tree_view)
4302 {
4303   GdkRectangle area;
4304
4305   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4306     return;
4307
4308   area.x = 0;
4309   area.y = 0;
4310   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4311   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4312   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4313 }
4314
4315 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4316  * is empty.
4317  */
4318 static void
4319 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4320 {
4321   GtkWidget *widget = GTK_WIDGET (tree_view);
4322   gint w, h;
4323
4324   if (!gtk_widget_has_focus (widget))
4325     return;
4326
4327   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4328   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4329
4330   if (w > 0 && h > 0)
4331     gtk_paint_focus (gtk_widget_get_style (widget),
4332                      cr,
4333                      gtk_widget_get_state (widget),
4334                      widget,
4335                      NULL,
4336                      1, 1, w, h);
4337 }
4338
4339 typedef enum {
4340   GTK_TREE_VIEW_GRID_LINE,
4341   GTK_TREE_VIEW_TREE_LINE,
4342   GTK_TREE_VIEW_FOREGROUND_LINE
4343 } GtkTreeViewLineType;
4344
4345 static void
4346 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4347                          cairo_t             *cr,
4348                          GtkTreeViewLineType  type,
4349                          int                  x1,
4350                          int                  y1,
4351                          int                  x2,
4352                          int                  y2)
4353 {
4354   cairo_save (cr);
4355
4356   switch (type)
4357     {
4358     case GTK_TREE_VIEW_TREE_LINE:
4359       cairo_set_source_rgb (cr, 0, 0, 0);
4360       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4361       if (tree_view->priv->tree_line_dashes[0])
4362         cairo_set_dash (cr, 
4363                         tree_view->priv->tree_line_dashes,
4364                         2, 0.5);
4365       break;
4366     case GTK_TREE_VIEW_GRID_LINE:
4367       cairo_set_source_rgb (cr, 0, 0, 0);
4368       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4369       if (tree_view->priv->grid_line_dashes[0])
4370         cairo_set_dash (cr, 
4371                         tree_view->priv->grid_line_dashes,
4372                         2, 0.5);
4373       break;
4374     default:
4375       g_assert_not_reached ();
4376       /* fall through */
4377     case GTK_TREE_VIEW_FOREGROUND_LINE:
4378       cairo_set_line_width (cr, 1.0);
4379       gdk_cairo_set_source_color (cr,
4380                                   &gtk_widget_get_style (GTK_WIDGET (tree_view))->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4381       break;
4382     }
4383
4384   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4385   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4386   cairo_stroke (cr);
4387
4388   cairo_restore (cr);
4389 }
4390                          
4391 static void
4392 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4393                                cairo_t        *cr,
4394                                gint            n_visible_columns)
4395 {
4396   GList *list = tree_view->priv->columns;
4397   gint i = 0;
4398   gint current_x = 0;
4399
4400   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4401       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4402     return;
4403
4404   /* Only draw the lines for visible rows and columns */
4405   for (list = tree_view->priv->columns; list; list = list->next, i++)
4406     {
4407       GtkTreeViewColumn *column = list->data;
4408
4409       /* We don't want a line for the last column */
4410       if (i == n_visible_columns - 1)
4411         break;
4412
4413       if (! column->visible)
4414         continue;
4415
4416       current_x += column->width;
4417
4418       gtk_tree_view_draw_line (tree_view, cr,
4419                                GTK_TREE_VIEW_GRID_LINE,
4420                                current_x - 1, 0,
4421                                current_x - 1, tree_view->priv->height);
4422     }
4423 }
4424
4425 /* Warning: Very scary function.
4426  * Modify at your own risk
4427  *
4428  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4429  * FIXME: It's not...
4430  */
4431 static gboolean
4432 gtk_tree_view_bin_draw (GtkWidget      *widget,
4433                         cairo_t        *cr)
4434 {
4435   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4436   GtkTreePath *path;
4437   GtkStyle *style;
4438   GtkRBTree *tree;
4439   GList *list;
4440   GtkRBNode *node;
4441   GtkRBNode *cursor = NULL;
4442   GtkRBTree *cursor_tree = NULL;
4443   GtkRBNode *drag_highlight = NULL;
4444   GtkRBTree *drag_highlight_tree = NULL;
4445   GtkTreeIter iter;
4446   gint new_y;
4447   gint y_offset, cell_offset;
4448   gint max_height;
4449   gint depth;
4450   GdkRectangle background_area;
4451   GdkRectangle cell_area;
4452   GdkRectangle clip;
4453   guint flags;
4454   gint highlight_x;
4455   gint expander_cell_width;
4456   gint bin_window_width;
4457   gint bin_window_height;
4458   GtkTreePath *cursor_path;
4459   GtkTreePath *drag_dest_path;
4460   GList *first_column, *last_column;
4461   gint vertical_separator;
4462   gint horizontal_separator;
4463   gint focus_line_width;
4464   gboolean allow_rules;
4465   gboolean has_special_cell;
4466   gboolean rtl;
4467   gint n_visible_columns;
4468   gint pointer_x, pointer_y;
4469   gint grid_line_width;
4470   gboolean got_pointer = FALSE;
4471   gboolean draw_vgrid_lines, draw_hgrid_lines;
4472
4473   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4474
4475   gtk_widget_style_get (widget,
4476                         "horizontal-separator", &horizontal_separator,
4477                         "vertical-separator", &vertical_separator,
4478                         "allow-rules", &allow_rules,
4479                         "focus-line-width", &focus_line_width,
4480                         NULL);
4481
4482   if (tree_view->priv->tree == NULL)
4483     {
4484       draw_empty_focus (tree_view, cr);
4485       return TRUE;
4486     }
4487
4488   style = gtk_widget_get_style (widget);
4489
4490   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4491   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4492   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4493   cairo_clip (cr);
4494   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4495     return TRUE;
4496
4497   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4498
4499   if (new_y < 0)
4500     new_y = 0;
4501   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4502
4503   if (tree_view->priv->height < bin_window_height)
4504     {
4505       gtk_paint_flat_box (style,
4506                           cr,
4507                           gtk_widget_get_state (widget),
4508                           GTK_SHADOW_NONE,
4509                           widget,
4510                           "cell_even",
4511                           0, tree_view->priv->height,
4512                           bin_window_width,
4513                           bin_window_height - tree_view->priv->height);
4514     }
4515
4516   if (node == NULL)
4517     return TRUE;
4518
4519   /* find the path for the node */
4520   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4521                                    tree,
4522                                    node);
4523   gtk_tree_model_get_iter (tree_view->priv->model,
4524                            &iter,
4525                            path);
4526   depth = gtk_tree_path_get_depth (path);
4527   gtk_tree_path_free (path);
4528   
4529   cursor_path = NULL;
4530   drag_dest_path = NULL;
4531
4532   if (tree_view->priv->cursor)
4533     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4534
4535   if (cursor_path)
4536     _gtk_tree_view_find_node (tree_view, cursor_path,
4537                               &cursor_tree, &cursor);
4538
4539   if (tree_view->priv->drag_dest_row)
4540     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4541
4542   if (drag_dest_path)
4543     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4544                               &drag_highlight_tree, &drag_highlight);
4545
4546   draw_vgrid_lines =
4547     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4548     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4549   draw_hgrid_lines =
4550     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4551     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4552
4553   if (draw_vgrid_lines || draw_hgrid_lines)
4554     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4555   
4556   n_visible_columns = 0;
4557   for (list = tree_view->priv->columns; list; list = list->next)
4558     {
4559       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4560         continue;
4561       n_visible_columns ++;
4562     }
4563
4564   /* Find the last column */
4565   for (last_column = g_list_last (tree_view->priv->columns);
4566        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4567        last_column = last_column->prev)
4568     ;
4569
4570   /* and the first */
4571   for (first_column = g_list_first (tree_view->priv->columns);
4572        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4573        first_column = first_column->next)
4574     ;
4575
4576   /* Actually process the expose event.  To do this, we want to
4577    * start at the first node of the event, and walk the tree in
4578    * order, drawing each successive node.
4579    */
4580
4581   do
4582     {
4583       gboolean parity;
4584       gboolean is_separator = FALSE;
4585       gboolean is_first = FALSE;
4586       gboolean is_last = FALSE;
4587       
4588       is_separator = row_is_separator (tree_view, &iter, NULL);
4589
4590       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4591
4592       cell_offset = 0;
4593       highlight_x = 0; /* should match x coord of first cell */
4594       expander_cell_width = 0;
4595
4596       background_area.y = y_offset + clip.y;
4597       background_area.height = max_height;
4598
4599       flags = 0;
4600
4601       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4602         flags |= GTK_CELL_RENDERER_PRELIT;
4603
4604       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4605         flags |= GTK_CELL_RENDERER_SELECTED;
4606
4607       parity = _gtk_rbtree_node_find_parity (tree, node);
4608
4609       /* we *need* to set cell data on all cells before the call
4610        * to _has_special_cell, else _has_special_cell() does not
4611        * return a correct value.
4612        */
4613       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4614            list;
4615            list = (rtl ? list->prev : list->next))
4616         {
4617           GtkTreeViewColumn *column = list->data;
4618           gtk_tree_view_column_cell_set_cell_data (column,
4619                                                    tree_view->priv->model,
4620                                                    &iter,
4621                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4622                                                    node->children?TRUE:FALSE);
4623         }
4624
4625       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4626
4627       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4628            list;
4629            list = (rtl ? list->prev : list->next))
4630         {
4631           GtkTreeViewColumn *column = list->data;
4632           const gchar *detail = NULL;
4633           gchar new_detail[128];
4634           GtkStateType state;
4635
4636           if (!column->visible)
4637             continue;
4638
4639           if (cell_offset > clip.x + clip.width ||
4640               cell_offset + column->width < clip.x)
4641             {
4642               cell_offset += column->width;
4643               continue;
4644             }
4645
4646           if (column->show_sort_indicator)
4647             flags |= GTK_CELL_RENDERER_SORTED;
4648           else
4649             flags &= ~GTK_CELL_RENDERER_SORTED;
4650
4651           if (cursor == node)
4652             flags |= GTK_CELL_RENDERER_FOCUSED;
4653           else
4654             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4655
4656           background_area.x = cell_offset;
4657           background_area.width = column->width;
4658
4659           cell_area = background_area;
4660           cell_area.y += vertical_separator / 2;
4661           cell_area.x += horizontal_separator / 2;
4662           cell_area.height -= vertical_separator;
4663           cell_area.width -= horizontal_separator;
4664
4665           if (draw_vgrid_lines)
4666             {
4667               if (list == first_column)
4668                 {
4669                   cell_area.width -= grid_line_width / 2;
4670                 }
4671               else if (list == last_column)
4672                 {
4673                   cell_area.x += grid_line_width / 2;
4674                   cell_area.width -= grid_line_width / 2;
4675                 }
4676               else
4677                 {
4678                   cell_area.x += grid_line_width / 2;
4679                   cell_area.width -= grid_line_width;
4680                 }
4681             }
4682
4683           if (draw_hgrid_lines)
4684             {
4685               cell_area.y += grid_line_width / 2;
4686               cell_area.height -= grid_line_width;
4687             }
4688
4689           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4690             {
4691               cell_offset += column->width;
4692               continue;
4693             }
4694
4695           gtk_tree_view_column_cell_set_cell_data (column,
4696                                                    tree_view->priv->model,
4697                                                    &iter,
4698                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4699                                                    node->children?TRUE:FALSE);
4700
4701           /* Select the detail for drawing the cell.  relevant
4702            * factors are parity, sortedness, and whether to
4703            * display rules.
4704            */
4705           if (allow_rules && tree_view->priv->has_rules)
4706             {
4707               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4708                   n_visible_columns >= 3)
4709                 {
4710                   if (parity)
4711                     detail = "cell_odd_ruled_sorted";
4712                   else
4713                     detail = "cell_even_ruled_sorted";
4714                 }
4715               else
4716                 {
4717                   if (parity)
4718                     detail = "cell_odd_ruled";
4719                   else
4720                     detail = "cell_even_ruled";
4721                 }
4722             }
4723           else
4724             {
4725               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4726                   n_visible_columns >= 3)
4727                 {
4728                   if (parity)
4729                     detail = "cell_odd_sorted";
4730                   else
4731                     detail = "cell_even_sorted";
4732                 }
4733               else
4734                 {
4735                   if (parity)
4736                     detail = "cell_odd";
4737                   else
4738                     detail = "cell_even";
4739                 }
4740             }
4741
4742           g_assert (detail);
4743
4744           if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
4745             state = GTK_STATE_INSENSITIVE;          
4746           else if (flags & GTK_CELL_RENDERER_SELECTED)
4747             state = GTK_STATE_SELECTED;
4748           else
4749             state = GTK_STATE_NORMAL;
4750
4751           /* Draw background */
4752           is_first = (rtl ? !list->next : !list->prev);
4753           is_last = (rtl ? !list->prev : !list->next);
4754
4755           /* (I don't like the snprintfs either, but couldn't find a
4756            * less messy way).
4757            */
4758           if (is_first && is_last)
4759             g_snprintf (new_detail, 127, "%s", detail);
4760           else if (is_first)
4761             g_snprintf (new_detail, 127, "%s_start", detail);
4762           else if (is_last)
4763             g_snprintf (new_detail, 127, "%s_end", detail);
4764           else
4765             g_snprintf (new_detail, 127, "%s_middle", detail);
4766
4767           gtk_paint_flat_box (style,
4768                               cr,
4769                               state,
4770                               GTK_SHADOW_NONE,
4771                               widget,
4772                               new_detail,
4773                               background_area.x,
4774                               background_area.y,
4775                               background_area.width,
4776                               background_area.height);
4777
4778           if (gtk_tree_view_is_expander_column (tree_view, column))
4779             {
4780               if (!rtl)
4781                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4782               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4783
4784               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4785                 {
4786                   if (!rtl)
4787                     cell_area.x += depth * tree_view->priv->expander_size;
4788                   cell_area.width -= depth * tree_view->priv->expander_size;
4789                 }
4790
4791               /* If we have an expander column, the highlight underline
4792                * starts with that column, so that it indicates which
4793                * level of the tree we're dropping at.
4794                */
4795               highlight_x = cell_area.x;
4796               expander_cell_width = cell_area.width;
4797
4798               if (is_separator)
4799                 gtk_paint_hline (style,
4800                                  cr,
4801                                  state,
4802                                  widget,
4803                                  NULL,
4804                                  cell_area.x,
4805                                  cell_area.x + cell_area.width,
4806                                  cell_area.y + cell_area.height / 2);
4807               else
4808                 _gtk_tree_view_column_cell_render (column,
4809                                                    cr,
4810                                                    &background_area,
4811                                                    &cell_area,
4812                                                    flags);
4813               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4814                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4815                 {
4816                   if (!got_pointer)
4817                     {
4818                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4819                                               &pointer_x, &pointer_y, NULL);
4820                       got_pointer = TRUE;
4821                     }
4822
4823                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4824                                             cr,
4825                                             tree,
4826                                             node,
4827                                             pointer_x, pointer_y);
4828                 }
4829             }
4830           else
4831             {
4832               if (is_separator)
4833                 gtk_paint_hline (style,
4834                                  cr,
4835                                  state,
4836                                  widget,
4837                                  NULL,
4838                                  cell_area.x,
4839                                  cell_area.x + cell_area.width,
4840                                  cell_area.y + cell_area.height / 2);
4841               else
4842                 _gtk_tree_view_column_cell_render (column,
4843                                                    cr,
4844                                                    &background_area,
4845                                                    &cell_area,
4846                                                    flags);
4847             }
4848
4849           if (draw_hgrid_lines)
4850             {
4851               if (background_area.y > 0)
4852                 gtk_tree_view_draw_line (tree_view, cr,
4853                                          GTK_TREE_VIEW_GRID_LINE,
4854                                          background_area.x, background_area.y,
4855                                          background_area.x + background_area.width,
4856                                          background_area.y);
4857
4858               if (y_offset + max_height >= clip.height)
4859                 gtk_tree_view_draw_line (tree_view, cr,
4860                                          GTK_TREE_VIEW_GRID_LINE,
4861                                          background_area.x, background_area.y + max_height,
4862                                          background_area.x + background_area.width,
4863                                          background_area.y + max_height);
4864             }
4865
4866           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4867               tree_view->priv->tree_lines_enabled)
4868             {
4869               gint x = background_area.x;
4870               gint mult = rtl ? -1 : 1;
4871               gint y0 = background_area.y;
4872               gint y1 = background_area.y + background_area.height/2;
4873               gint y2 = background_area.y + background_area.height;
4874
4875               if (rtl)
4876                 x += background_area.width - 1;
4877
4878               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4879                   && depth > 1)
4880                 {
4881                   gtk_tree_view_draw_line (tree_view, cr,
4882                                            GTK_TREE_VIEW_TREE_LINE,
4883                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4884                                            y1,
4885                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4886                                            y1);
4887                 }
4888               else if (depth > 1)
4889                 {
4890                   gtk_tree_view_draw_line (tree_view, cr,
4891                                            GTK_TREE_VIEW_TREE_LINE,
4892                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4893                                            y1,
4894                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4895                                            y1);
4896                 }
4897
4898               if (depth > 1)
4899                 {
4900                   gint i;
4901                   GtkRBNode *tmp_node;
4902                   GtkRBTree *tmp_tree;
4903
4904                   if (!_gtk_rbtree_next (tree, node))
4905                     gtk_tree_view_draw_line (tree_view, cr,
4906                                              GTK_TREE_VIEW_TREE_LINE,
4907                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4908                                              y0,
4909                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4910                                              y1);
4911                   else
4912                     gtk_tree_view_draw_line (tree_view, cr,
4913                                              GTK_TREE_VIEW_TREE_LINE,
4914                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4915                                              y0,
4916                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4917                                              y2);
4918
4919                   tmp_node = tree->parent_node;
4920                   tmp_tree = tree->parent_tree;
4921
4922                   for (i = depth - 2; i > 0; i--)
4923                     {
4924                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4925                         gtk_tree_view_draw_line (tree_view, cr,
4926                                                  GTK_TREE_VIEW_TREE_LINE,
4927                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4928                                                  y0,
4929                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4930                                                  y2);
4931
4932                       tmp_node = tmp_tree->parent_node;
4933                       tmp_tree = tmp_tree->parent_tree;
4934                     }
4935                 }
4936             }
4937
4938           if (node == cursor && has_special_cell &&
4939               ((column == tree_view->priv->focus_column &&
4940                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4941                 gtk_widget_has_focus (widget)) ||
4942                (column == tree_view->priv->edited_column)))
4943             {
4944               _gtk_tree_view_column_cell_draw_focus (column,
4945                                                      cr,
4946                                                      &background_area,
4947                                                      &cell_area,
4948                                                      flags);
4949             }
4950
4951           cell_offset += column->width;
4952         }
4953
4954       if (node == drag_highlight)
4955         {
4956           /* Draw indicator for the drop
4957            */
4958           gint highlight_y = -1;
4959           GtkRBTree *tree = NULL;
4960           GtkRBNode *node = NULL;
4961
4962           switch (tree_view->priv->drag_dest_pos)
4963             {
4964             case GTK_TREE_VIEW_DROP_BEFORE:
4965               highlight_y = background_area.y - 1;
4966               if (highlight_y < 0)
4967                       highlight_y = 0;
4968               break;
4969
4970             case GTK_TREE_VIEW_DROP_AFTER:
4971               highlight_y = background_area.y + background_area.height - 1;
4972               break;
4973
4974             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4975             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4976               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4977
4978               if (tree == NULL)
4979                 break;
4980
4981               gtk_paint_focus (style,
4982                                cr,
4983                                gtk_widget_get_state (widget),
4984                                widget,
4985                                (is_first
4986                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4987                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4988                                 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4989                                    - focus_line_width / 2,
4990                                 gdk_window_get_width (tree_view->priv->bin_window),
4991                                 ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4992                                    - focus_line_width + 1);
4993               break;
4994             }
4995
4996           if (highlight_y >= 0)
4997             {
4998               gtk_tree_view_draw_line (tree_view, cr,
4999                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5000                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5001                                        highlight_y,
5002                                        rtl ? 0 : bin_window_width,
5003                                        highlight_y);
5004             }
5005         }
5006
5007       /* draw the big row-spanning focus rectangle, if needed */
5008       if (!has_special_cell && node == cursor &&
5009           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
5010           gtk_widget_has_focus (widget))
5011         {
5012           gint tmp_y, tmp_height;
5013           GtkStateType focus_rect_state;
5014
5015           focus_rect_state =
5016             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
5017             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
5018              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
5019               GTK_STATE_NORMAL));
5020
5021           if (draw_hgrid_lines)
5022             {
5023               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
5024               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
5025             }
5026           else
5027             {
5028               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
5029               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
5030             }
5031
5032           gtk_paint_focus (style,
5033                            cr,
5034                            focus_rect_state,
5035                            widget,
5036                            (is_first
5037                             ? (is_last ? "treeview" : "treeview-left" )
5038                             : (is_last ? "treeview-right" : "treeview-middle" )),
5039                            0, tmp_y,
5040                            gdk_window_get_width (tree_view->priv->bin_window),
5041                            tmp_height);
5042         }
5043
5044       y_offset += max_height;
5045       if (node->children)
5046         {
5047           GtkTreeIter parent = iter;
5048           gboolean has_child;
5049
5050           tree = node->children;
5051           node = tree->root;
5052
5053           g_assert (node != tree->nil);
5054
5055           while (node->left != tree->nil)
5056             node = node->left;
5057           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5058                                                     &iter,
5059                                                     &parent);
5060           depth++;
5061
5062           /* Sanity Check! */
5063           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5064         }
5065       else
5066         {
5067           gboolean done = FALSE;
5068
5069           do
5070             {
5071               node = _gtk_rbtree_next (tree, node);
5072               if (node != NULL)
5073                 {
5074                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5075                   done = TRUE;
5076
5077                   /* Sanity Check! */
5078                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5079                 }
5080               else
5081                 {
5082                   GtkTreeIter parent_iter = iter;
5083                   gboolean has_parent;
5084
5085                   node = tree->parent_node;
5086                   tree = tree->parent_tree;
5087                   if (tree == NULL)
5088                     /* we should go to done to free some memory */
5089                     goto done;
5090                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5091                                                            &iter,
5092                                                            &parent_iter);
5093                   depth--;
5094
5095                   /* Sanity check */
5096                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5097                 }
5098             }
5099           while (!done);
5100         }
5101     }
5102   while (y_offset < clip.height);
5103
5104 done:
5105   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5106
5107   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5108     gtk_tree_view_paint_rubber_band (tree_view, cr);
5109
5110   if (cursor_path)
5111     gtk_tree_path_free (cursor_path);
5112
5113   if (drag_dest_path)
5114     gtk_tree_path_free (drag_dest_path);
5115
5116   return FALSE;
5117 }
5118
5119 static gboolean
5120 gtk_tree_view_draw (GtkWidget *widget,
5121                     cairo_t   *cr)
5122 {
5123   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5124
5125   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5126     {
5127       GList *tmp_list;
5128
5129       cairo_save (cr);
5130
5131       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5132
5133       gtk_tree_view_bin_draw (widget, cr);
5134
5135       cairo_restore (cr);
5136
5137       /* We can't just chain up to Container::draw as it will try to send the
5138        * event to the headers, so we handle propagating it to our children
5139        * (eg. widgets being edited) ourselves.
5140        */
5141       tmp_list = tree_view->priv->children;
5142       while (tmp_list)
5143         {
5144           GtkTreeViewChild *child = tmp_list->data;
5145           tmp_list = tmp_list->next;
5146
5147           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5148         }
5149     }
5150
5151   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5152     {
5153       GList *list;
5154       
5155       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5156         {
5157           GtkTreeViewColumn *column = list->data;
5158
5159           if (column == tree_view->priv->drag_column)
5160             continue;
5161
5162           if (column->visible)
5163             gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5164                                           column->button,
5165                                           cr);
5166         }
5167     }
5168   
5169   if (tree_view->priv->drag_window &&
5170       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5171     {
5172       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5173                                     tree_view->priv->drag_column->button,
5174                                     cr);
5175     }
5176
5177   return TRUE;
5178 }
5179
5180 enum
5181 {
5182   DROP_HOME,
5183   DROP_RIGHT,
5184   DROP_LEFT,
5185   DROP_END
5186 };
5187
5188 /* returns 0x1 when no column has been found -- yes it's hackish */
5189 static GtkTreeViewColumn *
5190 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5191                                GtkTreeViewColumn *column,
5192                                gint               drop_position)
5193 {
5194   GtkTreeViewColumn *left_column = NULL;
5195   GtkTreeViewColumn *cur_column = NULL;
5196   GList *tmp_list;
5197
5198   if (!column->reorderable)
5199     return (GtkTreeViewColumn *)0x1;
5200
5201   switch (drop_position)
5202     {
5203       case DROP_HOME:
5204         /* find first column where we can drop */
5205         tmp_list = tree_view->priv->columns;
5206         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5207           return (GtkTreeViewColumn *)0x1;
5208
5209         while (tmp_list)
5210           {
5211             g_assert (tmp_list);
5212
5213             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5214             tmp_list = tmp_list->next;
5215
5216             if (left_column && left_column->visible == FALSE)
5217               continue;
5218
5219             if (!tree_view->priv->column_drop_func)
5220               return left_column;
5221
5222             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5223               {
5224                 left_column = cur_column;
5225                 continue;
5226               }
5227
5228             return left_column;
5229           }
5230
5231         if (!tree_view->priv->column_drop_func)
5232           return left_column;
5233
5234         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5235           return left_column;
5236         else
5237           return (GtkTreeViewColumn *)0x1;
5238         break;
5239
5240       case DROP_RIGHT:
5241         /* find first column after column where we can drop */
5242         tmp_list = tree_view->priv->columns;
5243
5244         for (; tmp_list; tmp_list = tmp_list->next)
5245           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5246             break;
5247
5248         if (!tmp_list || !tmp_list->next)
5249           return (GtkTreeViewColumn *)0x1;
5250
5251         tmp_list = tmp_list->next;
5252         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5253         tmp_list = tmp_list->next;
5254
5255         while (tmp_list)
5256           {
5257             g_assert (tmp_list);
5258
5259             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5260             tmp_list = tmp_list->next;
5261
5262             if (left_column && left_column->visible == FALSE)
5263               {
5264                 left_column = cur_column;
5265                 if (tmp_list)
5266                   tmp_list = tmp_list->next;
5267                 continue;
5268               }
5269
5270             if (!tree_view->priv->column_drop_func)
5271               return left_column;
5272
5273             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5274               {
5275                 left_column = cur_column;
5276                 continue;
5277               }
5278
5279             return left_column;
5280           }
5281
5282         if (!tree_view->priv->column_drop_func)
5283           return left_column;
5284
5285         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5286           return left_column;
5287         else
5288           return (GtkTreeViewColumn *)0x1;
5289         break;
5290
5291       case DROP_LEFT:
5292         /* find first column before column where we can drop */
5293         tmp_list = tree_view->priv->columns;
5294
5295         for (; tmp_list; tmp_list = tmp_list->next)
5296           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5297             break;
5298
5299         if (!tmp_list || !tmp_list->prev)
5300           return (GtkTreeViewColumn *)0x1;
5301
5302         tmp_list = tmp_list->prev;
5303         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5304         tmp_list = tmp_list->prev;
5305
5306         while (tmp_list)
5307           {
5308             g_assert (tmp_list);
5309
5310             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5311
5312             if (left_column && !left_column->visible)
5313               {
5314                 /*if (!tmp_list->prev)
5315                   return (GtkTreeViewColumn *)0x1;
5316                   */
5317 /*
5318                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5319                 tmp_list = tmp_list->prev->prev;
5320                 continue;*/
5321
5322                 cur_column = left_column;
5323                 if (tmp_list)
5324                   tmp_list = tmp_list->prev;
5325                 continue;
5326               }
5327
5328             if (!tree_view->priv->column_drop_func)
5329               return left_column;
5330
5331             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5332               return left_column;
5333
5334             cur_column = left_column;
5335             tmp_list = tmp_list->prev;
5336           }
5337
5338         if (!tree_view->priv->column_drop_func)
5339           return NULL;
5340
5341         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5342           return NULL;
5343         else
5344           return (GtkTreeViewColumn *)0x1;
5345         break;
5346
5347       case DROP_END:
5348         /* same as DROP_HOME case, but doing it backwards */
5349         tmp_list = g_list_last (tree_view->priv->columns);
5350         cur_column = NULL;
5351
5352         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5353           return (GtkTreeViewColumn *)0x1;
5354
5355         while (tmp_list)
5356           {
5357             g_assert (tmp_list);
5358
5359             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5360
5361             if (left_column && !left_column->visible)
5362               {
5363                 cur_column = left_column;
5364                 tmp_list = tmp_list->prev;
5365               }
5366
5367             if (!tree_view->priv->column_drop_func)
5368               return left_column;
5369
5370             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5371               return left_column;
5372
5373             cur_column = left_column;
5374             tmp_list = tmp_list->prev;
5375           }
5376
5377         if (!tree_view->priv->column_drop_func)
5378           return NULL;
5379
5380         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5381           return NULL;
5382         else
5383           return (GtkTreeViewColumn *)0x1;
5384         break;
5385     }
5386
5387   return (GtkTreeViewColumn *)0x1;
5388 }
5389
5390 static gboolean
5391 gtk_tree_view_key_press (GtkWidget   *widget,
5392                          GdkEventKey *event)
5393 {
5394   GtkTreeView *tree_view = (GtkTreeView *) widget;
5395
5396   if (tree_view->priv->rubber_band_status)
5397     {
5398       if (event->keyval == GDK_KEY_Escape)
5399         gtk_tree_view_stop_rubber_band (tree_view);
5400
5401       return TRUE;
5402     }
5403
5404   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5405     {
5406       if (event->keyval == GDK_KEY_Escape)
5407         {
5408           tree_view->priv->cur_reorder = NULL;
5409           gtk_tree_view_button_release_drag_column (widget, NULL);
5410         }
5411       return TRUE;
5412     }
5413
5414   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5415     {
5416       GList *focus_column;
5417       gboolean rtl;
5418
5419       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5420
5421       for (focus_column = tree_view->priv->columns;
5422            focus_column;
5423            focus_column = focus_column->next)
5424         {
5425           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5426
5427           if (gtk_widget_has_focus (column->button))
5428             break;
5429         }
5430
5431       if (focus_column &&
5432           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5433           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5434            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5435         {
5436           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5437
5438           if (!column->resizable)
5439             {
5440               gtk_widget_error_bell (widget);
5441               return TRUE;
5442             }
5443
5444           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5445               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5446             {
5447               GtkRequisition button_req;
5448               gint old_width = column->resized_width;
5449
5450               gtk_widget_get_preferred_size (column->button, &button_req, NULL);
5451
5452               column->resized_width = MAX (column->resized_width,
5453                                            column->width);
5454               column->resized_width -= 2;
5455               if (column->resized_width < 0)
5456                 column->resized_width = 0;
5457
5458               if (column->min_width == -1)
5459                 column->resized_width = MAX (button_req.width,
5460                                              column->resized_width);
5461               else
5462                 {
5463                   column->resized_width = MAX (column->min_width,
5464                                                column->resized_width);
5465                 }
5466
5467               if (column->max_width != -1)
5468                 column->resized_width = MIN (column->resized_width,
5469                                              column->max_width);
5470
5471               column->use_resized_width = TRUE;
5472
5473               if (column->resized_width != old_width)
5474                 gtk_widget_queue_resize (widget);
5475               else
5476                 gtk_widget_error_bell (widget);
5477             }
5478           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5479                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5480             {
5481               gint old_width = column->resized_width;
5482
5483               column->resized_width = MAX (column->resized_width,
5484                                            column->width);
5485               column->resized_width += 2;
5486
5487               if (column->max_width != -1)
5488                 column->resized_width = MIN (column->resized_width,
5489                                              column->max_width);
5490
5491               column->use_resized_width = TRUE;
5492
5493               if (column->resized_width != old_width)
5494                 gtk_widget_queue_resize (widget);
5495               else
5496                 gtk_widget_error_bell (widget);
5497             }
5498
5499           return TRUE;
5500         }
5501
5502       if (focus_column &&
5503           (event->state & GDK_MOD1_MASK) &&
5504           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5505            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5506            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5507            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5508         {
5509           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5510
5511           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5512               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5513             {
5514               GtkTreeViewColumn *col;
5515               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5516               if (col != (GtkTreeViewColumn *)0x1)
5517                 gtk_tree_view_move_column_after (tree_view, column, col);
5518               else
5519                 gtk_widget_error_bell (widget);
5520             }
5521           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5522                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5523             {
5524               GtkTreeViewColumn *col;
5525               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5526               if (col != (GtkTreeViewColumn *)0x1)
5527                 gtk_tree_view_move_column_after (tree_view, column, col);
5528               else
5529                 gtk_widget_error_bell (widget);
5530             }
5531           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5532             {
5533               GtkTreeViewColumn *col;
5534               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5535               if (col != (GtkTreeViewColumn *)0x1)
5536                 gtk_tree_view_move_column_after (tree_view, column, col);
5537               else
5538                 gtk_widget_error_bell (widget);
5539             }
5540           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5541             {
5542               GtkTreeViewColumn *col;
5543               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5544               if (col != (GtkTreeViewColumn *)0x1)
5545                 gtk_tree_view_move_column_after (tree_view, column, col);
5546               else
5547                 gtk_widget_error_bell (widget);
5548             }
5549
5550           return TRUE;
5551         }
5552     }
5553
5554   /* Chain up to the parent class.  It handles the keybindings. */
5555   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5556     return TRUE;
5557
5558   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5559     {
5560       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5561       return FALSE;
5562     }
5563
5564   /* We pass the event to the search_entry.  If its text changes, then we start
5565    * the typeahead find capabilities. */
5566   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5567       && tree_view->priv->enable_search
5568       && !tree_view->priv->search_custom_entry_set)
5569     {
5570       GdkEvent *new_event;
5571       char *old_text;
5572       const char *new_text;
5573       gboolean retval;
5574       GdkScreen *screen;
5575       gboolean text_modified;
5576       gulong popup_menu_id;
5577
5578       gtk_tree_view_ensure_interactive_directory (tree_view);
5579
5580       /* Make a copy of the current text */
5581       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5582       new_event = gdk_event_copy ((GdkEvent *) event);
5583       g_object_unref (((GdkEventKey *) new_event)->window);
5584       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5585       gtk_widget_realize (tree_view->priv->search_window);
5586
5587       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5588                                         "popup-menu", G_CALLBACK (gtk_true),
5589                                         NULL);
5590
5591       /* Move the entry off screen */
5592       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5593       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5594                        gdk_screen_get_width (screen) + 1,
5595                        gdk_screen_get_height (screen) + 1);
5596       gtk_widget_show (tree_view->priv->search_window);
5597
5598       /* Send the event to the window.  If the preedit_changed signal is emitted
5599        * during this event, we will set priv->imcontext_changed  */
5600       tree_view->priv->imcontext_changed = FALSE;
5601       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5602       gdk_event_free (new_event);
5603       gtk_widget_hide (tree_view->priv->search_window);
5604
5605       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5606                                    popup_menu_id);
5607
5608       /* We check to make sure that the entry tried to handle the text, and that
5609        * the text has changed.
5610        */
5611       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5612       text_modified = strcmp (old_text, new_text) != 0;
5613       g_free (old_text);
5614       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5615           (retval && text_modified))               /* ...or the text was modified */
5616         {
5617           if (gtk_tree_view_real_start_interactive_search (tree_view,
5618                                                            gdk_event_get_device ((GdkEvent *) event),
5619                                                            FALSE))
5620             {
5621               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5622               return TRUE;
5623             }
5624           else
5625             {
5626               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5627               return FALSE;
5628             }
5629         }
5630     }
5631
5632   return FALSE;
5633 }
5634
5635 static gboolean
5636 gtk_tree_view_key_release (GtkWidget   *widget,
5637                            GdkEventKey *event)
5638 {
5639   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5640
5641   if (tree_view->priv->rubber_band_status)
5642     return TRUE;
5643
5644   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5645 }
5646
5647 /* FIXME Is this function necessary? Can I get an enter_notify event
5648  * w/o either an expose event or a mouse motion event?
5649  */
5650 static gboolean
5651 gtk_tree_view_enter_notify (GtkWidget        *widget,
5652                             GdkEventCrossing *event)
5653 {
5654   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5655   GtkRBTree *tree;
5656   GtkRBNode *node;
5657   gint new_y;
5658
5659   /* Sanity check it */
5660   if (event->window != tree_view->priv->bin_window)
5661     return FALSE;
5662
5663   if (tree_view->priv->tree == NULL)
5664     return FALSE;
5665
5666   if (event->mode == GDK_CROSSING_GRAB ||
5667       event->mode == GDK_CROSSING_GTK_GRAB ||
5668       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5669       event->mode == GDK_CROSSING_STATE_CHANGED)
5670     return TRUE;
5671
5672   /* find the node internally */
5673   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5674   if (new_y < 0)
5675     new_y = 0;
5676   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5677
5678   tree_view->priv->event_last_x = event->x;
5679   tree_view->priv->event_last_y = event->y;
5680
5681   if ((tree_view->priv->button_pressed_node == NULL) ||
5682       (tree_view->priv->button_pressed_node == node))
5683     prelight_or_select (tree_view, tree, node, event->x, event->y);
5684
5685   return TRUE;
5686 }
5687
5688 static gboolean
5689 gtk_tree_view_leave_notify (GtkWidget        *widget,
5690                             GdkEventCrossing *event)
5691 {
5692   GtkTreeView *tree_view;
5693
5694   if (event->mode == GDK_CROSSING_GRAB)
5695     return TRUE;
5696
5697   tree_view = GTK_TREE_VIEW (widget);
5698
5699   if (tree_view->priv->prelight_node)
5700     _gtk_tree_view_queue_draw_node (tree_view,
5701                                    tree_view->priv->prelight_tree,
5702                                    tree_view->priv->prelight_node,
5703                                    NULL);
5704
5705   tree_view->priv->event_last_x = -10000;
5706   tree_view->priv->event_last_y = -10000;
5707
5708   prelight_or_select (tree_view,
5709                       NULL, NULL,
5710                       -1000, -1000); /* coords not possibly over an arrow */
5711
5712   return TRUE;
5713 }
5714
5715
5716 static gint
5717 gtk_tree_view_focus_out (GtkWidget     *widget,
5718                          GdkEventFocus *event)
5719 {
5720   GtkTreeView *tree_view;
5721
5722   tree_view = GTK_TREE_VIEW (widget);
5723
5724   gtk_widget_queue_draw (widget);
5725
5726   /* destroy interactive search dialog */
5727   if (tree_view->priv->search_window)
5728     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5729                                       gdk_event_get_device ((GdkEvent *) event));
5730
5731   return FALSE;
5732 }
5733
5734
5735 /* Incremental Reflow
5736  */
5737
5738 static void
5739 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5740                                  GtkRBTree   *tree,
5741                                  GtkRBNode   *node)
5742 {
5743   GtkAllocation allocation;
5744   gint y;
5745
5746   y = _gtk_rbtree_node_find_offset (tree, node)
5747     - tree_view->priv->vadjustment->value
5748     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5749
5750   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5751   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5752                               0, y,
5753                               allocation.width,
5754                               GTK_RBNODE_GET_HEIGHT (node));
5755 }
5756
5757 static gboolean
5758 node_is_visible (GtkTreeView *tree_view,
5759                  GtkRBTree   *tree,
5760                  GtkRBNode   *node)
5761 {
5762   int y;
5763   int height;
5764
5765   y = _gtk_rbtree_node_find_offset (tree, node);
5766   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5767
5768   if (y >= tree_view->priv->vadjustment->value &&
5769       y + height <= (tree_view->priv->vadjustment->value
5770                      + tree_view->priv->vadjustment->page_size))
5771     return TRUE;
5772
5773   return FALSE;
5774 }
5775
5776 /* Returns TRUE if it updated the size
5777  */
5778 static gboolean
5779 validate_row (GtkTreeView *tree_view,
5780               GtkRBTree   *tree,
5781               GtkRBNode   *node,
5782               GtkTreeIter *iter,
5783               GtkTreePath *path)
5784 {
5785   GtkTreeViewColumn *column;
5786   GList *list, *first_column, *last_column;
5787   gint height = 0;
5788   gint horizontal_separator;
5789   gint vertical_separator;
5790   gint focus_line_width;
5791   gint depth = gtk_tree_path_get_depth (path);
5792   gboolean retval = FALSE;
5793   gboolean is_separator = FALSE;
5794   gboolean draw_vgrid_lines, draw_hgrid_lines;
5795   gint focus_pad;
5796   gint grid_line_width;
5797   gboolean wide_separators;
5798   gint separator_height;
5799
5800   /* double check the row needs validating */
5801   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5802       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5803     return FALSE;
5804
5805   is_separator = row_is_separator (tree_view, iter, NULL);
5806
5807   gtk_widget_style_get (GTK_WIDGET (tree_view),
5808                         "focus-padding", &focus_pad,
5809                         "focus-line-width", &focus_line_width,
5810                         "horizontal-separator", &horizontal_separator,
5811                         "vertical-separator", &vertical_separator,
5812                         "grid-line-width", &grid_line_width,
5813                         "wide-separators",  &wide_separators,
5814                         "separator-height", &separator_height,
5815                         NULL);
5816   
5817   draw_vgrid_lines =
5818     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5819     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5820   draw_hgrid_lines =
5821     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5822     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5823
5824   for (last_column = g_list_last (tree_view->priv->columns);
5825        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5826        last_column = last_column->prev)
5827     ;
5828
5829   for (first_column = g_list_first (tree_view->priv->columns);
5830        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5831        first_column = first_column->next)
5832     ;
5833
5834   for (list = tree_view->priv->columns; list; list = list->next)
5835     {
5836       gint tmp_width;
5837       gint tmp_height;
5838
5839       column = list->data;
5840
5841       if (! column->visible)
5842         continue;
5843
5844       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5845         continue;
5846
5847       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5848                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5849                                                node->children?TRUE:FALSE);
5850       gtk_tree_view_column_cell_get_size (column,
5851                                           NULL, NULL, NULL,
5852                                           &tmp_width, &tmp_height);
5853
5854       if (!is_separator)
5855         {
5856           tmp_height += vertical_separator;
5857           height = MAX (height, tmp_height);
5858           height = MAX (height, tree_view->priv->expander_size);
5859         }
5860       else
5861         {
5862           if (wide_separators)
5863             height = separator_height + 2 * focus_pad;
5864           else
5865             height = 2 + 2 * focus_pad;
5866         }
5867
5868       if (gtk_tree_view_is_expander_column (tree_view, column))
5869         {
5870           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5871
5872           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5873             tmp_width += depth * tree_view->priv->expander_size;
5874         }
5875       else
5876         tmp_width = tmp_width + horizontal_separator;
5877
5878       if (draw_vgrid_lines)
5879         {
5880           if (list->data == first_column || list->data == last_column)
5881             tmp_width += grid_line_width / 2.0;
5882           else
5883             tmp_width += grid_line_width;
5884         }
5885
5886       if (tmp_width > column->requested_width)
5887         {
5888           retval = TRUE;
5889           column->requested_width = tmp_width;
5890         }
5891     }
5892
5893   if (draw_hgrid_lines)
5894     height += grid_line_width;
5895
5896   if (height != GTK_RBNODE_GET_HEIGHT (node))
5897     {
5898       retval = TRUE;
5899       _gtk_rbtree_node_set_height (tree, node, height);
5900     }
5901   _gtk_rbtree_node_mark_valid (tree, node);
5902   tree_view->priv->post_validation_flag = TRUE;
5903
5904   return retval;
5905 }
5906
5907
5908 static void
5909 validate_visible_area (GtkTreeView *tree_view)
5910 {
5911   GtkAllocation allocation;
5912   GtkTreePath *path = NULL;
5913   GtkTreePath *above_path = NULL;
5914   GtkTreeIter iter;
5915   GtkRBTree *tree = NULL;
5916   GtkRBNode *node = NULL;
5917   gboolean need_redraw = FALSE;
5918   gboolean size_changed = FALSE;
5919   gint total_height;
5920   gint area_above = 0;
5921   gint area_below = 0;
5922
5923   if (tree_view->priv->tree == NULL)
5924     return;
5925
5926   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5927       tree_view->priv->scroll_to_path == NULL)
5928     return;
5929
5930   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5931   total_height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5932
5933   if (total_height == 0)
5934     return;
5935
5936   /* First, we check to see if we need to scroll anywhere
5937    */
5938   if (tree_view->priv->scroll_to_path)
5939     {
5940       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5941       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5942         {
5943           /* we are going to scroll, and will update dy */
5944           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5945           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5946               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5947             {
5948               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5949               if (validate_row (tree_view, tree, node, &iter, path))
5950                 size_changed = TRUE;
5951             }
5952
5953           if (tree_view->priv->scroll_to_use_align)
5954             {
5955               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5956               area_above = (total_height - height) *
5957                 tree_view->priv->scroll_to_row_align;
5958               area_below = total_height - area_above - height;
5959               area_above = MAX (area_above, 0);
5960               area_below = MAX (area_below, 0);
5961             }
5962           else
5963             {
5964               /* two cases:
5965                * 1) row not visible
5966                * 2) row visible
5967                */
5968               gint dy;
5969               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5970
5971               dy = _gtk_rbtree_node_find_offset (tree, node);
5972
5973               if (dy >= tree_view->priv->vadjustment->value &&
5974                   dy + height <= (tree_view->priv->vadjustment->value
5975                                   + tree_view->priv->vadjustment->page_size))
5976                 {
5977                   /* row visible: keep the row at the same position */
5978                   area_above = dy - tree_view->priv->vadjustment->value;
5979                   area_below = (tree_view->priv->vadjustment->value +
5980                                 tree_view->priv->vadjustment->page_size)
5981                                - dy - height;
5982                 }
5983               else
5984                 {
5985                   /* row not visible */
5986                   if (dy >= 0
5987                       && dy + height <= tree_view->priv->vadjustment->page_size)
5988                     {
5989                       /* row at the beginning -- fixed */
5990                       area_above = dy;
5991                       area_below = tree_view->priv->vadjustment->page_size
5992                                    - area_above - height;
5993                     }
5994                   else if (dy >= (tree_view->priv->vadjustment->upper -
5995                                   tree_view->priv->vadjustment->page_size))
5996                     {
5997                       /* row at the end -- fixed */
5998                       area_above = dy - (tree_view->priv->vadjustment->upper -
5999                                    tree_view->priv->vadjustment->page_size);
6000                       area_below = tree_view->priv->vadjustment->page_size -
6001                                    area_above - height;
6002
6003                       if (area_below < 0)
6004                         {
6005                           area_above = tree_view->priv->vadjustment->page_size - height;
6006                           area_below = 0;
6007                         }
6008                     }
6009                   else
6010                     {
6011                       /* row somewhere in the middle, bring it to the top
6012                        * of the view
6013                        */
6014                       area_above = 0;
6015                       area_below = total_height - height;
6016                     }
6017                 }
6018             }
6019         }
6020       else
6021         /* the scroll to isn't valid; ignore it.
6022          */
6023         {
6024           if (tree_view->priv->scroll_to_path && !path)
6025             {
6026               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6027               tree_view->priv->scroll_to_path = NULL;
6028             }
6029           if (path)
6030             gtk_tree_path_free (path);
6031           path = NULL;
6032         }      
6033     }
6034
6035   /* We didn't have a scroll_to set, so we just handle things normally
6036    */
6037   if (path == NULL)
6038     {
6039       gint offset;
6040
6041       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6042                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6043                                         &tree, &node);
6044       if (node == NULL)
6045         {
6046           /* In this case, nothing has been validated */
6047           path = gtk_tree_path_new_first ();
6048           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6049         }
6050       else
6051         {
6052           path = _gtk_tree_view_find_path (tree_view, tree, node);
6053           total_height += offset;
6054         }
6055
6056       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6057
6058       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6059           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6060         {
6061           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6062           if (validate_row (tree_view, tree, node, &iter, path))
6063             size_changed = TRUE;
6064         }
6065       area_above = 0;
6066       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6067     }
6068
6069   above_path = gtk_tree_path_copy (path);
6070
6071   /* if we do not validate any row above the new top_row, we will make sure
6072    * that the row immediately above top_row has been validated. (if we do not
6073    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6074    * when invalidated that row's height will be zero. and this will mess up
6075    * scrolling).
6076    */
6077   if (area_above == 0)
6078     {
6079       GtkRBTree *tmptree;
6080       GtkRBNode *tmpnode;
6081
6082       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6083       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6084
6085       if (tmpnode)
6086         {
6087           GtkTreePath *tmppath;
6088           GtkTreeIter tmpiter;
6089
6090           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6091           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6092
6093           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6094               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6095             {
6096               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6097               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6098                 size_changed = TRUE;
6099             }
6100
6101           gtk_tree_path_free (tmppath);
6102         }
6103     }
6104
6105   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6106    * backwards is much slower then forward, as there is no iter_prev function.
6107    * We go forwards first in case we run out of tree.  Then we go backwards to
6108    * fill out the top.
6109    */
6110   while (node && area_below > 0)
6111     {
6112       if (node->children)
6113         {
6114           GtkTreeIter parent = iter;
6115           gboolean has_child;
6116
6117           tree = node->children;
6118           node = tree->root;
6119
6120           g_assert (node != tree->nil);
6121
6122           while (node->left != tree->nil)
6123             node = node->left;
6124           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6125                                                     &iter,
6126                                                     &parent);
6127           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6128           gtk_tree_path_down (path);
6129         }
6130       else
6131         {
6132           gboolean done = FALSE;
6133           do
6134             {
6135               node = _gtk_rbtree_next (tree, node);
6136               if (node != NULL)
6137                 {
6138                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6139                   done = TRUE;
6140                   gtk_tree_path_next (path);
6141
6142                   /* Sanity Check! */
6143                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6144                 }
6145               else
6146                 {
6147                   GtkTreeIter parent_iter = iter;
6148                   gboolean has_parent;
6149
6150                   node = tree->parent_node;
6151                   tree = tree->parent_tree;
6152                   if (tree == NULL)
6153                     break;
6154                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6155                                                            &iter,
6156                                                            &parent_iter);
6157                   gtk_tree_path_up (path);
6158
6159                   /* Sanity check */
6160                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6161                 }
6162             }
6163           while (!done);
6164         }
6165
6166       if (!node)
6167         break;
6168
6169       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6170           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6171         {
6172           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6173           if (validate_row (tree_view, tree, node, &iter, path))
6174               size_changed = TRUE;
6175         }
6176
6177       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6178     }
6179   gtk_tree_path_free (path);
6180
6181   /* If we ran out of tree, and have extra area_below left, we need to add it
6182    * to area_above */
6183   if (area_below > 0)
6184     area_above += area_below;
6185
6186   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6187
6188   /* We walk backwards */
6189   while (area_above > 0)
6190     {
6191       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6192
6193       /* Always find the new path in the tree.  We cannot just assume
6194        * a gtk_tree_path_prev() is enough here, as there might be children
6195        * in between this node and the previous sibling node.  If this
6196        * appears to be a performance hotspot in profiles, we can look into
6197        * intrigate logic for keeping path, node and iter in sync like
6198        * we do for forward walks.  (Which will be hard because of the lacking
6199        * iter_prev).
6200        */
6201
6202       if (node == NULL)
6203         break;
6204
6205       gtk_tree_path_free (above_path);
6206       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6207
6208       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6209
6210       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6211           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6212         {
6213           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6214           if (validate_row (tree_view, tree, node, &iter, above_path))
6215             size_changed = TRUE;
6216         }
6217       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6218     }
6219
6220   /* if we scrolled to a path, we need to set the dy here,
6221    * and sync the top row accordingly
6222    */
6223   if (tree_view->priv->scroll_to_path)
6224     {
6225       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6226       gtk_tree_view_top_row_to_dy (tree_view);
6227
6228       need_redraw = TRUE;
6229     }
6230   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6231     {
6232       /* when we are not scrolling, we should never set dy to something
6233        * else than zero. we update top_row to be in sync with dy = 0.
6234        */
6235       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6236       gtk_tree_view_dy_to_top_row (tree_view);
6237     }
6238   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6239     {
6240       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6241       gtk_tree_view_dy_to_top_row (tree_view);
6242     }
6243   else
6244     gtk_tree_view_top_row_to_dy (tree_view);
6245
6246   /* update width/height and queue a resize */
6247   if (size_changed)
6248     {
6249       GtkRequisition requisition;
6250
6251       /* We temporarily guess a size, under the assumption that it will be the
6252        * same when we get our next size_allocate.  If we don't do this, we'll be
6253        * in an inconsistent state if we call top_row_to_dy. */
6254
6255       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6256                                      &requisition, NULL);
6257       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6258       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6259       gtk_adjustment_changed (tree_view->priv->hadjustment);
6260       gtk_adjustment_changed (tree_view->priv->vadjustment);
6261       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6262     }
6263
6264   if (tree_view->priv->scroll_to_path)
6265     {
6266       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6267       tree_view->priv->scroll_to_path = NULL;
6268     }
6269
6270   if (above_path)
6271     gtk_tree_path_free (above_path);
6272
6273   if (tree_view->priv->scroll_to_column)
6274     {
6275       tree_view->priv->scroll_to_column = NULL;
6276     }
6277   if (need_redraw)
6278     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6279 }
6280
6281 static void
6282 initialize_fixed_height_mode (GtkTreeView *tree_view)
6283 {
6284   if (!tree_view->priv->tree)
6285     return;
6286
6287   if (tree_view->priv->fixed_height < 0)
6288     {
6289       GtkTreeIter iter;
6290       GtkTreePath *path;
6291
6292       GtkRBTree *tree = NULL;
6293       GtkRBNode *node = NULL;
6294
6295       tree = tree_view->priv->tree;
6296       node = tree->root;
6297
6298       path = _gtk_tree_view_find_path (tree_view, tree, node);
6299       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6300
6301       validate_row (tree_view, tree, node, &iter, path);
6302
6303       gtk_tree_path_free (path);
6304
6305       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6306     }
6307
6308    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6309                                  tree_view->priv->fixed_height, TRUE);
6310 }
6311
6312 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6313  * the left-most uninvalidated node.  We then try walking right, validating
6314  * nodes.  Once we find a valid node, we repeat the previous process of finding
6315  * the first invalid node.
6316  */
6317
6318 static gboolean
6319 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6320 {
6321   GtkRBTree *tree = NULL;
6322   GtkRBNode *node = NULL;
6323   gboolean validated_area = FALSE;
6324   gint retval = TRUE;
6325   GtkTreePath *path = NULL;
6326   GtkTreeIter iter;
6327   GTimer *timer;
6328   gint i = 0;
6329
6330   gint prev_height = -1;
6331   gboolean fixed_height = TRUE;
6332
6333   g_assert (tree_view);
6334
6335   if (tree_view->priv->tree == NULL)
6336       return FALSE;
6337
6338   if (tree_view->priv->fixed_height_mode)
6339     {
6340       if (tree_view->priv->fixed_height < 0)
6341         initialize_fixed_height_mode (tree_view);
6342
6343       return FALSE;
6344     }
6345
6346   timer = g_timer_new ();
6347   g_timer_start (timer);
6348
6349   do
6350     {
6351       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6352         {
6353           retval = FALSE;
6354           goto done;
6355         }
6356
6357       if (path != NULL)
6358         {
6359           node = _gtk_rbtree_next (tree, node);
6360           if (node != NULL)
6361             {
6362               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6363               gtk_tree_path_next (path);
6364             }
6365           else
6366             {
6367               gtk_tree_path_free (path);
6368               path = NULL;
6369             }
6370         }
6371
6372       if (path == NULL)
6373         {
6374           tree = tree_view->priv->tree;
6375           node = tree_view->priv->tree->root;
6376
6377           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6378
6379           do
6380             {
6381               if (node->left != tree->nil &&
6382                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6383                 {
6384                   node = node->left;
6385                 }
6386               else if (node->right != tree->nil &&
6387                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6388                 {
6389                   node = node->right;
6390                 }
6391               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6392                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6393                 {
6394                   break;
6395                 }
6396               else if (node->children != NULL)
6397                 {
6398                   tree = node->children;
6399                   node = tree->root;
6400                 }
6401               else
6402                 /* RBTree corruption!  All bad */
6403                 g_assert_not_reached ();
6404             }
6405           while (TRUE);
6406           path = _gtk_tree_view_find_path (tree_view, tree, node);
6407           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6408         }
6409
6410       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6411                        validated_area;
6412
6413       if (!tree_view->priv->fixed_height_check)
6414         {
6415           gint height;
6416
6417           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6418           if (prev_height < 0)
6419             prev_height = height;
6420           else if (prev_height != height)
6421             fixed_height = FALSE;
6422         }
6423
6424       i++;
6425     }
6426   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6427
6428   if (!tree_view->priv->fixed_height_check)
6429    {
6430      if (fixed_height)
6431        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6432
6433      tree_view->priv->fixed_height_check = 1;
6434    }
6435   
6436  done:
6437   if (validated_area)
6438     {
6439       GtkRequisition requisition;
6440
6441       /* We temporarily guess a size, under the assumption that it will be the
6442        * same when we get our next size_allocate.  If we don't do this, we'll be
6443        * in an inconsistent state when we call top_row_to_dy. */
6444
6445       /* FIXME: This is called from size_request, for some reason it is not infinitely
6446        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6447        * not allowed (from inside ->get_preferred_width/height() implementations, one
6448        * should call the vfuncs directly). However what is desired here is the full
6449        * size including any margins and limited by any alignment (i.e. after 
6450        * GtkWidget:adjust_size_request() is called).
6451        *
6452        * Currently bypassing this but the real solution is to not update the scroll adjustments
6453        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6454        */
6455       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition);
6456
6457       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6458       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6459       gtk_adjustment_changed (tree_view->priv->hadjustment);
6460       gtk_adjustment_changed (tree_view->priv->vadjustment);
6461
6462       if (queue_resize)
6463         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6464     }
6465
6466   if (path) gtk_tree_path_free (path);
6467   g_timer_destroy (timer);
6468
6469   return retval;
6470 }
6471
6472 static gboolean
6473 validate_rows (GtkTreeView *tree_view)
6474 {
6475   gboolean retval;
6476   
6477   retval = do_validate_rows (tree_view, TRUE);
6478   
6479   if (! retval && tree_view->priv->validate_rows_timer)
6480     {
6481       g_source_remove (tree_view->priv->validate_rows_timer);
6482       tree_view->priv->validate_rows_timer = 0;
6483     }
6484
6485   return retval;
6486 }
6487
6488 static gboolean
6489 validate_rows_handler (GtkTreeView *tree_view)
6490 {
6491   gboolean retval;
6492
6493   retval = do_validate_rows (tree_view, TRUE);
6494   if (! retval && tree_view->priv->validate_rows_timer)
6495     {
6496       g_source_remove (tree_view->priv->validate_rows_timer);
6497       tree_view->priv->validate_rows_timer = 0;
6498     }
6499
6500   return retval;
6501 }
6502
6503 static gboolean
6504 do_presize_handler (GtkTreeView *tree_view)
6505 {
6506   if (tree_view->priv->mark_rows_col_dirty)
6507     {
6508       if (tree_view->priv->tree)
6509         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6510       tree_view->priv->mark_rows_col_dirty = FALSE;
6511     }
6512   validate_visible_area (tree_view);
6513   tree_view->priv->presize_handler_timer = 0;
6514
6515   if (tree_view->priv->fixed_height_mode)
6516     {
6517       GtkRequisition requisition;
6518
6519       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6520                                      &requisition, NULL);
6521
6522       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6523       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6524       gtk_adjustment_changed (tree_view->priv->hadjustment);
6525       gtk_adjustment_changed (tree_view->priv->vadjustment);
6526       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6527     }
6528                    
6529   return FALSE;
6530 }
6531
6532 static gboolean
6533 presize_handler_callback (gpointer data)
6534 {
6535   do_presize_handler (GTK_TREE_VIEW (data));
6536                    
6537   return FALSE;
6538 }
6539
6540 static void
6541 install_presize_handler (GtkTreeView *tree_view)
6542 {
6543   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6544     return;
6545
6546   if (! tree_view->priv->presize_handler_timer)
6547     {
6548       tree_view->priv->presize_handler_timer =
6549         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6550     }
6551   if (! tree_view->priv->validate_rows_timer)
6552     {
6553       tree_view->priv->validate_rows_timer =
6554         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6555     }
6556 }
6557
6558 static void
6559 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6560 {
6561   /* Prior to drawing, we make sure the visible area is validated. */
6562   if (tree_view->priv->presize_handler_timer)
6563     {
6564       g_source_remove (tree_view->priv->presize_handler_timer);
6565       tree_view->priv->presize_handler_timer = 0;
6566
6567       do_presize_handler (tree_view);
6568     }
6569
6570   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6571 }
6572
6573 static gboolean
6574 scroll_sync_handler (GtkTreeView *tree_view)
6575 {
6576   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6577     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6578   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6579     gtk_tree_view_top_row_to_dy (tree_view);
6580   else
6581     gtk_tree_view_dy_to_top_row (tree_view);
6582
6583   tree_view->priv->scroll_sync_timer = 0;
6584
6585   return FALSE;
6586 }
6587
6588 static void
6589 install_scroll_sync_handler (GtkTreeView *tree_view)
6590 {
6591   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6592     return;
6593
6594   if (!tree_view->priv->scroll_sync_timer)
6595     {
6596       tree_view->priv->scroll_sync_timer =
6597         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6598     }
6599 }
6600
6601 static void
6602 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6603                            GtkTreePath *path,
6604                            gint         offset)
6605 {
6606   gtk_tree_row_reference_free (tree_view->priv->top_row);
6607
6608   if (!path)
6609     {
6610       tree_view->priv->top_row = NULL;
6611       tree_view->priv->top_row_dy = 0;
6612     }
6613   else
6614     {
6615       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6616       tree_view->priv->top_row_dy = offset;
6617     }
6618 }
6619
6620 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6621  * it's set to be NULL, and top_row_dy is 0;
6622  */
6623 static void
6624 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6625 {
6626   gint offset;
6627   GtkTreePath *path;
6628   GtkRBTree *tree;
6629   GtkRBNode *node;
6630
6631   if (tree_view->priv->tree == NULL)
6632     {
6633       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6634     }
6635   else
6636     {
6637       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6638                                         tree_view->priv->dy,
6639                                         &tree, &node);
6640
6641       if (tree == NULL)
6642         {
6643           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6644         }
6645       else
6646         {
6647           path = _gtk_tree_view_find_path (tree_view, tree, node);
6648           gtk_tree_view_set_top_row (tree_view, path, offset);
6649           gtk_tree_path_free (path);
6650         }
6651     }
6652 }
6653
6654 static void
6655 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6656 {
6657   GtkTreePath *path;
6658   GtkRBTree *tree;
6659   GtkRBNode *node;
6660   int new_dy;
6661
6662   /* Avoid recursive calls */
6663   if (tree_view->priv->in_top_row_to_dy)
6664     return;
6665
6666   if (tree_view->priv->top_row)
6667     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6668   else
6669     path = NULL;
6670
6671   if (!path)
6672     tree = NULL;
6673   else
6674     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6675
6676   if (path)
6677     gtk_tree_path_free (path);
6678
6679   if (tree == NULL)
6680     {
6681       /* keep dy and set new toprow */
6682       gtk_tree_row_reference_free (tree_view->priv->top_row);
6683       tree_view->priv->top_row = NULL;
6684       tree_view->priv->top_row_dy = 0;
6685       /* DO NOT install the idle handler */
6686       gtk_tree_view_dy_to_top_row (tree_view);
6687       return;
6688     }
6689
6690   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6691       < tree_view->priv->top_row_dy)
6692     {
6693       /* new top row -- do NOT install the idle handler */
6694       gtk_tree_view_dy_to_top_row (tree_view);
6695       return;
6696     }
6697
6698   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6699   new_dy += tree_view->priv->top_row_dy;
6700
6701   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6702     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6703
6704   new_dy = MAX (0, new_dy);
6705
6706   tree_view->priv->in_top_row_to_dy = TRUE;
6707   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6708   tree_view->priv->in_top_row_to_dy = FALSE;
6709 }
6710
6711
6712 void
6713 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6714 {
6715   tree_view->priv->mark_rows_col_dirty = TRUE;
6716
6717   install_presize_handler (tree_view);
6718 }
6719
6720 /*
6721  * This function works synchronously (due to the while (validate_rows...)
6722  * loop).
6723  *
6724  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6725  * here. You now need to check that yourself.
6726  */
6727 void
6728 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6729                                 GtkTreeViewColumn *column)
6730 {
6731   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6732   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6733
6734   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6735
6736   do_presize_handler (tree_view);
6737   while (validate_rows (tree_view));
6738
6739   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6740 }
6741
6742 /* Drag-and-drop */
6743
6744 static void
6745 set_source_row (GdkDragContext *context,
6746                 GtkTreeModel   *model,
6747                 GtkTreePath    *source_row)
6748 {
6749   g_object_set_data_full (G_OBJECT (context),
6750                           I_("gtk-tree-view-source-row"),
6751                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6752                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6753 }
6754
6755 static GtkTreePath*
6756 get_source_row (GdkDragContext *context)
6757 {
6758   GtkTreeRowReference *ref =
6759     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6760
6761   if (ref)
6762     return gtk_tree_row_reference_get_path (ref);
6763   else
6764     return NULL;
6765 }
6766
6767 typedef struct
6768 {
6769   GtkTreeRowReference *dest_row;
6770   guint                path_down_mode   : 1;
6771   guint                empty_view_drop  : 1;
6772   guint                drop_append_mode : 1;
6773 }
6774 DestRow;
6775
6776 static void
6777 dest_row_free (gpointer data)
6778 {
6779   DestRow *dr = (DestRow *)data;
6780
6781   gtk_tree_row_reference_free (dr->dest_row);
6782   g_slice_free (DestRow, dr);
6783 }
6784
6785 static void
6786 set_dest_row (GdkDragContext *context,
6787               GtkTreeModel   *model,
6788               GtkTreePath    *dest_row,
6789               gboolean        path_down_mode,
6790               gboolean        empty_view_drop,
6791               gboolean        drop_append_mode)
6792 {
6793   DestRow *dr;
6794
6795   if (!dest_row)
6796     {
6797       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6798                               NULL, NULL);
6799       return;
6800     }
6801
6802   dr = g_slice_new (DestRow);
6803
6804   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6805   dr->path_down_mode = path_down_mode != FALSE;
6806   dr->empty_view_drop = empty_view_drop != FALSE;
6807   dr->drop_append_mode = drop_append_mode != FALSE;
6808
6809   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6810                           dr, (GDestroyNotify) dest_row_free);
6811 }
6812
6813 static GtkTreePath*
6814 get_dest_row (GdkDragContext *context,
6815               gboolean       *path_down_mode)
6816 {
6817   DestRow *dr =
6818     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6819
6820   if (dr)
6821     {
6822       GtkTreePath *path = NULL;
6823
6824       if (path_down_mode)
6825         *path_down_mode = dr->path_down_mode;
6826
6827       if (dr->dest_row)
6828         path = gtk_tree_row_reference_get_path (dr->dest_row);
6829       else if (dr->empty_view_drop)
6830         path = gtk_tree_path_new_from_indices (0, -1);
6831       else
6832         path = NULL;
6833
6834       if (path && dr->drop_append_mode)
6835         gtk_tree_path_next (path);
6836
6837       return path;
6838     }
6839   else
6840     return NULL;
6841 }
6842
6843 /* Get/set whether drag_motion requested the drag data and
6844  * drag_data_received should thus not actually insert the data,
6845  * since the data doesn't result from a drop.
6846  */
6847 static void
6848 set_status_pending (GdkDragContext *context,
6849                     GdkDragAction   suggested_action)
6850 {
6851   g_object_set_data (G_OBJECT (context),
6852                      I_("gtk-tree-view-status-pending"),
6853                      GINT_TO_POINTER (suggested_action));
6854 }
6855
6856 static GdkDragAction
6857 get_status_pending (GdkDragContext *context)
6858 {
6859   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6860                                              "gtk-tree-view-status-pending"));
6861 }
6862
6863 static TreeViewDragInfo*
6864 get_info (GtkTreeView *tree_view)
6865 {
6866   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6867 }
6868
6869 static void
6870 destroy_info (TreeViewDragInfo *di)
6871 {
6872   g_slice_free (TreeViewDragInfo, di);
6873 }
6874
6875 static TreeViewDragInfo*
6876 ensure_info (GtkTreeView *tree_view)
6877 {
6878   TreeViewDragInfo *di;
6879
6880   di = get_info (tree_view);
6881
6882   if (di == NULL)
6883     {
6884       di = g_slice_new0 (TreeViewDragInfo);
6885
6886       g_object_set_data_full (G_OBJECT (tree_view),
6887                               I_("gtk-tree-view-drag-info"),
6888                               di,
6889                               (GDestroyNotify) destroy_info);
6890     }
6891
6892   return di;
6893 }
6894
6895 static void
6896 remove_info (GtkTreeView *tree_view)
6897 {
6898   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6899 }
6900
6901 #if 0
6902 static gint
6903 drag_scan_timeout (gpointer data)
6904 {
6905   GtkTreeView *tree_view;
6906   gint x, y;
6907   GdkModifierType state;
6908   GtkTreePath *path = NULL;
6909   GtkTreeViewColumn *column = NULL;
6910   GdkRectangle visible_rect;
6911
6912   GDK_THREADS_ENTER ();
6913
6914   tree_view = GTK_TREE_VIEW (data);
6915
6916   gdk_window_get_pointer (tree_view->priv->bin_window,
6917                           &x, &y, &state);
6918
6919   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6920
6921   /* See if we are near the edge. */
6922   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6923       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6924       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6925       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6926     {
6927       gtk_tree_view_get_path_at_pos (tree_view,
6928                                      tree_view->priv->bin_window,
6929                                      x, y,
6930                                      &path,
6931                                      &column,
6932                                      NULL,
6933                                      NULL);
6934
6935       if (path != NULL)
6936         {
6937           gtk_tree_view_scroll_to_cell (tree_view,
6938                                         path,
6939                                         column,
6940                                         TRUE,
6941                                         0.5, 0.5);
6942
6943           gtk_tree_path_free (path);
6944         }
6945     }
6946
6947   GDK_THREADS_LEAVE ();
6948
6949   return TRUE;
6950 }
6951 #endif /* 0 */
6952
6953 static void
6954 add_scroll_timeout (GtkTreeView *tree_view)
6955 {
6956   if (tree_view->priv->scroll_timeout == 0)
6957     {
6958       tree_view->priv->scroll_timeout =
6959         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6960     }
6961 }
6962
6963 static void
6964 remove_scroll_timeout (GtkTreeView *tree_view)
6965 {
6966   if (tree_view->priv->scroll_timeout != 0)
6967     {
6968       g_source_remove (tree_view->priv->scroll_timeout);
6969       tree_view->priv->scroll_timeout = 0;
6970     }
6971 }
6972
6973 static gboolean
6974 check_model_dnd (GtkTreeModel *model,
6975                  GType         required_iface,
6976                  const gchar  *signal)
6977 {
6978   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6979     {
6980       g_warning ("You must override the default '%s' handler "
6981                  "on GtkTreeView when using models that don't support "
6982                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6983                  "is to connect to '%s' and call "
6984                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6985                  "the default handler from running. Look at the source code "
6986                  "for the default handler in gtktreeview.c to get an idea what "
6987                  "your handler should do. (gtktreeview.c is in the GTK source "
6988                  "code.) If you're using GTK from a language other than C, "
6989                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6990                  signal, g_type_name (required_iface), signal);
6991       return FALSE;
6992     }
6993   else
6994     return TRUE;
6995 }
6996
6997 static void
6998 remove_open_timeout (GtkTreeView *tree_view)
6999 {
7000   if (tree_view->priv->open_dest_timeout != 0)
7001     {
7002       g_source_remove (tree_view->priv->open_dest_timeout);
7003       tree_view->priv->open_dest_timeout = 0;
7004     }
7005 }
7006
7007
7008 static gint
7009 open_row_timeout (gpointer data)
7010 {
7011   GtkTreeView *tree_view = data;
7012   GtkTreePath *dest_path = NULL;
7013   GtkTreeViewDropPosition pos;
7014   gboolean result = FALSE;
7015
7016   gtk_tree_view_get_drag_dest_row (tree_view,
7017                                    &dest_path,
7018                                    &pos);
7019
7020   if (dest_path &&
7021       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7022        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7023     {
7024       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7025       tree_view->priv->open_dest_timeout = 0;
7026
7027       gtk_tree_path_free (dest_path);
7028     }
7029   else
7030     {
7031       if (dest_path)
7032         gtk_tree_path_free (dest_path);
7033
7034       result = TRUE;
7035     }
7036
7037   return result;
7038 }
7039
7040 static gboolean
7041 scroll_row_timeout (gpointer data)
7042 {
7043   GtkTreeView *tree_view = data;
7044
7045   gtk_tree_view_vertical_autoscroll (tree_view);
7046
7047   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7048     gtk_tree_view_update_rubber_band (tree_view);
7049
7050   return TRUE;
7051 }
7052
7053 /* Returns TRUE if event should not be propagated to parent widgets */
7054 static gboolean
7055 set_destination_row (GtkTreeView    *tree_view,
7056                      GdkDragContext *context,
7057                      /* coordinates relative to the widget */
7058                      gint            x,
7059                      gint            y,
7060                      GdkDragAction  *suggested_action,
7061                      GdkAtom        *target)
7062 {
7063   GtkTreePath *path = NULL;
7064   GtkTreeViewDropPosition pos;
7065   GtkTreeViewDropPosition old_pos;
7066   TreeViewDragInfo *di;
7067   GtkWidget *widget;
7068   GtkTreePath *old_dest_path = NULL;
7069   gboolean can_drop = FALSE;
7070
7071   *suggested_action = 0;
7072   *target = GDK_NONE;
7073
7074   widget = GTK_WIDGET (tree_view);
7075
7076   di = get_info (tree_view);
7077
7078   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
7079     {
7080       /* someone unset us as a drag dest, note that if
7081        * we return FALSE drag_leave isn't called
7082        */
7083
7084       gtk_tree_view_set_drag_dest_row (tree_view,
7085                                        NULL,
7086                                        GTK_TREE_VIEW_DROP_BEFORE);
7087
7088       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7089       remove_open_timeout (GTK_TREE_VIEW (widget));
7090
7091       return FALSE; /* no longer a drop site */
7092     }
7093
7094   *target = gtk_drag_dest_find_target (widget, context,
7095                                        gtk_drag_dest_get_target_list (widget));
7096   if (*target == GDK_NONE)
7097     {
7098       return FALSE;
7099     }
7100
7101   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7102                                           x, y,
7103                                           &path,
7104                                           &pos))
7105     {
7106       gint n_children;
7107       GtkTreeModel *model;
7108
7109       remove_open_timeout (tree_view);
7110
7111       /* the row got dropped on empty space, let's setup a special case
7112        */
7113
7114       if (path)
7115         gtk_tree_path_free (path);
7116
7117       model = gtk_tree_view_get_model (tree_view);
7118
7119       n_children = gtk_tree_model_iter_n_children (model, NULL);
7120       if (n_children)
7121         {
7122           pos = GTK_TREE_VIEW_DROP_AFTER;
7123           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7124         }
7125       else
7126         {
7127           pos = GTK_TREE_VIEW_DROP_BEFORE;
7128           path = gtk_tree_path_new_from_indices (0, -1);
7129         }
7130
7131       can_drop = TRUE;
7132
7133       goto out;
7134     }
7135
7136   g_assert (path);
7137
7138   /* If we left the current row's "open" zone, unset the timeout for
7139    * opening the row
7140    */
7141   gtk_tree_view_get_drag_dest_row (tree_view,
7142                                    &old_dest_path,
7143                                    &old_pos);
7144
7145   if (old_dest_path &&
7146       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7147        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7148          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7149     remove_open_timeout (tree_view);
7150
7151   if (old_dest_path)
7152     gtk_tree_path_free (old_dest_path);
7153
7154   if (TRUE /* FIXME if the location droppable predicate */)
7155     {
7156       can_drop = TRUE;
7157     }
7158
7159 out:
7160   if (can_drop)
7161     {
7162       GtkWidget *source_widget;
7163
7164       *suggested_action = context->suggested_action;
7165       source_widget = gtk_drag_get_source_widget (context);
7166
7167       if (source_widget == widget)
7168         {
7169           /* Default to MOVE, unless the user has
7170            * pressed ctrl or shift to affect available actions
7171            */
7172           if ((context->actions & GDK_ACTION_MOVE) != 0)
7173             *suggested_action = GDK_ACTION_MOVE;
7174         }
7175
7176       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7177                                        path, pos);
7178     }
7179   else
7180     {
7181       /* can't drop here */
7182       remove_open_timeout (tree_view);
7183
7184       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7185                                        NULL,
7186                                        GTK_TREE_VIEW_DROP_BEFORE);
7187     }
7188
7189   if (path)
7190     gtk_tree_path_free (path);
7191
7192   return TRUE;
7193 }
7194
7195 static GtkTreePath*
7196 get_logical_dest_row (GtkTreeView *tree_view,
7197                       gboolean    *path_down_mode,
7198                       gboolean    *drop_append_mode)
7199 {
7200   /* adjust path to point to the row the drop goes in front of */
7201   GtkTreePath *path = NULL;
7202   GtkTreeViewDropPosition pos;
7203
7204   g_return_val_if_fail (path_down_mode != NULL, NULL);
7205   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7206
7207   *path_down_mode = FALSE;
7208   *drop_append_mode = 0;
7209
7210   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7211
7212   if (path == NULL)
7213     return NULL;
7214
7215   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7216     ; /* do nothing */
7217   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7218            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7219     *path_down_mode = TRUE;
7220   else
7221     {
7222       GtkTreeIter iter;
7223       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7224
7225       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7226
7227       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7228           !gtk_tree_model_iter_next (model, &iter))
7229         *drop_append_mode = 1;
7230       else
7231         {
7232           *drop_append_mode = 0;
7233           gtk_tree_path_next (path);
7234         }
7235     }
7236
7237   return path;
7238 }
7239
7240 static gboolean
7241 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7242                                         GdkEventMotion   *event)
7243 {
7244   GtkWidget *widget = GTK_WIDGET (tree_view);
7245   GdkDragContext *context;
7246   TreeViewDragInfo *di;
7247   GtkTreePath *path = NULL;
7248   gint button;
7249   gint cell_x, cell_y;
7250   GtkTreeModel *model;
7251   gboolean retval = FALSE;
7252
7253   di = get_info (tree_view);
7254
7255   if (di == NULL || !di->source_set)
7256     goto out;
7257
7258   if (tree_view->priv->pressed_button < 0)
7259     goto out;
7260
7261   if (!gtk_drag_check_threshold (widget,
7262                                  tree_view->priv->press_start_x,
7263                                  tree_view->priv->press_start_y,
7264                                  event->x, event->y))
7265     goto out;
7266
7267   model = gtk_tree_view_get_model (tree_view);
7268
7269   if (model == NULL)
7270     goto out;
7271
7272   button = tree_view->priv->pressed_button;
7273   tree_view->priv->pressed_button = -1;
7274
7275   gtk_tree_view_get_path_at_pos (tree_view,
7276                                  tree_view->priv->press_start_x,
7277                                  tree_view->priv->press_start_y,
7278                                  &path,
7279                                  NULL,
7280                                  &cell_x,
7281                                  &cell_y);
7282
7283   if (path == NULL)
7284     goto out;
7285
7286   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7287       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7288                                            path))
7289     goto out;
7290
7291   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7292     goto out;
7293
7294   /* Now we can begin the drag */
7295
7296   retval = TRUE;
7297
7298   context = gtk_drag_begin (widget,
7299                             gtk_drag_source_get_target_list (widget),
7300                             di->source_actions,
7301                             button,
7302                             (GdkEvent*)event);
7303
7304   set_source_row (context, model, path);
7305
7306  out:
7307   if (path)
7308     gtk_tree_path_free (path);
7309
7310   return retval;
7311 }
7312
7313
7314 static void
7315 gtk_tree_view_drag_begin (GtkWidget      *widget,
7316                           GdkDragContext *context)
7317 {
7318   GtkTreeView *tree_view;
7319   GtkTreePath *path = NULL;
7320   gint cell_x, cell_y;
7321   cairo_surface_t *row_pix;
7322   TreeViewDragInfo *di;
7323
7324   tree_view = GTK_TREE_VIEW (widget);
7325
7326   /* if the user uses a custom DND source impl, we don't set the icon here */
7327   di = get_info (tree_view);
7328
7329   if (di == NULL || !di->source_set)
7330     return;
7331
7332   gtk_tree_view_get_path_at_pos (tree_view,
7333                                  tree_view->priv->press_start_x,
7334                                  tree_view->priv->press_start_y,
7335                                  &path,
7336                                  NULL,
7337                                  &cell_x,
7338                                  &cell_y);
7339
7340   g_return_if_fail (path != NULL);
7341
7342   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7343                                                 path);
7344   cairo_surface_set_device_offset (row_pix,
7345                                    /* the + 1 is for the black border in the icon */
7346                                    - (tree_view->priv->press_start_x + 1),
7347                                    - (cell_y + 1));
7348
7349   gtk_drag_set_icon_surface (context, row_pix);
7350
7351   cairo_surface_destroy (row_pix);
7352   gtk_tree_path_free (path);
7353 }
7354
7355 static void
7356 gtk_tree_view_drag_end (GtkWidget      *widget,
7357                         GdkDragContext *context)
7358 {
7359   /* do nothing */
7360 }
7361
7362 /* Default signal implementations for the drag signals */
7363 static void
7364 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7365                              GdkDragContext   *context,
7366                              GtkSelectionData *selection_data,
7367                              guint             info,
7368                              guint             time)
7369 {
7370   GtkTreeView *tree_view;
7371   GtkTreeModel *model;
7372   TreeViewDragInfo *di;
7373   GtkTreePath *source_row;
7374
7375   tree_view = GTK_TREE_VIEW (widget);
7376
7377   model = gtk_tree_view_get_model (tree_view);
7378
7379   if (model == NULL)
7380     return;
7381
7382   di = get_info (GTK_TREE_VIEW (widget));
7383
7384   if (di == NULL)
7385     return;
7386
7387   source_row = get_source_row (context);
7388
7389   if (source_row == NULL)
7390     return;
7391
7392   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7393    * any model; for DragSource models there are some other targets
7394    * we also support.
7395    */
7396
7397   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7398       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7399                                           source_row,
7400                                           selection_data))
7401     goto done;
7402
7403   /* If drag_data_get does nothing, try providing row data. */
7404   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7405     {
7406       gtk_tree_set_row_drag_data (selection_data,
7407                                   model,
7408                                   source_row);
7409     }
7410
7411  done:
7412   gtk_tree_path_free (source_row);
7413 }
7414
7415
7416 static void
7417 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7418                                 GdkDragContext *context)
7419 {
7420   TreeViewDragInfo *di;
7421   GtkTreeModel *model;
7422   GtkTreeView *tree_view;
7423   GtkTreePath *source_row;
7424
7425   tree_view = GTK_TREE_VIEW (widget);
7426   model = gtk_tree_view_get_model (tree_view);
7427
7428   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7429     return;
7430
7431   di = get_info (tree_view);
7432
7433   if (di == NULL)
7434     return;
7435
7436   source_row = get_source_row (context);
7437
7438   if (source_row == NULL)
7439     return;
7440
7441   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7442                                          source_row);
7443
7444   gtk_tree_path_free (source_row);
7445
7446   set_source_row (context, NULL, NULL);
7447 }
7448
7449 static void
7450 gtk_tree_view_drag_leave (GtkWidget      *widget,
7451                           GdkDragContext *context,
7452                           guint             time)
7453 {
7454   /* unset any highlight row */
7455   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7456                                    NULL,
7457                                    GTK_TREE_VIEW_DROP_BEFORE);
7458
7459   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7460   remove_open_timeout (GTK_TREE_VIEW (widget));
7461 }
7462
7463
7464 static gboolean
7465 gtk_tree_view_drag_motion (GtkWidget        *widget,
7466                            GdkDragContext   *context,
7467                            /* coordinates relative to the widget */
7468                            gint              x,
7469                            gint              y,
7470                            guint             time)
7471 {
7472   gboolean empty;
7473   GtkTreePath *path = NULL;
7474   GtkTreeViewDropPosition pos;
7475   GtkTreeView *tree_view;
7476   GdkDragAction suggested_action = 0;
7477   GdkAtom target;
7478
7479   tree_view = GTK_TREE_VIEW (widget);
7480
7481   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7482     return FALSE;
7483
7484   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7485
7486   /* we only know this *after* set_desination_row */
7487   empty = tree_view->priv->empty_view_drop;
7488
7489   if (path == NULL && !empty)
7490     {
7491       /* Can't drop here. */
7492       gdk_drag_status (context, 0, time);
7493     }
7494   else
7495     {
7496       if (tree_view->priv->open_dest_timeout == 0 &&
7497           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7498            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7499         {
7500           tree_view->priv->open_dest_timeout =
7501             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7502         }
7503       else
7504         {
7505           add_scroll_timeout (tree_view);
7506         }
7507
7508       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7509         {
7510           /* Request data so we can use the source row when
7511            * determining whether to accept the drop
7512            */
7513           set_status_pending (context, suggested_action);
7514           gtk_drag_get_data (widget, context, target, time);
7515         }
7516       else
7517         {
7518           set_status_pending (context, 0);
7519           gdk_drag_status (context, suggested_action, time);
7520         }
7521     }
7522
7523   if (path)
7524     gtk_tree_path_free (path);
7525
7526   return TRUE;
7527 }
7528
7529
7530 static gboolean
7531 gtk_tree_view_drag_drop (GtkWidget        *widget,
7532                          GdkDragContext   *context,
7533                          /* coordinates relative to the widget */
7534                          gint              x,
7535                          gint              y,
7536                          guint             time)
7537 {
7538   GtkTreeView *tree_view;
7539   GtkTreePath *path;
7540   GdkDragAction suggested_action = 0;
7541   GdkAtom target = GDK_NONE;
7542   TreeViewDragInfo *di;
7543   GtkTreeModel *model;
7544   gboolean path_down_mode;
7545   gboolean drop_append_mode;
7546
7547   tree_view = GTK_TREE_VIEW (widget);
7548
7549   model = gtk_tree_view_get_model (tree_view);
7550
7551   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7552   remove_open_timeout (GTK_TREE_VIEW (widget));
7553
7554   di = get_info (tree_view);
7555
7556   if (di == NULL)
7557     return FALSE;
7558
7559   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7560     return FALSE;
7561
7562   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7563     return FALSE;
7564
7565   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7566
7567   if (target != GDK_NONE && path != NULL)
7568     {
7569       /* in case a motion had requested drag data, change things so we
7570        * treat drag data receives as a drop.
7571        */
7572       set_status_pending (context, 0);
7573       set_dest_row (context, model, path,
7574                     path_down_mode, tree_view->priv->empty_view_drop,
7575                     drop_append_mode);
7576     }
7577
7578   if (path)
7579     gtk_tree_path_free (path);
7580
7581   /* Unset this thing */
7582   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7583                                    NULL,
7584                                    GTK_TREE_VIEW_DROP_BEFORE);
7585
7586   if (target != GDK_NONE)
7587     {
7588       gtk_drag_get_data (widget, context, target, time);
7589       return TRUE;
7590     }
7591   else
7592     return FALSE;
7593 }
7594
7595 static void
7596 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7597                                   GdkDragContext   *context,
7598                                   /* coordinates relative to the widget */
7599                                   gint              x,
7600                                   gint              y,
7601                                   GtkSelectionData *selection_data,
7602                                   guint             info,
7603                                   guint             time)
7604 {
7605   GtkTreePath *path;
7606   TreeViewDragInfo *di;
7607   gboolean accepted = FALSE;
7608   GtkTreeModel *model;
7609   GtkTreeView *tree_view;
7610   GtkTreePath *dest_row;
7611   GdkDragAction suggested_action;
7612   gboolean path_down_mode;
7613   gboolean drop_append_mode;
7614
7615   tree_view = GTK_TREE_VIEW (widget);
7616
7617   model = gtk_tree_view_get_model (tree_view);
7618
7619   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7620     return;
7621
7622   di = get_info (tree_view);
7623
7624   if (di == NULL)
7625     return;
7626
7627   suggested_action = get_status_pending (context);
7628
7629   if (suggested_action)
7630     {
7631       /* We are getting this data due to a request in drag_motion,
7632        * rather than due to a request in drag_drop, so we are just
7633        * supposed to call drag_status, not actually paste in the
7634        * data.
7635        */
7636       path = get_logical_dest_row (tree_view, &path_down_mode,
7637                                    &drop_append_mode);
7638
7639       if (path == NULL)
7640         suggested_action = 0;
7641       else if (path_down_mode)
7642         gtk_tree_path_down (path);
7643
7644       if (suggested_action)
7645         {
7646           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7647                                                      path,
7648                                                      selection_data))
7649             {
7650               if (path_down_mode)
7651                 {
7652                   path_down_mode = FALSE;
7653                   gtk_tree_path_up (path);
7654
7655                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7656                                                              path,
7657                                                              selection_data))
7658                     suggested_action = 0;
7659                 }
7660               else
7661                 suggested_action = 0;
7662             }
7663         }
7664
7665       gdk_drag_status (context, suggested_action, time);
7666
7667       if (path)
7668         gtk_tree_path_free (path);
7669
7670       /* If you can't drop, remove user drop indicator until the next motion */
7671       if (suggested_action == 0)
7672         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7673                                          NULL,
7674                                          GTK_TREE_VIEW_DROP_BEFORE);
7675
7676       return;
7677     }
7678
7679   dest_row = get_dest_row (context, &path_down_mode);
7680
7681   if (dest_row == NULL)
7682     return;
7683
7684   if (selection_data->length >= 0)
7685     {
7686       if (path_down_mode)
7687         {
7688           gtk_tree_path_down (dest_row);
7689           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7690                                                      dest_row, selection_data))
7691             gtk_tree_path_up (dest_row);
7692         }
7693     }
7694
7695   if (selection_data->length >= 0)
7696     {
7697       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7698                                                  dest_row,
7699                                                  selection_data))
7700         accepted = TRUE;
7701     }
7702
7703   gtk_drag_finish (context,
7704                    accepted,
7705                    (context->action == GDK_ACTION_MOVE),
7706                    time);
7707
7708   if (gtk_tree_path_get_depth (dest_row) == 1
7709       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7710     {
7711       /* special special case drag to "0", scroll to first item */
7712       if (!tree_view->priv->scroll_to_path)
7713         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7714     }
7715
7716   gtk_tree_path_free (dest_row);
7717
7718   /* drop dest_row */
7719   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7720 }
7721
7722
7723
7724 /* GtkContainer Methods
7725  */
7726
7727
7728 static void
7729 gtk_tree_view_remove (GtkContainer *container,
7730                       GtkWidget    *widget)
7731 {
7732   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7733   GtkTreeViewChild *child = NULL;
7734   GList *tmp_list;
7735
7736   tmp_list = tree_view->priv->children;
7737   while (tmp_list)
7738     {
7739       child = tmp_list->data;
7740       if (child->widget == widget)
7741         {
7742           gtk_widget_unparent (widget);
7743
7744           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7745           g_list_free_1 (tmp_list);
7746           g_slice_free (GtkTreeViewChild, child);
7747           return;
7748         }
7749
7750       tmp_list = tmp_list->next;
7751     }
7752
7753   tmp_list = tree_view->priv->columns;
7754
7755   while (tmp_list)
7756     {
7757       GtkTreeViewColumn *column;
7758       column = tmp_list->data;
7759       if (column->button == widget)
7760         {
7761           gtk_widget_unparent (widget);
7762           return;
7763         }
7764       tmp_list = tmp_list->next;
7765     }
7766 }
7767
7768 static void
7769 gtk_tree_view_forall (GtkContainer *container,
7770                       gboolean      include_internals,
7771                       GtkCallback   callback,
7772                       gpointer      callback_data)
7773 {
7774   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7775   GtkTreeViewChild *child = NULL;
7776   GtkTreeViewColumn *column;
7777   GList *tmp_list;
7778
7779   tmp_list = tree_view->priv->children;
7780   while (tmp_list)
7781     {
7782       child = tmp_list->data;
7783       tmp_list = tmp_list->next;
7784
7785       (* callback) (child->widget, callback_data);
7786     }
7787   if (include_internals == FALSE)
7788     return;
7789
7790   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7791     {
7792       column = tmp_list->data;
7793
7794       if (column->button)
7795         (* callback) (column->button, callback_data);
7796     }
7797 }
7798
7799 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7800  * cells. If so we draw one big row-spanning focus rectangle.
7801  */
7802 static gboolean
7803 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7804 {
7805   GList *list;
7806
7807   for (list = tree_view->priv->columns; list; list = list->next)
7808     {
7809       if (!((GtkTreeViewColumn *)list->data)->visible)
7810         continue;
7811       if (_gtk_tree_view_column_count_special_cells (list->data))
7812         return TRUE;
7813     }
7814
7815   return FALSE;
7816 }
7817
7818 static void
7819 column_sizing_notify (GObject    *object,
7820                       GParamSpec *pspec,
7821                       gpointer    data)
7822 {
7823   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7824
7825   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7826     /* disable fixed height mode */
7827     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7828 }
7829
7830 /**
7831  * gtk_tree_view_set_fixed_height_mode:
7832  * @tree_view: a #GtkTreeView 
7833  * @enable: %TRUE to enable fixed height mode
7834  * 
7835  * Enables or disables the fixed height mode of @tree_view. 
7836  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7837  * rows have the same height. 
7838  * Only enable this option if all rows are the same height and all
7839  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7840  *
7841  * Since: 2.6 
7842  **/
7843 void
7844 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7845                                      gboolean     enable)
7846 {
7847   GList *l;
7848   
7849   enable = enable != FALSE;
7850
7851   if (enable == tree_view->priv->fixed_height_mode)
7852     return;
7853
7854   if (!enable)
7855     {
7856       tree_view->priv->fixed_height_mode = 0;
7857       tree_view->priv->fixed_height = -1;
7858
7859       /* force a revalidation */
7860       install_presize_handler (tree_view);
7861     }
7862   else 
7863     {
7864       /* make sure all columns are of type FIXED */
7865       for (l = tree_view->priv->columns; l; l = l->next)
7866         {
7867           GtkTreeViewColumn *c = l->data;
7868           
7869           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7870         }
7871       
7872       /* yes, we really have to do this is in a separate loop */
7873       for (l = tree_view->priv->columns; l; l = l->next)
7874         g_signal_connect (l->data, "notify::sizing",
7875                           G_CALLBACK (column_sizing_notify), tree_view);
7876       
7877       tree_view->priv->fixed_height_mode = 1;
7878       tree_view->priv->fixed_height = -1;
7879       
7880       if (tree_view->priv->tree)
7881         initialize_fixed_height_mode (tree_view);
7882     }
7883
7884   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7885 }
7886
7887 /**
7888  * gtk_tree_view_get_fixed_height_mode:
7889  * @tree_view: a #GtkTreeView
7890  * 
7891  * Returns whether fixed height mode is turned on for @tree_view.
7892  * 
7893  * Return value: %TRUE if @tree_view is in fixed height mode
7894  * 
7895  * Since: 2.6
7896  **/
7897 gboolean
7898 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7899 {
7900   return tree_view->priv->fixed_height_mode;
7901 }
7902
7903 /* Returns TRUE if the focus is within the headers, after the focus operation is
7904  * done
7905  */
7906 static gboolean
7907 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7908                             GtkDirectionType  dir,
7909                             gboolean          clamp_column_visible)
7910 {
7911   GtkWidget *focus_child;
7912
7913   GList *last_column, *first_column;
7914   GList *tmp_list;
7915   gboolean rtl;
7916
7917   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7918     return FALSE;
7919
7920   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
7921
7922   first_column = tree_view->priv->columns;
7923   while (first_column)
7924     {
7925       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7926           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7927           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7928            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7929         break;
7930       first_column = first_column->next;
7931     }
7932
7933   /* No headers are visible, or are focusable.  We can't focus in or out.
7934    */
7935   if (first_column == NULL)
7936     return FALSE;
7937
7938   last_column = g_list_last (tree_view->priv->columns);
7939   while (last_column)
7940     {
7941       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7942           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7943           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7944            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7945         break;
7946       last_column = last_column->prev;
7947     }
7948
7949
7950   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7951
7952   switch (dir)
7953     {
7954     case GTK_DIR_TAB_BACKWARD:
7955     case GTK_DIR_TAB_FORWARD:
7956     case GTK_DIR_UP:
7957     case GTK_DIR_DOWN:
7958       if (focus_child == NULL)
7959         {
7960           if (tree_view->priv->focus_column != NULL &&
7961               gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
7962             focus_child = tree_view->priv->focus_column->button;
7963           else
7964             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7965           gtk_widget_grab_focus (focus_child);
7966           break;
7967         }
7968       return FALSE;
7969
7970     case GTK_DIR_LEFT:
7971     case GTK_DIR_RIGHT:
7972       if (focus_child == NULL)
7973         {
7974           if (tree_view->priv->focus_column != NULL)
7975             focus_child = tree_view->priv->focus_column->button;
7976           else if (dir == GTK_DIR_LEFT)
7977             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7978           else
7979             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7980           gtk_widget_grab_focus (focus_child);
7981           break;
7982         }
7983
7984       if (gtk_widget_child_focus (focus_child, dir))
7985         {
7986           /* The focus moves inside the button. */
7987           /* This is probably a great example of bad UI */
7988           break;
7989         }
7990
7991       /* We need to move the focus among the row of buttons. */
7992       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7993         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7994           break;
7995
7996       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7997           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7998         {
7999           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8000           break;
8001         }
8002
8003       while (tmp_list)
8004         {
8005           GtkTreeViewColumn *column;
8006
8007           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8008             tmp_list = tmp_list->next;
8009           else
8010             tmp_list = tmp_list->prev;
8011
8012           if (tmp_list == NULL)
8013             {
8014               g_warning ("Internal button not found");
8015               break;
8016             }
8017           column = tmp_list->data;
8018           if (column->button &&
8019               column->visible &&
8020               gtk_widget_get_can_focus (column->button))
8021             {
8022               focus_child = column->button;
8023               gtk_widget_grab_focus (column->button);
8024               break;
8025             }
8026         }
8027       break;
8028     default:
8029       g_assert_not_reached ();
8030       break;
8031     }
8032
8033   /* if focus child is non-null, we assume it's been set to the current focus child
8034    */
8035   if (focus_child)
8036     {
8037       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8038         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
8039           {
8040             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8041             break;
8042           }
8043
8044       if (clamp_column_visible)
8045         {
8046           gtk_tree_view_clamp_column_visible (tree_view,
8047                                               tree_view->priv->focus_column,
8048                                               FALSE);
8049         }
8050     }
8051
8052   return (focus_child != NULL);
8053 }
8054
8055 /* This function returns in 'path' the first focusable path, if the given path
8056  * is already focusable, it's the returned one.
8057  */
8058 static gboolean
8059 search_first_focusable_path (GtkTreeView  *tree_view,
8060                              GtkTreePath **path,
8061                              gboolean      search_forward,
8062                              GtkRBTree   **new_tree,
8063                              GtkRBNode   **new_node)
8064 {
8065   GtkRBTree *tree = NULL;
8066   GtkRBNode *node = NULL;
8067
8068   if (!path || !*path)
8069     return FALSE;
8070
8071   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8072
8073   if (!tree || !node)
8074     return FALSE;
8075
8076   while (node && row_is_separator (tree_view, NULL, *path))
8077     {
8078       if (search_forward)
8079         _gtk_rbtree_next_full (tree, node, &tree, &node);
8080       else
8081         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8082
8083       if (*path)
8084         gtk_tree_path_free (*path);
8085
8086       if (node)
8087         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8088       else
8089         *path = NULL;
8090     }
8091
8092   if (new_tree)
8093     *new_tree = tree;
8094
8095   if (new_node)
8096     *new_node = node;
8097
8098   return (*path != NULL);
8099 }
8100
8101 static gint
8102 gtk_tree_view_focus (GtkWidget        *widget,
8103                      GtkDirectionType  direction)
8104 {
8105   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8106   GtkContainer *container = GTK_CONTAINER (widget);
8107   GtkWidget *focus_child;
8108
8109   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8110     return FALSE;
8111
8112   focus_child = gtk_container_get_focus_child (container);
8113
8114   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8115   /* Case 1.  Headers currently have focus. */
8116   if (focus_child)
8117     {
8118       switch (direction)
8119         {
8120         case GTK_DIR_LEFT:
8121         case GTK_DIR_RIGHT:
8122           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8123           return TRUE;
8124         case GTK_DIR_TAB_BACKWARD:
8125         case GTK_DIR_UP:
8126           return FALSE;
8127         case GTK_DIR_TAB_FORWARD:
8128         case GTK_DIR_DOWN:
8129           gtk_widget_grab_focus (widget);
8130           return TRUE;
8131         default:
8132           g_assert_not_reached ();
8133           return FALSE;
8134         }
8135     }
8136
8137   /* Case 2. We don't have focus at all. */
8138   if (!gtk_widget_has_focus (widget))
8139     {
8140       gtk_widget_grab_focus (widget);
8141       return TRUE;
8142     }
8143
8144   /* Case 3. We have focus already. */
8145   if (direction == GTK_DIR_TAB_BACKWARD)
8146     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8147   else if (direction == GTK_DIR_TAB_FORWARD)
8148     return FALSE;
8149
8150   /* Other directions caught by the keybindings */
8151   gtk_widget_grab_focus (widget);
8152   return TRUE;
8153 }
8154
8155 static void
8156 gtk_tree_view_grab_focus (GtkWidget *widget)
8157 {
8158   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8159
8160   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8161 }
8162
8163 static void
8164 gtk_tree_view_style_set (GtkWidget *widget,
8165                          GtkStyle *previous_style)
8166 {
8167   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8168   GtkStyle *style;
8169   GList *list;
8170   GtkTreeViewColumn *column;
8171
8172   if (gtk_widget_get_realized (widget))
8173     {
8174       style = gtk_widget_get_style (widget);
8175       gdk_window_set_background (tree_view->priv->bin_window,
8176                                  &style->base[gtk_widget_get_state (widget)]);
8177       gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8178
8179       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8180       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8181     }
8182
8183   gtk_widget_style_get (widget,
8184                         "expander-size", &tree_view->priv->expander_size,
8185                         NULL);
8186   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8187
8188   for (list = tree_view->priv->columns; list; list = list->next)
8189     {
8190       column = list->data;
8191       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8192     }
8193
8194   tree_view->priv->fixed_height = -1;
8195   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8196
8197   gtk_widget_queue_resize (widget);
8198 }
8199
8200
8201 static void
8202 gtk_tree_view_set_focus_child (GtkContainer *container,
8203                                GtkWidget    *child)
8204 {
8205   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8206   GList *list;
8207
8208   for (list = tree_view->priv->columns; list; list = list->next)
8209     {
8210       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8211         {
8212           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8213           break;
8214         }
8215     }
8216
8217   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8218 }
8219
8220 static gboolean
8221 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8222                                 GtkMovementStep    step,
8223                                 gint               count)
8224 {
8225   GdkModifierType state;
8226
8227   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8228   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8229                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8230                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8231                         step == GTK_MOVEMENT_PAGES ||
8232                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8233
8234   if (tree_view->priv->tree == NULL)
8235     return FALSE;
8236   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8237     return FALSE;
8238
8239   gtk_tree_view_stop_editing (tree_view, FALSE);
8240   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8241   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8242
8243   if (gtk_get_current_event_state (&state))
8244     {
8245       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8246         tree_view->priv->ctrl_pressed = TRUE;
8247       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8248         tree_view->priv->shift_pressed = TRUE;
8249     }
8250   /* else we assume not pressed */
8251
8252   switch (step)
8253     {
8254       /* currently we make no distinction.  When we go bi-di, we need to */
8255     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8256     case GTK_MOVEMENT_VISUAL_POSITIONS:
8257       gtk_tree_view_move_cursor_left_right (tree_view, count);
8258       break;
8259     case GTK_MOVEMENT_DISPLAY_LINES:
8260       gtk_tree_view_move_cursor_up_down (tree_view, count);
8261       break;
8262     case GTK_MOVEMENT_PAGES:
8263       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8264       break;
8265     case GTK_MOVEMENT_BUFFER_ENDS:
8266       gtk_tree_view_move_cursor_start_end (tree_view, count);
8267       break;
8268     default:
8269       g_assert_not_reached ();
8270     }
8271
8272   tree_view->priv->ctrl_pressed = FALSE;
8273   tree_view->priv->shift_pressed = FALSE;
8274
8275   return TRUE;
8276 }
8277
8278 static void
8279 gtk_tree_view_put (GtkTreeView *tree_view,
8280                    GtkWidget   *child_widget,
8281                    /* in bin_window coordinates */
8282                    gint         x,
8283                    gint         y,
8284                    gint         width,
8285                    gint         height)
8286 {
8287   GtkTreeViewChild *child;
8288   
8289   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8290   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8291
8292   child = g_slice_new (GtkTreeViewChild);
8293
8294   child->widget = child_widget;
8295   child->x = x;
8296   child->y = y;
8297   child->width = width;
8298   child->height = height;
8299
8300   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8301
8302   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8303     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8304   
8305   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8306 }
8307
8308 void
8309 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8310                                   GtkWidget   *widget,
8311                                   /* in tree coordinates */
8312                                   gint         x,
8313                                   gint         y,
8314                                   gint         width,
8315                                   gint         height)
8316 {
8317   GtkTreeViewChild *child = NULL;
8318   GList *list;
8319   GdkRectangle allocation;
8320
8321   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8322   g_return_if_fail (GTK_IS_WIDGET (widget));
8323
8324   for (list = tree_view->priv->children; list; list = list->next)
8325     {
8326       if (((GtkTreeViewChild *)list->data)->widget == widget)
8327         {
8328           child = list->data;
8329           break;
8330         }
8331     }
8332   if (child == NULL)
8333     return;
8334
8335   allocation.x = child->x = x;
8336   allocation.y = child->y = y;
8337   allocation.width = child->width = width;
8338   allocation.height = child->height = height;
8339
8340   if (gtk_widget_get_realized (widget))
8341     gtk_widget_size_allocate (widget, &allocation);
8342 }
8343
8344
8345 /* TreeModel Callbacks
8346  */
8347
8348 static void
8349 gtk_tree_view_row_changed (GtkTreeModel *model,
8350                            GtkTreePath  *path,
8351                            GtkTreeIter  *iter,
8352                            gpointer      data)
8353 {
8354   GtkTreeView *tree_view = (GtkTreeView *)data;
8355   GtkRBTree *tree;
8356   GtkRBNode *node;
8357   gboolean free_path = FALSE;
8358   GList *list;
8359   GtkTreePath *cursor_path;
8360
8361   g_return_if_fail (path != NULL || iter != NULL);
8362
8363   if (tree_view->priv->cursor != NULL)
8364     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8365   else
8366     cursor_path = NULL;
8367
8368   if (tree_view->priv->edited_column &&
8369       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8370     gtk_tree_view_stop_editing (tree_view, TRUE);
8371
8372   if (cursor_path != NULL)
8373     gtk_tree_path_free (cursor_path);
8374
8375   if (path == NULL)
8376     {
8377       path = gtk_tree_model_get_path (model, iter);
8378       free_path = TRUE;
8379     }
8380   else if (iter == NULL)
8381     gtk_tree_model_get_iter (model, iter, path);
8382
8383   if (_gtk_tree_view_find_node (tree_view,
8384                                 path,
8385                                 &tree,
8386                                 &node))
8387     /* We aren't actually showing the node */
8388     goto done;
8389
8390   if (tree == NULL)
8391     goto done;
8392
8393   if (tree_view->priv->fixed_height_mode
8394       && tree_view->priv->fixed_height >= 0)
8395     {
8396       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8397       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8398         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8399     }
8400   else
8401     {
8402       _gtk_rbtree_node_mark_invalid (tree, node);
8403       for (list = tree_view->priv->columns; list; list = list->next)
8404         {
8405           GtkTreeViewColumn *column;
8406
8407           column = list->data;
8408           if (! column->visible)
8409             continue;
8410
8411           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8412             {
8413               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8414             }
8415         }
8416     }
8417
8418  done:
8419   if (!tree_view->priv->fixed_height_mode &&
8420       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8421     install_presize_handler (tree_view);
8422   if (free_path)
8423     gtk_tree_path_free (path);
8424 }
8425
8426 static void
8427 gtk_tree_view_row_inserted (GtkTreeModel *model,
8428                             GtkTreePath  *path,
8429                             GtkTreeIter  *iter,
8430                             gpointer      data)
8431 {
8432   GtkTreeView *tree_view = (GtkTreeView *) data;
8433   gint *indices;
8434   GtkRBTree *tmptree, *tree;
8435   GtkRBNode *tmpnode = NULL;
8436   gint depth;
8437   gint i = 0;
8438   gint height;
8439   gboolean free_path = FALSE;
8440   gboolean node_visible = TRUE;
8441
8442   g_return_if_fail (path != NULL || iter != NULL);
8443
8444   if (tree_view->priv->fixed_height_mode
8445       && tree_view->priv->fixed_height >= 0)
8446     height = tree_view->priv->fixed_height;
8447   else
8448     height = 0;
8449
8450   if (path == NULL)
8451     {
8452       path = gtk_tree_model_get_path (model, iter);
8453       free_path = TRUE;
8454     }
8455   else if (iter == NULL)
8456     gtk_tree_model_get_iter (model, iter, path);
8457
8458   if (tree_view->priv->tree == NULL)
8459     tree_view->priv->tree = _gtk_rbtree_new ();
8460
8461   tmptree = tree = tree_view->priv->tree;
8462
8463   /* Update all row-references */
8464   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8465   depth = gtk_tree_path_get_depth (path);
8466   indices = gtk_tree_path_get_indices (path);
8467
8468   /* First, find the parent tree */
8469   while (i < depth - 1)
8470     {
8471       if (tmptree == NULL)
8472         {
8473           /* We aren't showing the node */
8474           node_visible = FALSE;
8475           goto done;
8476         }
8477
8478       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8479       if (tmpnode == NULL)
8480         {
8481           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8482                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8483                      "before the parent was inserted.");
8484           goto done;
8485         }
8486       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8487         {
8488           /* FIXME enforce correct behavior on model, probably */
8489           /* In theory, the model should have emitted has_child_toggled here.  We
8490            * try to catch it anyway, just to be safe, in case the model hasn't.
8491            */
8492           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8493                                                            tree,
8494                                                            tmpnode);
8495           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8496           gtk_tree_path_free (tmppath);
8497           goto done;
8498         }
8499
8500       tmptree = tmpnode->children;
8501       tree = tmptree;
8502       i++;
8503     }
8504
8505   if (tree == NULL)
8506     {
8507       node_visible = FALSE;
8508       goto done;
8509     }
8510
8511   /* ref the node */
8512   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8513   if (indices[depth - 1] == 0)
8514     {
8515       tmpnode = _gtk_rbtree_find_count (tree, 1);
8516       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8517     }
8518   else
8519     {
8520       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8521       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8522     }
8523
8524  done:
8525   if (height > 0)
8526     {
8527       if (tree)
8528         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8529
8530       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8531         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8532       else
8533         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8534     }
8535   else
8536     install_presize_handler (tree_view);
8537   if (free_path)
8538     gtk_tree_path_free (path);
8539 }
8540
8541 static void
8542 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8543                                      GtkTreePath  *path,
8544                                      GtkTreeIter  *iter,
8545                                      gpointer      data)
8546 {
8547   GtkTreeView *tree_view = (GtkTreeView *)data;
8548   GtkTreeIter real_iter;
8549   gboolean has_child;
8550   GtkRBTree *tree;
8551   GtkRBNode *node;
8552   gboolean free_path = FALSE;
8553
8554   g_return_if_fail (path != NULL || iter != NULL);
8555
8556   if (iter)
8557     real_iter = *iter;
8558
8559   if (path == NULL)
8560     {
8561       path = gtk_tree_model_get_path (model, iter);
8562       free_path = TRUE;
8563     }
8564   else if (iter == NULL)
8565     gtk_tree_model_get_iter (model, &real_iter, path);
8566
8567   if (_gtk_tree_view_find_node (tree_view,
8568                                 path,
8569                                 &tree,
8570                                 &node))
8571     /* We aren't actually showing the node */
8572     goto done;
8573
8574   if (tree == NULL)
8575     goto done;
8576
8577   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8578   /* Sanity check.
8579    */
8580   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8581     goto done;
8582
8583   if (has_child)
8584     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8585   else
8586     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8587
8588   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8589     {
8590       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8591       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8592         {
8593           GList *list;
8594
8595           for (list = tree_view->priv->columns; list; list = list->next)
8596             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8597               {
8598                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8599                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8600                 break;
8601               }
8602         }
8603       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8604     }
8605   else
8606     {
8607       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8608     }
8609
8610  done:
8611   if (free_path)
8612     gtk_tree_path_free (path);
8613 }
8614
8615 static void
8616 count_children_helper (GtkRBTree *tree,
8617                        GtkRBNode *node,
8618                        gpointer   data)
8619 {
8620   if (node->children)
8621     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8622   (*((gint *)data))++;
8623 }
8624
8625 static void
8626 check_selection_helper (GtkRBTree *tree,
8627                         GtkRBNode *node,
8628                         gpointer   data)
8629 {
8630   gint *value = (gint *)data;
8631
8632   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8633
8634   if (node->children && !*value)
8635     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8636 }
8637
8638 static void
8639 gtk_tree_view_row_deleted (GtkTreeModel *model,
8640                            GtkTreePath  *path,
8641                            gpointer      data)
8642 {
8643   GtkTreeView *tree_view = (GtkTreeView *)data;
8644   GtkRBTree *tree;
8645   GtkRBNode *node;
8646   GList *list;
8647   gint selection_changed = FALSE;
8648
8649   g_return_if_fail (path != NULL);
8650
8651   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8652
8653   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8654     return;
8655
8656   if (tree == NULL)
8657     return;
8658
8659   /* check if the selection has been changed */
8660   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8661                         check_selection_helper, &selection_changed);
8662
8663   for (list = tree_view->priv->columns; list; list = list->next)
8664     if (((GtkTreeViewColumn *)list->data)->visible &&
8665         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8666       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8667
8668   /* Ensure we don't have a dangling pointer to a dead node */
8669   ensure_unprelighted (tree_view);
8670
8671   /* Cancel editting if we've started */
8672   gtk_tree_view_stop_editing (tree_view, TRUE);
8673
8674   /* If we have a node expanded/collapsed timeout, remove it */
8675   remove_expand_collapse_timeout (tree_view);
8676
8677   if (tree_view->priv->destroy_count_func)
8678     {
8679       gint child_count = 0;
8680       if (node->children)
8681         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8682       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8683     }
8684
8685   if (tree->root->count == 1)
8686     {
8687       if (tree_view->priv->tree == tree)
8688         tree_view->priv->tree = NULL;
8689
8690       _gtk_rbtree_remove (tree);
8691     }
8692   else
8693     {
8694       _gtk_rbtree_remove_node (tree, node);
8695     }
8696
8697   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8698     {
8699       gtk_tree_row_reference_free (tree_view->priv->top_row);
8700       tree_view->priv->top_row = NULL;
8701     }
8702
8703   install_scroll_sync_handler (tree_view);
8704
8705   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8706
8707   if (selection_changed)
8708     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8709 }
8710
8711 static void
8712 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8713                               GtkTreePath  *parent,
8714                               GtkTreeIter  *iter,
8715                               gint         *new_order,
8716                               gpointer      data)
8717 {
8718   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8719   GtkRBTree *tree;
8720   GtkRBNode *node;
8721   gint len;
8722
8723   len = gtk_tree_model_iter_n_children (model, iter);
8724
8725   if (len < 2)
8726     return;
8727
8728   gtk_tree_row_reference_reordered (G_OBJECT (data),
8729                                     parent,
8730                                     iter,
8731                                     new_order);
8732
8733   if (_gtk_tree_view_find_node (tree_view,
8734                                 parent,
8735                                 &tree,
8736                                 &node))
8737     return;
8738
8739   /* We need to special case the parent path */
8740   if (tree == NULL)
8741     tree = tree_view->priv->tree;
8742   else
8743     tree = node->children;
8744
8745   if (tree == NULL)
8746     return;
8747
8748   if (tree_view->priv->edited_column)
8749     gtk_tree_view_stop_editing (tree_view, TRUE);
8750
8751   /* we need to be unprelighted */
8752   ensure_unprelighted (tree_view);
8753
8754   /* clear the timeout */
8755   cancel_arrow_animation (tree_view);
8756   
8757   _gtk_rbtree_reorder (tree, new_order, len);
8758
8759   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8760
8761   gtk_tree_view_dy_to_top_row (tree_view);
8762 }
8763
8764
8765 /* Internal tree functions
8766  */
8767
8768
8769 static void
8770 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8771                                      GtkRBTree         *tree,
8772                                      GtkTreeViewColumn *column,
8773                                      gint              *x1,
8774                                      gint              *x2)
8775 {
8776   GtkTreeViewColumn *tmp_column = NULL;
8777   gint total_width;
8778   GList *list;
8779   gboolean rtl;
8780
8781   if (x1)
8782     *x1 = 0;
8783
8784   if (x2)
8785     *x2 = 0;
8786
8787   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8788
8789   total_width = 0;
8790   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8791        list;
8792        list = (rtl ? list->prev : list->next))
8793     {
8794       tmp_column = list->data;
8795
8796       if (tmp_column == column)
8797         break;
8798
8799       if (tmp_column->visible)
8800         total_width += tmp_column->width;
8801     }
8802
8803   if (tmp_column != column)
8804     {
8805       g_warning (G_STRLOC": passed-in column isn't in the tree");
8806       return;
8807     }
8808
8809   if (x1)
8810     *x1 = total_width;
8811
8812   if (x2)
8813     {
8814       if (column->visible)
8815         *x2 = total_width + column->width;
8816       else
8817         *x2 = total_width; /* width of 0 */
8818     }
8819 }
8820 static void
8821 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8822                                 GtkRBTree   *tree,
8823                                 gint        *x1,
8824                                 gint        *x2)
8825 {
8826   gint x_offset = 0;
8827   GList *list;
8828   GtkTreeViewColumn *tmp_column = NULL;
8829   gint total_width;
8830   gboolean indent_expanders;
8831   gboolean rtl;
8832
8833   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8834
8835   total_width = 0;
8836   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8837        list;
8838        list = (rtl ? list->prev : list->next))
8839     {
8840       tmp_column = list->data;
8841
8842       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8843         {
8844           if (rtl)
8845             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8846           else
8847             x_offset = total_width;
8848           break;
8849         }
8850
8851       if (tmp_column->visible)
8852         total_width += tmp_column->width;
8853     }
8854
8855   gtk_widget_style_get (GTK_WIDGET (tree_view),
8856                         "indent-expanders", &indent_expanders,
8857                         NULL);
8858
8859   if (indent_expanders)
8860     {
8861       if (rtl)
8862         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8863       else
8864         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8865     }
8866
8867   *x1 = x_offset;
8868   
8869   if (tmp_column && tmp_column->visible)
8870     /* +1 because x2 isn't included in the range. */
8871     *x2 = *x1 + tree_view->priv->expander_size + 1;
8872   else
8873     *x2 = *x1;
8874 }
8875
8876 static void
8877 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8878                           GtkRBTree   *tree,
8879                           GtkTreeIter *iter,
8880                           gint         depth,
8881                           gboolean     recurse)
8882 {
8883   GtkRBNode *temp = NULL;
8884   GtkTreePath *path = NULL;
8885   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8886
8887   do
8888     {
8889       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8890       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8891
8892       if (tree_view->priv->fixed_height > 0)
8893         {
8894           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8895             {
8896               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8897               _gtk_rbtree_node_mark_valid (tree, temp);
8898             }
8899         }
8900
8901       if (is_list)
8902         continue;
8903
8904       if (recurse)
8905         {
8906           GtkTreeIter child;
8907
8908           if (!path)
8909             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8910           else
8911             gtk_tree_path_next (path);
8912
8913           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8914             {
8915               gboolean expand;
8916
8917               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8918
8919               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8920                   && !expand)
8921                 {
8922                   temp->children = _gtk_rbtree_new ();
8923                   temp->children->parent_tree = tree;
8924                   temp->children->parent_node = temp;
8925                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8926                 }
8927             }
8928         }
8929
8930       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8931         {
8932           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8933             temp->flags ^= GTK_RBNODE_IS_PARENT;
8934         }
8935     }
8936   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8937
8938   if (path)
8939     gtk_tree_path_free (path);
8940 }
8941
8942 /* Make sure the node is visible vertically */
8943 static void
8944 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8945                                   GtkRBTree   *tree,
8946                                   GtkRBNode   *node)
8947 {
8948   gint node_dy, height;
8949   GtkTreePath *path = NULL;
8950
8951   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8952     return;
8953
8954   /* just return if the node is visible, avoiding a costly expose */
8955   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8956   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8957   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8958       && node_dy >= tree_view->priv->vadjustment->value
8959       && node_dy + height <= (tree_view->priv->vadjustment->value
8960                               + tree_view->priv->vadjustment->page_size))
8961     return;
8962
8963   path = _gtk_tree_view_find_path (tree_view, tree, node);
8964   if (path)
8965     {
8966       /* We process updates because we want to clear old selected items when we scroll.
8967        * if this is removed, we get a "selection streak" at the bottom. */
8968       gtk_tree_view_bin_process_updates (tree_view);
8969
8970       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8971       gtk_tree_path_free (path);
8972     }
8973 }
8974
8975 static void
8976 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8977                                     GtkTreeViewColumn *column,
8978                                     gboolean           focus_to_cell)
8979 {
8980   GtkAllocation allocation;
8981   gint x, width;
8982
8983   if (column == NULL)
8984     return;
8985
8986   gtk_widget_get_allocation (column->button, &allocation);
8987   x = allocation.x;
8988   width = allocation.width;
8989
8990   if (width > tree_view->priv->hadjustment->page_size)
8991     {
8992       /* The column is larger than the horizontal page size.  If the
8993        * column has cells which can be focussed individually, then we make
8994        * sure the cell which gets focus is fully visible (if even the
8995        * focus cell is bigger than the page size, we make sure the
8996        * left-hand side of the cell is visible).
8997        *
8998        * If the column does not have those so-called special cells, we
8999        * make sure the left-hand side of the column is visible.
9000        */
9001
9002       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
9003         {
9004           GtkTreePath *cursor_path;
9005           GdkRectangle background_area, cell_area, focus_area;
9006
9007           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9008
9009           gtk_tree_view_get_cell_area (tree_view,
9010                                        cursor_path, column, &cell_area);
9011           gtk_tree_view_get_background_area (tree_view,
9012                                              cursor_path, column,
9013                                              &background_area);
9014
9015           gtk_tree_path_free (cursor_path);
9016
9017           _gtk_tree_view_column_get_focus_area (column,
9018                                                 &background_area,
9019                                                 &cell_area,
9020                                                 &focus_area);
9021
9022           x = focus_area.x;
9023           width = focus_area.width;
9024
9025           if (width < tree_view->priv->hadjustment->page_size)
9026             {
9027               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
9028                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
9029                                           x + width - tree_view->priv->hadjustment->page_size);
9030               else if (tree_view->priv->hadjustment->value > x)
9031                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9032             }
9033         }
9034
9035       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9036     }
9037   else
9038     {
9039       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
9040           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9041                                     x + width - tree_view->priv->hadjustment->page_size);
9042       else if (tree_view->priv->hadjustment->value > x)
9043         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9044   }
9045 }
9046
9047 /* This function could be more efficient.  I'll optimize it if profiling seems
9048  * to imply that it is important */
9049 GtkTreePath *
9050 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9051                           GtkRBTree   *tree,
9052                           GtkRBNode   *node)
9053 {
9054   GtkTreePath *path;
9055   GtkRBTree *tmp_tree;
9056   GtkRBNode *tmp_node, *last;
9057   gint count;
9058
9059   path = gtk_tree_path_new ();
9060
9061   g_return_val_if_fail (node != NULL, path);
9062   g_return_val_if_fail (node != tree->nil, path);
9063
9064   count = 1 + node->left->count;
9065
9066   last = node;
9067   tmp_node = node->parent;
9068   tmp_tree = tree;
9069   while (tmp_tree)
9070     {
9071       while (tmp_node != tmp_tree->nil)
9072         {
9073           if (tmp_node->right == last)
9074             count += 1 + tmp_node->left->count;
9075           last = tmp_node;
9076           tmp_node = tmp_node->parent;
9077         }
9078       gtk_tree_path_prepend_index (path, count - 1);
9079       last = tmp_tree->parent_node;
9080       tmp_tree = tmp_tree->parent_tree;
9081       if (last)
9082         {
9083           count = 1 + last->left->count;
9084           tmp_node = last->parent;
9085         }
9086     }
9087   return path;
9088 }
9089
9090 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9091  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9092  * both set to NULL.
9093  */
9094 gboolean
9095 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9096                           GtkTreePath  *path,
9097                           GtkRBTree   **tree,
9098                           GtkRBNode   **node)
9099 {
9100   GtkRBNode *tmpnode = NULL;
9101   GtkRBTree *tmptree = tree_view->priv->tree;
9102   gint *indices = gtk_tree_path_get_indices (path);
9103   gint depth = gtk_tree_path_get_depth (path);
9104   gint i = 0;
9105
9106   *node = NULL;
9107   *tree = NULL;
9108
9109   if (depth == 0 || tmptree == NULL)
9110     return FALSE;
9111   do
9112     {
9113       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9114       ++i;
9115       if (tmpnode == NULL)
9116         {
9117           *tree = NULL;
9118           *node = NULL;
9119           return FALSE;
9120         }
9121       if (i >= depth)
9122         {
9123           *tree = tmptree;
9124           *node = tmpnode;
9125           return FALSE;
9126         }
9127       *tree = tmptree;
9128       *node = tmpnode;
9129       tmptree = tmpnode->children;
9130       if (tmptree == NULL)
9131         return TRUE;
9132     }
9133   while (1);
9134 }
9135
9136 static gboolean
9137 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9138                                   GtkTreeViewColumn *column)
9139 {
9140   GList *list;
9141
9142   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9143     return FALSE;
9144
9145   if (tree_view->priv->expander_column != NULL)
9146     {
9147       if (tree_view->priv->expander_column == column)
9148         return TRUE;
9149       return FALSE;
9150     }
9151   else
9152     {
9153       for (list = tree_view->priv->columns;
9154            list;
9155            list = list->next)
9156         if (((GtkTreeViewColumn *)list->data)->visible)
9157           break;
9158       if (list && list->data == column)
9159         return TRUE;
9160     }
9161   return FALSE;
9162 }
9163
9164 static void
9165 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9166                                 guint           keyval,
9167                                 guint           modmask,
9168                                 gboolean        add_shifted_binding,
9169                                 GtkMovementStep step,
9170                                 gint            count)
9171 {
9172   
9173   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9174                                 "move-cursor", 2,
9175                                 G_TYPE_ENUM, step,
9176                                 G_TYPE_INT, count);
9177
9178   if (add_shifted_binding)
9179     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9180                                   "move-cursor", 2,
9181                                   G_TYPE_ENUM, step,
9182                                   G_TYPE_INT, count);
9183
9184   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9185    return;
9186
9187   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9188                                 "move-cursor", 2,
9189                                 G_TYPE_ENUM, step,
9190                                 G_TYPE_INT, count);
9191
9192   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9193                                 "move-cursor", 2,
9194                                 G_TYPE_ENUM, step,
9195                                 G_TYPE_INT, count);
9196 }
9197
9198 static gint
9199 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9200                                  GtkTreeIter  *iter,
9201                                  GtkRBTree    *tree,
9202                                  GtkRBNode    *node)
9203 {
9204   gint retval = FALSE;
9205   do
9206     {
9207       g_return_val_if_fail (node != NULL, FALSE);
9208
9209       if (node->children)
9210         {
9211           GtkTreeIter child;
9212           GtkRBTree *new_tree;
9213           GtkRBNode *new_node;
9214
9215           new_tree = node->children;
9216           new_node = new_tree->root;
9217
9218           while (new_node && new_node->left != new_tree->nil)
9219             new_node = new_node->left;
9220
9221           if (!gtk_tree_model_iter_children (model, &child, iter))
9222             return FALSE;
9223
9224           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9225         }
9226
9227       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9228         retval = TRUE;
9229       gtk_tree_model_unref_node (model, iter);
9230       node = _gtk_rbtree_next (tree, node);
9231     }
9232   while (gtk_tree_model_iter_next (model, iter));
9233
9234   return retval;
9235 }
9236
9237 static gint
9238 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9239                                               GtkRBTree   *tree)
9240 {
9241   GtkTreeIter iter;
9242   GtkTreePath *path;
9243   GtkRBNode *node;
9244   gint retval;
9245
9246   if (!tree)
9247     return FALSE;
9248
9249   node = tree->root;
9250   while (node && node->left != tree->nil)
9251     node = node->left;
9252
9253   g_return_val_if_fail (node != NULL, FALSE);
9254   path = _gtk_tree_view_find_path (tree_view, tree, node);
9255   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9256                            &iter, path);
9257   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9258   gtk_tree_path_free (path);
9259
9260   return retval;
9261 }
9262
9263 static void
9264 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9265                                     GtkTreeViewColumn *column)
9266 {
9267   GtkTreeViewColumn *left_column;
9268   GtkTreeViewColumn *cur_column = NULL;
9269   GtkTreeViewColumnReorder *reorder;
9270   gboolean rtl;
9271   GList *tmp_list;
9272   gint left;
9273
9274   /* We want to precalculate the motion list such that we know what column slots
9275    * are available.
9276    */
9277   left_column = NULL;
9278   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9279
9280   /* First, identify all possible drop spots */
9281   if (rtl)
9282     tmp_list = g_list_last (tree_view->priv->columns);
9283   else
9284     tmp_list = g_list_first (tree_view->priv->columns);
9285
9286   while (tmp_list)
9287     {
9288       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9289       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9290
9291       if (cur_column->visible == FALSE)
9292         continue;
9293
9294       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9295       if (left_column != column && cur_column != column &&
9296           tree_view->priv->column_drop_func &&
9297           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9298         {
9299           left_column = cur_column;
9300           continue;
9301         }
9302       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9303       reorder->left_column = left_column;
9304       left_column = reorder->right_column = cur_column;
9305
9306       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9307     }
9308
9309   /* Add the last one */
9310   if (tree_view->priv->column_drop_func == NULL ||
9311       ((left_column != column) &&
9312        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9313     {
9314       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9315       reorder->left_column = left_column;
9316       reorder->right_column = NULL;
9317       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9318     }
9319
9320   /* We quickly check to see if it even makes sense to reorder columns. */
9321   /* If there is nothing that can be moved, then we return */
9322
9323   if (tree_view->priv->column_drag_info == NULL)
9324     return;
9325
9326   /* We know there are always 2 slots possbile, as you can always return column. */
9327   /* If that's all there is, return */
9328   if (tree_view->priv->column_drag_info->next == NULL || 
9329       (tree_view->priv->column_drag_info->next->next == NULL &&
9330        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9331        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9332     {
9333       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9334         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9335       g_list_free (tree_view->priv->column_drag_info);
9336       tree_view->priv->column_drag_info = NULL;
9337       return;
9338     }
9339   /* We fill in the ranges for the columns, now that we've isolated them */
9340   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9341
9342   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9343     {
9344       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9345
9346       reorder->left_align = left;
9347       if (tmp_list->next != NULL)
9348         {
9349           GtkAllocation right_allocation, left_allocation;
9350
9351           g_assert (tmp_list->next->data);
9352
9353           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
9354           gtk_widget_get_allocation (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button, &left_allocation);
9355           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9356         }
9357       else
9358         {
9359           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9360                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9361         }
9362     }
9363 }
9364
9365 void
9366 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9367                                   GtkTreeViewColumn *column,
9368                                   GdkDevice         *device)
9369 {
9370   GdkEvent *send_event;
9371   GtkAllocation allocation;
9372   GtkAllocation button_allocation;
9373   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9374   GdkDisplay *display = gdk_screen_get_display (screen);
9375
9376   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9377   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9378
9379   gtk_tree_view_set_column_drag_info (tree_view, column);
9380
9381   if (tree_view->priv->column_drag_info == NULL)
9382     return;
9383
9384   if (tree_view->priv->drag_window == NULL)
9385     {
9386       GdkWindowAttr attributes;
9387       guint attributes_mask;
9388
9389       gtk_widget_get_allocation (column->button, &button_allocation);
9390
9391       attributes.window_type = GDK_WINDOW_CHILD;
9392       attributes.wclass = GDK_INPUT_OUTPUT;
9393       attributes.x = button_allocation.x;
9394       attributes.y = 0;
9395       attributes.width = button_allocation.width;
9396       attributes.height = button_allocation.height;
9397       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9398       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9399       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9400
9401       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9402                                                      &attributes,
9403                                                      attributes_mask);
9404       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9405     }
9406
9407   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9408   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9409
9410   gtk_grab_remove (column->button);
9411
9412   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9413   send_event->crossing.send_event = TRUE;
9414   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (column->button)));
9415   send_event->crossing.subwindow = NULL;
9416   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9417   send_event->crossing.time = GDK_CURRENT_TIME;
9418   gdk_event_set_device (send_event, device);
9419
9420   gtk_propagate_event (column->button, send_event);
9421   gdk_event_free (send_event);
9422
9423   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9424   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9425   send_event->button.send_event = TRUE;
9426   send_event->button.time = GDK_CURRENT_TIME;
9427   send_event->button.x = -1;
9428   send_event->button.y = -1;
9429   send_event->button.axes = NULL;
9430   send_event->button.state = 0;
9431   send_event->button.button = 1;
9432   send_event->button.x_root = 0;
9433   send_event->button.y_root = 0;
9434   gdk_event_set_device (send_event, device);
9435
9436   gtk_propagate_event (column->button, send_event);
9437   gdk_event_free (send_event);
9438
9439   /* Kids, don't try this at home */
9440   g_object_ref (column->button);
9441   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9442   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9443   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9444   g_object_unref (column->button);
9445
9446   gtk_widget_get_allocation (column->button, &button_allocation);
9447   tree_view->priv->drag_column_x = button_allocation.x;
9448   allocation = button_allocation;
9449   allocation.x = 0;
9450   gtk_widget_size_allocate (column->button, &allocation);
9451   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9452
9453   tree_view->priv->drag_column = column;
9454   gdk_window_show (tree_view->priv->drag_window);
9455
9456   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9457   while (gtk_events_pending ())
9458     gtk_main_iteration ();
9459
9460   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9461   gdk_pointer_grab (tree_view->priv->drag_window,
9462                     FALSE,
9463                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9464                     NULL, NULL, GDK_CURRENT_TIME);
9465   gdk_keyboard_grab (tree_view->priv->drag_window,
9466                      FALSE,
9467                      GDK_CURRENT_TIME);
9468 }
9469
9470 static void
9471 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9472                                 GtkRBTree          *tree,
9473                                 GtkRBNode          *node)
9474 {
9475   GtkAllocation allocation;
9476   GdkRectangle rect;
9477
9478   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9479     return;
9480
9481   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9482   rect.x = 0;
9483   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9484
9485   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9486   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9487
9488   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9489 }
9490
9491 void
9492 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9493                                 GtkRBTree          *tree,
9494                                 GtkRBNode          *node,
9495                                 const GdkRectangle *clip_rect)
9496 {
9497   GtkAllocation allocation;
9498   GdkRectangle rect;
9499
9500   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9501     return;
9502
9503   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9504   rect.x = 0;
9505   rect.width = MAX (tree_view->priv->width, allocation.width);
9506
9507   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9508   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9509
9510   if (clip_rect)
9511     {
9512       GdkRectangle new_rect;
9513
9514       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9515
9516       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9517     }
9518   else
9519     {
9520       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9521     }
9522 }
9523
9524 static void
9525 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9526                                GtkTreePath        *path,
9527                                const GdkRectangle *clip_rect)
9528 {
9529   GtkRBTree *tree = NULL;
9530   GtkRBNode *node = NULL;
9531
9532   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9533
9534   if (tree)
9535     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9536 }
9537
9538 /* x and y are the mouse position
9539  */
9540 static void
9541 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9542                           cairo_t     *cr,
9543                           GtkRBTree   *tree,
9544                           GtkRBNode   *node,
9545                           /* in bin_window coordinates */
9546                           gint         x,
9547                           gint         y)
9548 {
9549   GdkRectangle area;
9550   GtkStateType state;
9551   GtkWidget *widget;
9552   gint x_offset = 0;
9553   gint x2;
9554   gint vertical_separator;
9555   gint expander_size;
9556   GtkExpanderStyle expander_style;
9557
9558   widget = GTK_WIDGET (tree_view);
9559
9560   gtk_widget_style_get (widget,
9561                         "vertical-separator", &vertical_separator,
9562                         NULL);
9563   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9564
9565   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9566     return;
9567
9568   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9569
9570   area.x = x_offset;
9571   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9572   area.width = expander_size + 2;
9573   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9574
9575   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9576     {
9577       state = GTK_STATE_INSENSITIVE;
9578     }
9579   else if (node == tree_view->priv->button_pressed_node)
9580     {
9581       if (x >= area.x && x <= (area.x + area.width) &&
9582           y >= area.y && y <= (area.y + area.height))
9583         state = GTK_STATE_ACTIVE;
9584       else
9585         state = GTK_STATE_NORMAL;
9586     }
9587   else
9588     {
9589       if (node == tree_view->priv->prelight_node &&
9590           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9591         state = GTK_STATE_PRELIGHT;
9592       else
9593         state = GTK_STATE_NORMAL;
9594     }
9595
9596   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9597     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9598   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9599     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9600   else if (node->children != NULL)
9601     expander_style = GTK_EXPANDER_EXPANDED;
9602   else
9603     expander_style = GTK_EXPANDER_COLLAPSED;
9604
9605   gtk_paint_expander (gtk_widget_get_style (widget),
9606                       cr,
9607                       state,
9608                       widget,
9609                       "treeview",
9610                       area.x + area.width / 2,
9611                       area.y + area.height / 2,
9612                       expander_style);
9613 }
9614
9615 static void
9616 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9617
9618 {
9619   GtkTreePath *cursor_path;
9620
9621   if ((tree_view->priv->tree == NULL) ||
9622       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
9623     return;
9624
9625   cursor_path = NULL;
9626   if (tree_view->priv->cursor)
9627     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9628
9629   if (cursor_path == NULL)
9630     {
9631       /* Consult the selection before defaulting to the
9632        * first focusable element
9633        */
9634       GList *selected_rows;
9635       GtkTreeModel *model;
9636       GtkTreeSelection *selection;
9637
9638       selection = gtk_tree_view_get_selection (tree_view);
9639       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9640
9641       if (selected_rows)
9642         {
9643           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9644           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9645           g_list_free (selected_rows);
9646         }
9647       else
9648         {
9649           cursor_path = gtk_tree_path_new_first ();
9650           search_first_focusable_path (tree_view, &cursor_path,
9651                                        TRUE, NULL, NULL);
9652         }
9653
9654       gtk_tree_row_reference_free (tree_view->priv->cursor);
9655       tree_view->priv->cursor = NULL;
9656
9657       if (cursor_path)
9658         {
9659           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9660             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9661           else
9662             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9663         }
9664     }
9665
9666   if (cursor_path)
9667     {
9668       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9669
9670       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9671       gtk_tree_path_free (cursor_path);
9672
9673       if (tree_view->priv->focus_column == NULL)
9674         {
9675           GList *list;
9676           for (list = tree_view->priv->columns; list; list = list->next)
9677             {
9678               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9679                 {
9680                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9681                   break;
9682                 }
9683             }
9684         }
9685     }
9686 }
9687
9688 static void
9689 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9690                                    gint         count)
9691 {
9692   gint selection_count;
9693   GtkRBTree *cursor_tree = NULL;
9694   GtkRBNode *cursor_node = NULL;
9695   GtkRBTree *new_cursor_tree = NULL;
9696   GtkRBNode *new_cursor_node = NULL;
9697   GtkTreePath *cursor_path = NULL;
9698   gboolean grab_focus = TRUE;
9699   gboolean selectable;
9700
9701   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9702     return;
9703
9704   cursor_path = NULL;
9705   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9706     /* FIXME: we lost the cursor; should we get the first? */
9707     return;
9708
9709   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9710   _gtk_tree_view_find_node (tree_view, cursor_path,
9711                             &cursor_tree, &cursor_node);
9712
9713   if (cursor_tree == NULL)
9714     /* FIXME: we lost the cursor; should we get the first? */
9715     return;
9716
9717   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9718   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9719                                                       cursor_node,
9720                                                       cursor_path);
9721
9722   if (selection_count == 0
9723       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9724       && !tree_view->priv->ctrl_pressed
9725       && selectable)
9726     {
9727       /* Don't move the cursor, but just select the current node */
9728       new_cursor_tree = cursor_tree;
9729       new_cursor_node = cursor_node;
9730     }
9731   else
9732     {
9733       if (count == -1)
9734         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9735                                &new_cursor_tree, &new_cursor_node);
9736       else
9737         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9738                                &new_cursor_tree, &new_cursor_node);
9739     }
9740
9741   gtk_tree_path_free (cursor_path);
9742
9743   if (new_cursor_node)
9744     {
9745       cursor_path = _gtk_tree_view_find_path (tree_view,
9746                                               new_cursor_tree, new_cursor_node);
9747
9748       search_first_focusable_path (tree_view, &cursor_path,
9749                                    (count != -1),
9750                                    &new_cursor_tree,
9751                                    &new_cursor_node);
9752
9753       if (cursor_path)
9754         gtk_tree_path_free (cursor_path);
9755     }
9756
9757   /*
9758    * If the list has only one item and multi-selection is set then select
9759    * the row (if not yet selected).
9760    */
9761   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9762       new_cursor_node == NULL)
9763     {
9764       if (count == -1)
9765         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9766                                &new_cursor_tree, &new_cursor_node);
9767       else
9768         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9769                                &new_cursor_tree, &new_cursor_node);
9770
9771       if (new_cursor_node == NULL
9772           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9773         {
9774           new_cursor_node = cursor_node;
9775           new_cursor_tree = cursor_tree;
9776         }
9777       else
9778         {
9779           new_cursor_node = NULL;
9780         }
9781     }
9782
9783   if (new_cursor_node)
9784     {
9785       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9786       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9787       gtk_tree_path_free (cursor_path);
9788     }
9789   else
9790     {
9791       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9792
9793       if (!tree_view->priv->shift_pressed)
9794         {
9795           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9796                                           count < 0 ?
9797                                           GTK_DIR_UP : GTK_DIR_DOWN))
9798             {
9799               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9800
9801               if (toplevel)
9802                 gtk_widget_child_focus (toplevel,
9803                                         count < 0 ?
9804                                         GTK_DIR_TAB_BACKWARD :
9805                                         GTK_DIR_TAB_FORWARD);
9806
9807               grab_focus = FALSE;
9808             }
9809         }
9810       else
9811         {
9812           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9813         }
9814     }
9815
9816   if (grab_focus)
9817     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9818 }
9819
9820 static void
9821 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9822                                         gint         count)
9823 {
9824   GtkRBTree *cursor_tree = NULL;
9825   GtkRBNode *cursor_node = NULL;
9826   GtkTreePath *old_cursor_path = NULL;
9827   GtkTreePath *cursor_path = NULL;
9828   GtkRBTree *start_cursor_tree = NULL;
9829   GtkRBNode *start_cursor_node = NULL;
9830   gint y;
9831   gint window_y;
9832   gint vertical_separator;
9833
9834   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9835     return;
9836
9837   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9838     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9839   else
9840     /* This is sorta weird.  Focus in should give us a cursor */
9841     return;
9842
9843   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9844   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9845                             &cursor_tree, &cursor_node);
9846
9847   if (cursor_tree == NULL)
9848     {
9849       /* FIXME: we lost the cursor.  Should we try to get one? */
9850       gtk_tree_path_free (old_cursor_path);
9851       return;
9852     }
9853   g_return_if_fail (cursor_node != NULL);
9854
9855   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9856   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9857   y += tree_view->priv->cursor_offset;
9858   y += count * (int)tree_view->priv->vadjustment->page_increment;
9859   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9860
9861   if (y >= tree_view->priv->height)
9862     y = tree_view->priv->height - 1;
9863
9864   tree_view->priv->cursor_offset =
9865     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9866                              &cursor_tree, &cursor_node);
9867
9868   if (cursor_tree == NULL)
9869     {
9870       /* FIXME: we lost the cursor.  Should we try to get one? */
9871       gtk_tree_path_free (old_cursor_path);
9872       return;
9873     }
9874
9875   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9876     {
9877       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9878                              &cursor_tree, &cursor_node);
9879       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9880     }
9881
9882   y -= tree_view->priv->cursor_offset;
9883   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9884
9885   start_cursor_tree = cursor_tree;
9886   start_cursor_node = cursor_node;
9887
9888   if (! search_first_focusable_path (tree_view, &cursor_path,
9889                                      (count != -1),
9890                                      &cursor_tree, &cursor_node))
9891     {
9892       /* It looks like we reached the end of the view without finding
9893        * a focusable row.  We will step backwards to find the last
9894        * focusable row.
9895        */
9896       cursor_tree = start_cursor_tree;
9897       cursor_node = start_cursor_node;
9898       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9899
9900       search_first_focusable_path (tree_view, &cursor_path,
9901                                    (count == -1),
9902                                    &cursor_tree, &cursor_node);
9903     }
9904
9905   if (!cursor_path)
9906     goto cleanup;
9907
9908   /* update y */
9909   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9910
9911   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9912
9913   y -= window_y;
9914   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9915   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9916   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9917
9918   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9919     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9920
9921   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9922
9923 cleanup:
9924   gtk_tree_path_free (old_cursor_path);
9925   gtk_tree_path_free (cursor_path);
9926 }
9927
9928 static void
9929 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9930                                       gint         count)
9931 {
9932   GtkRBTree *cursor_tree = NULL;
9933   GtkRBNode *cursor_node = NULL;
9934   GtkTreePath *cursor_path = NULL;
9935   GtkTreeViewColumn *column;
9936   GtkTreeIter iter;
9937   GList *list;
9938   gboolean found_column = FALSE;
9939   gboolean rtl;
9940
9941   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9942
9943   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9944     return;
9945
9946   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9947     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9948   else
9949     return;
9950
9951   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9952   if (cursor_tree == NULL)
9953     return;
9954   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9955     {
9956       gtk_tree_path_free (cursor_path);
9957       return;
9958     }
9959   gtk_tree_path_free (cursor_path);
9960
9961   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9962   if (tree_view->priv->focus_column)
9963     {
9964       for (; list; list = (rtl ? list->prev : list->next))
9965         {
9966           if (list->data == tree_view->priv->focus_column)
9967             break;
9968         }
9969     }
9970
9971   while (list)
9972     {
9973       gboolean left, right;
9974
9975       column = list->data;
9976       if (column->visible == FALSE)
9977         goto loop_end;
9978
9979       gtk_tree_view_column_cell_set_cell_data (column,
9980                                                tree_view->priv->model,
9981                                                &iter,
9982                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9983                                                cursor_node->children?TRUE:FALSE);
9984
9985       if (rtl)
9986         {
9987           right = list->prev ? TRUE : FALSE;
9988           left = list->next ? TRUE : FALSE;
9989         }
9990       else
9991         {
9992           left = list->prev ? TRUE : FALSE;
9993           right = list->next ? TRUE : FALSE;
9994         }
9995
9996       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9997         {
9998           tree_view->priv->focus_column = column;
9999           found_column = TRUE;
10000           break;
10001         }
10002     loop_end:
10003       if (count == 1)
10004         list = rtl ? list->prev : list->next;
10005       else
10006         list = rtl ? list->next : list->prev;
10007     }
10008
10009   if (found_column)
10010     {
10011       if (!gtk_tree_view_has_special_cell (tree_view))
10012         _gtk_tree_view_queue_draw_node (tree_view,
10013                                         cursor_tree,
10014                                         cursor_node,
10015                                         NULL);
10016       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10017       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10018     }
10019   else
10020     {
10021       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10022     }
10023
10024   gtk_tree_view_clamp_column_visible (tree_view,
10025                                       tree_view->priv->focus_column, TRUE);
10026 }
10027
10028 static void
10029 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10030                                      gint         count)
10031 {
10032   GtkRBTree *cursor_tree;
10033   GtkRBNode *cursor_node;
10034   GtkTreePath *path;
10035   GtkTreePath *old_path;
10036
10037   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10038     return;
10039
10040   g_return_if_fail (tree_view->priv->tree != NULL);
10041
10042   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10043
10044   cursor_tree = tree_view->priv->tree;
10045   cursor_node = cursor_tree->root;
10046
10047   if (count == -1)
10048     {
10049       while (cursor_node && cursor_node->left != cursor_tree->nil)
10050         cursor_node = cursor_node->left;
10051
10052       /* Now go forward to find the first focusable row. */
10053       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10054       search_first_focusable_path (tree_view, &path,
10055                                    TRUE, &cursor_tree, &cursor_node);
10056     }
10057   else
10058     {
10059       do
10060         {
10061           while (cursor_node && cursor_node->right != cursor_tree->nil)
10062             cursor_node = cursor_node->right;
10063           if (cursor_node->children == NULL)
10064             break;
10065
10066           cursor_tree = cursor_node->children;
10067           cursor_node = cursor_tree->root;
10068         }
10069       while (1);
10070
10071       /* Now go backwards to find last focusable row. */
10072       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10073       search_first_focusable_path (tree_view, &path,
10074                                    FALSE, &cursor_tree, &cursor_node);
10075     }
10076
10077   if (!path)
10078     goto cleanup;
10079
10080   if (gtk_tree_path_compare (old_path, path))
10081     {
10082       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10083       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10084     }
10085   else
10086     {
10087       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10088     }
10089
10090 cleanup:
10091   gtk_tree_path_free (old_path);
10092   gtk_tree_path_free (path);
10093 }
10094
10095 static gboolean
10096 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10097 {
10098   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10099     return FALSE;
10100
10101   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10102     return FALSE;
10103
10104   gtk_tree_selection_select_all (tree_view->priv->selection);
10105
10106   return TRUE;
10107 }
10108
10109 static gboolean
10110 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10111 {
10112   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10113     return FALSE;
10114
10115   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10116     return FALSE;
10117
10118   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10119
10120   return TRUE;
10121 }
10122
10123 static gboolean
10124 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10125                                       gboolean     start_editing)
10126 {
10127   GtkRBTree *new_tree = NULL;
10128   GtkRBNode *new_node = NULL;
10129   GtkRBTree *cursor_tree = NULL;
10130   GtkRBNode *cursor_node = NULL;
10131   GtkTreePath *cursor_path = NULL;
10132   GtkTreeSelectMode mode = 0;
10133
10134   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10135     return FALSE;
10136
10137   if (tree_view->priv->cursor)
10138     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10139
10140   if (cursor_path == NULL)
10141     return FALSE;
10142
10143   _gtk_tree_view_find_node (tree_view, cursor_path,
10144                             &cursor_tree, &cursor_node);
10145
10146   if (cursor_tree == NULL)
10147     {
10148       gtk_tree_path_free (cursor_path);
10149       return FALSE;
10150     }
10151
10152   if (!tree_view->priv->shift_pressed && start_editing &&
10153       tree_view->priv->focus_column)
10154     {
10155       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10156         {
10157           gtk_tree_path_free (cursor_path);
10158           return TRUE;
10159         }
10160     }
10161
10162   if (tree_view->priv->ctrl_pressed)
10163     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10164   if (tree_view->priv->shift_pressed)
10165     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10166
10167   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10168                                             cursor_node,
10169                                             cursor_tree,
10170                                             cursor_path,
10171                                             mode,
10172                                             FALSE);
10173
10174   /* We bail out if the original (tree, node) don't exist anymore after
10175    * handling the selection-changed callback.  We do return TRUE because
10176    * the key press has been handled at this point.
10177    */
10178   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10179
10180   if (cursor_tree != new_tree || cursor_node != new_node)
10181     return FALSE;
10182
10183   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10184
10185   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10186   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10187
10188   if (!tree_view->priv->shift_pressed)
10189     gtk_tree_view_row_activated (tree_view, cursor_path,
10190                                  tree_view->priv->focus_column);
10191     
10192   gtk_tree_path_free (cursor_path);
10193
10194   return TRUE;
10195 }
10196
10197 static gboolean
10198 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10199 {
10200   GtkRBTree *new_tree = NULL;
10201   GtkRBNode *new_node = NULL;
10202   GtkRBTree *cursor_tree = NULL;
10203   GtkRBNode *cursor_node = NULL;
10204   GtkTreePath *cursor_path = NULL;
10205
10206   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10207     return FALSE;
10208
10209   cursor_path = NULL;
10210   if (tree_view->priv->cursor)
10211     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10212
10213   if (cursor_path == NULL)
10214     return FALSE;
10215
10216   _gtk_tree_view_find_node (tree_view, cursor_path,
10217                             &cursor_tree, &cursor_node);
10218   if (cursor_tree == NULL)
10219     {
10220       gtk_tree_path_free (cursor_path);
10221       return FALSE;
10222     }
10223
10224   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10225                                             cursor_node,
10226                                             cursor_tree,
10227                                             cursor_path,
10228                                             GTK_TREE_SELECT_MODE_TOGGLE,
10229                                             FALSE);
10230
10231   /* We bail out if the original (tree, node) don't exist anymore after
10232    * handling the selection-changed callback.  We do return TRUE because
10233    * the key press has been handled at this point.
10234    */
10235   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10236
10237   if (cursor_tree != new_tree || cursor_node != new_node)
10238     return FALSE;
10239
10240   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10241
10242   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10243   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10244   gtk_tree_path_free (cursor_path);
10245
10246   return TRUE;
10247 }
10248
10249 static gboolean
10250 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10251                                                gboolean     logical,
10252                                                gboolean     expand,
10253                                                gboolean     open_all)
10254 {
10255   GtkTreePath *cursor_path = NULL;
10256   GtkRBTree *tree;
10257   GtkRBNode *node;
10258
10259   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10260     return FALSE;
10261
10262   cursor_path = NULL;
10263   if (tree_view->priv->cursor)
10264     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10265
10266   if (cursor_path == NULL)
10267     return FALSE;
10268
10269   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10270     return FALSE;
10271
10272   /* Don't handle the event if we aren't an expander */
10273   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10274     return FALSE;
10275
10276   if (!logical
10277       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10278     expand = !expand;
10279
10280   if (expand)
10281     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10282   else
10283     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10284
10285   gtk_tree_path_free (cursor_path);
10286
10287   return TRUE;
10288 }
10289
10290 static gboolean
10291 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10292 {
10293   GtkRBTree *cursor_tree = NULL;
10294   GtkRBNode *cursor_node = NULL;
10295   GtkTreePath *cursor_path = NULL;
10296   GdkModifierType state;
10297
10298   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10299     goto out;
10300
10301   cursor_path = NULL;
10302   if (tree_view->priv->cursor)
10303     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10304
10305   if (cursor_path == NULL)
10306     goto out;
10307
10308   _gtk_tree_view_find_node (tree_view, cursor_path,
10309                             &cursor_tree, &cursor_node);
10310   if (cursor_tree == NULL)
10311     {
10312       gtk_tree_path_free (cursor_path);
10313       goto out;
10314     }
10315
10316   if (cursor_tree->parent_node)
10317     {
10318       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10319       cursor_node = cursor_tree->parent_node;
10320       cursor_tree = cursor_tree->parent_tree;
10321
10322       gtk_tree_path_up (cursor_path);
10323
10324       if (gtk_get_current_event_state (&state))
10325         {
10326           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10327             tree_view->priv->ctrl_pressed = TRUE;
10328         }
10329
10330       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10331       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10332
10333       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10334       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10335       gtk_tree_path_free (cursor_path);
10336
10337       tree_view->priv->ctrl_pressed = FALSE;
10338
10339       return TRUE;
10340     }
10341
10342  out:
10343
10344   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10345   return FALSE;
10346 }
10347
10348 static gboolean
10349 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10350 {
10351   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10352   tree_view->priv->typeselect_flush_timeout = 0;
10353
10354   return FALSE;
10355 }
10356
10357 /* Cut and paste from gtkwindow.c */
10358 static void
10359 send_focus_change (GtkWidget *widget,
10360                    GdkDevice *device,
10361                    gboolean   in)
10362 {
10363   GdkDeviceManager *device_manager;
10364   GList *devices, *d;
10365
10366   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10367   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10368   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10369   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10370
10371   for (d = devices; d; d = d->next)
10372     {
10373       GdkDevice *dev = d->data;
10374       GdkEvent *fevent;
10375       GdkWindow *window;
10376
10377       if (dev->source != GDK_SOURCE_KEYBOARD)
10378         continue;
10379
10380       window = gtk_widget_get_window (widget);
10381
10382       /* Skip non-master keyboards that haven't
10383        * selected for events from this window
10384        */
10385       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10386           !gdk_window_get_device_events (window, dev))
10387         continue;
10388
10389       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10390
10391       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10392       fevent->focus_change.window = g_object_ref (window);
10393       fevent->focus_change.in = in;
10394       gdk_event_set_device (fevent, device);
10395
10396       gtk_widget_send_focus_change (widget, fevent);
10397
10398       gdk_event_free (fevent);
10399     }
10400 }
10401
10402 static void
10403 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10404 {
10405   GtkWidget *frame, *vbox, *toplevel;
10406   GdkScreen *screen;
10407
10408   if (tree_view->priv->search_custom_entry_set)
10409     return;
10410
10411   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10412   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10413
10414    if (tree_view->priv->search_window != NULL)
10415      {
10416        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10417          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10418                                       GTK_WINDOW (tree_view->priv->search_window));
10419        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10420          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10421                                          GTK_WINDOW (tree_view->priv->search_window));
10422
10423        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10424
10425        return;
10426      }
10427    
10428   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10429   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10430
10431   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10432     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10433                                  GTK_WINDOW (tree_view->priv->search_window));
10434
10435   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10436                             GDK_WINDOW_TYPE_HINT_UTILITY);
10437   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10438   g_signal_connect (tree_view->priv->search_window, "delete-event",
10439                     G_CALLBACK (gtk_tree_view_search_delete_event),
10440                     tree_view);
10441   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10442                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10443                     tree_view);
10444   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10445                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10446                     tree_view);
10447   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10448                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10449                     tree_view);
10450
10451   frame = gtk_frame_new (NULL);
10452   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10453   gtk_widget_show (frame);
10454   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10455
10456   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10457   gtk_widget_show (vbox);
10458   gtk_container_add (GTK_CONTAINER (frame), vbox);
10459   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10460
10461   /* add entry */
10462   tree_view->priv->search_entry = gtk_entry_new ();
10463   gtk_widget_show (tree_view->priv->search_entry);
10464   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10465                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10466                     tree_view);
10467   g_signal_connect (tree_view->priv->search_entry,
10468                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10469                     tree_view);
10470   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10471                     "preedit-changed",
10472                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10473                     tree_view);
10474   gtk_container_add (GTK_CONTAINER (vbox),
10475                      tree_view->priv->search_entry);
10476
10477   gtk_widget_realize (tree_view->priv->search_entry);
10478 }
10479
10480 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10481  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10482  */
10483 static gboolean
10484 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10485                                              GdkDevice   *device,
10486                                              gboolean     keybinding)
10487 {
10488   /* We only start interactive search if we have focus or the columns
10489    * have focus.  If one of our children have focus, we don't want to
10490    * start the search.
10491    */
10492   GList *list;
10493   gboolean found_focus = FALSE;
10494   GtkWidgetClass *entry_parent_class;
10495   
10496   if (!tree_view->priv->enable_search && !keybinding)
10497     return FALSE;
10498
10499   if (tree_view->priv->search_custom_entry_set)
10500     return FALSE;
10501
10502   if (tree_view->priv->search_window != NULL &&
10503       gtk_widget_get_visible (tree_view->priv->search_window))
10504     return TRUE;
10505
10506   for (list = tree_view->priv->columns; list; list = list->next)
10507     {
10508       GtkTreeViewColumn *column;
10509
10510       column = list->data;
10511       if (! column->visible)
10512         continue;
10513
10514       if (gtk_widget_has_focus (column->button))
10515         {
10516           found_focus = TRUE;
10517           break;
10518         }
10519     }
10520   
10521   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10522     found_focus = TRUE;
10523
10524   if (!found_focus)
10525     return FALSE;
10526
10527   if (tree_view->priv->search_column < 0)
10528     return FALSE;
10529
10530   gtk_tree_view_ensure_interactive_directory (tree_view);
10531
10532   if (keybinding)
10533     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10534
10535   /* done, show it */
10536   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10537   gtk_widget_show (tree_view->priv->search_window);
10538   if (tree_view->priv->search_entry_changed_id == 0)
10539     {
10540       tree_view->priv->search_entry_changed_id =
10541         g_signal_connect (tree_view->priv->search_entry, "changed",
10542                           G_CALLBACK (gtk_tree_view_search_init),
10543                           tree_view);
10544     }
10545
10546   tree_view->priv->typeselect_flush_timeout =
10547     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10548                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10549                    tree_view);
10550
10551   /* Grab focus will select all the text.  We don't want that to happen, so we
10552    * call the parent instance and bypass the selection change.  This is probably
10553    * really non-kosher. */
10554   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10555   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10556
10557   /* send focus-in event */
10558   send_focus_change (tree_view->priv->search_entry, device, TRUE);
10559
10560   /* search first matching iter */
10561   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10562
10563   return TRUE;
10564 }
10565
10566 static gboolean
10567 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10568 {
10569   return gtk_tree_view_real_start_interactive_search (tree_view,
10570                                                       gtk_get_current_event_device (),
10571                                                       TRUE);
10572 }
10573
10574 /* this function returns the new width of the column being resized given
10575  * the column and x position of the cursor; the x cursor position is passed
10576  * in as a pointer and automagicly corrected if it's beyond min/max limits
10577  */
10578 static gint
10579 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10580                                 gint       i,
10581                                 gint      *x)
10582 {
10583   GtkAllocation allocation;
10584   GtkTreeViewColumn *column;
10585   GtkRequisition button_req;
10586   gint width;
10587   gboolean rtl;
10588
10589   /* first translate the x position from widget->window
10590    * to clist->clist_window
10591    */
10592   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10593   column = g_list_nth (tree_view->priv->columns, i)->data;
10594   gtk_widget_get_allocation (column->button, &allocation);
10595   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
10596
10597   /* Clamp down the value */
10598   if (column->min_width == -1)
10599     {
10600       gtk_widget_get_preferred_size (column->button, &button_req, NULL);
10601       width = MAX (button_req.width, width);
10602     }
10603   else
10604     width = MAX (column->min_width,
10605                  width);
10606   if (column->max_width != -1)
10607     width = MIN (width, column->max_width);
10608
10609   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
10610
10611   return width;
10612 }
10613
10614
10615 /* FIXME this adjust_allocation is a big cut-and-paste from
10616  * GtkCList, needs to be some "official" way to do this
10617  * factored out.
10618  */
10619 typedef struct
10620 {
10621   GdkWindow *window;
10622   int dx;
10623   int dy;
10624 } ScrollData;
10625
10626 /* The window to which widget->window is relative */
10627 #define ALLOCATION_WINDOW(widget)               \
10628    (!gtk_widget_get_has_window (widget) ?                   \
10629     gtk_widget_get_window (widget) :                        \
10630     gdk_window_get_parent (gtk_widget_get_window (widget)))
10631
10632 static void
10633 adjust_allocation_recurse (GtkWidget *widget,
10634                            gpointer   data)
10635 {
10636   GtkAllocation allocation;
10637   ScrollData *scroll_data = data;
10638
10639   /* Need to really size allocate instead of just poking
10640    * into widget->allocation if the widget is not realized.
10641    * FIXME someone figure out why this was.
10642    */
10643   gtk_widget_get_allocation (widget, &allocation);
10644   if (!gtk_widget_get_realized (widget))
10645     {
10646       if (gtk_widget_get_visible (widget))
10647         {
10648           GdkRectangle tmp_rectangle = allocation;
10649           tmp_rectangle.x += scroll_data->dx;
10650           tmp_rectangle.y += scroll_data->dy;
10651           
10652           gtk_widget_size_allocate (widget, &tmp_rectangle);
10653         }
10654     }
10655   else
10656     {
10657       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10658         {
10659           allocation.x += scroll_data->dx;
10660           allocation.y += scroll_data->dy;
10661           gtk_widget_set_allocation (widget, &allocation);
10662
10663           if (GTK_IS_CONTAINER (widget))
10664             gtk_container_forall (GTK_CONTAINER (widget),
10665                                   adjust_allocation_recurse,
10666                                   data);
10667         }
10668     }
10669 }
10670
10671 static void
10672 adjust_allocation (GtkWidget *widget,
10673                    int        dx,
10674                    int        dy)
10675 {
10676   ScrollData scroll_data;
10677
10678   if (gtk_widget_get_realized (widget))
10679     scroll_data.window = ALLOCATION_WINDOW (widget);
10680   else
10681     scroll_data.window = NULL;
10682     
10683   scroll_data.dx = dx;
10684   scroll_data.dy = dy;
10685   
10686   adjust_allocation_recurse (widget, &scroll_data);
10687 }
10688
10689 /* Callbacks */
10690 static void
10691 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10692                                   GtkTreeView   *tree_view)
10693 {
10694   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10695     {
10696       gint dy;
10697         
10698       gdk_window_move (tree_view->priv->bin_window,
10699                        - tree_view->priv->hadjustment->value,
10700                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10701       gdk_window_move (tree_view->priv->header_window,
10702                        - tree_view->priv->hadjustment->value,
10703                        0);
10704       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10705       if (dy)
10706         {
10707           update_prelight (tree_view,
10708                            tree_view->priv->event_last_x,
10709                            tree_view->priv->event_last_y - dy);
10710
10711           if (tree_view->priv->edited_column &&
10712               GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10713             {
10714               GList *list;
10715               GtkWidget *widget;
10716               GtkTreeViewChild *child = NULL;
10717
10718               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10719               adjust_allocation (widget, 0, dy); 
10720               
10721               for (list = tree_view->priv->children; list; list = list->next)
10722                 {
10723                   child = (GtkTreeViewChild *)list->data;
10724                   if (child->widget == widget)
10725                     {
10726                       child->y += dy;
10727                       break;
10728                     }
10729                 }
10730             }
10731         }
10732       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10733
10734       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10735         {
10736           /* update our dy and top_row */
10737           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10738
10739           if (!tree_view->priv->in_top_row_to_dy)
10740             gtk_tree_view_dy_to_top_row (tree_view);
10741         }
10742
10743       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10744       gtk_tree_view_bin_process_updates (tree_view);
10745     }
10746 }
10747
10748 \f
10749
10750 /* Public methods
10751  */
10752
10753 /**
10754  * gtk_tree_view_new:
10755  *
10756  * Creates a new #GtkTreeView widget.
10757  *
10758  * Return value: A newly created #GtkTreeView widget.
10759  **/
10760 GtkWidget *
10761 gtk_tree_view_new (void)
10762 {
10763   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10764 }
10765
10766 /**
10767  * gtk_tree_view_new_with_model:
10768  * @model: the model.
10769  *
10770  * Creates a new #GtkTreeView widget with the model initialized to @model.
10771  *
10772  * Return value: A newly created #GtkTreeView widget.
10773  **/
10774 GtkWidget *
10775 gtk_tree_view_new_with_model (GtkTreeModel *model)
10776 {
10777   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10778 }
10779
10780 /* Public Accessors
10781  */
10782
10783 /**
10784  * gtk_tree_view_get_model:
10785  * @tree_view: a #GtkTreeView
10786  *
10787  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10788  * model is unset.
10789  *
10790  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
10791  **/
10792 GtkTreeModel *
10793 gtk_tree_view_get_model (GtkTreeView *tree_view)
10794 {
10795   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10796
10797   return tree_view->priv->model;
10798 }
10799
10800 /**
10801  * gtk_tree_view_set_model:
10802  * @tree_view: A #GtkTreeNode.
10803  * @model: (allow-none): The model.
10804  *
10805  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10806  * set, it will remove it before setting the new model.  If @model is %NULL,
10807  * then it will unset the old model.
10808  **/
10809 void
10810 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10811                          GtkTreeModel *model)
10812 {
10813   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10814   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10815
10816   if (model == tree_view->priv->model)
10817     return;
10818
10819   if (tree_view->priv->scroll_to_path)
10820     {
10821       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10822       tree_view->priv->scroll_to_path = NULL;
10823     }
10824
10825   if (tree_view->priv->model)
10826     {
10827       GList *tmplist = tree_view->priv->columns;
10828
10829       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10830       gtk_tree_view_stop_editing (tree_view, TRUE);
10831
10832       remove_expand_collapse_timeout (tree_view);
10833
10834       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10835                                             gtk_tree_view_row_changed,
10836                                             tree_view);
10837       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10838                                             gtk_tree_view_row_inserted,
10839                                             tree_view);
10840       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10841                                             gtk_tree_view_row_has_child_toggled,
10842                                             tree_view);
10843       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10844                                             gtk_tree_view_row_deleted,
10845                                             tree_view);
10846       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10847                                             gtk_tree_view_rows_reordered,
10848                                             tree_view);
10849
10850       for (; tmplist; tmplist = tmplist->next)
10851         _gtk_tree_view_column_unset_model (tmplist->data,
10852                                            tree_view->priv->model);
10853
10854       if (tree_view->priv->tree)
10855         gtk_tree_view_free_rbtree (tree_view);
10856
10857       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10858       tree_view->priv->drag_dest_row = NULL;
10859       gtk_tree_row_reference_free (tree_view->priv->cursor);
10860       tree_view->priv->cursor = NULL;
10861       gtk_tree_row_reference_free (tree_view->priv->anchor);
10862       tree_view->priv->anchor = NULL;
10863       gtk_tree_row_reference_free (tree_view->priv->top_row);
10864       tree_view->priv->top_row = NULL;
10865       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10866       tree_view->priv->scroll_to_path = NULL;
10867
10868       tree_view->priv->scroll_to_column = NULL;
10869
10870       g_object_unref (tree_view->priv->model);
10871
10872       tree_view->priv->search_column = -1;
10873       tree_view->priv->fixed_height_check = 0;
10874       tree_view->priv->fixed_height = -1;
10875       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10876       tree_view->priv->last_button_x = -1;
10877       tree_view->priv->last_button_y = -1;
10878     }
10879
10880   tree_view->priv->model = model;
10881
10882   if (tree_view->priv->model)
10883     {
10884       gint i;
10885       GtkTreePath *path;
10886       GtkTreeIter iter;
10887       GtkTreeModelFlags flags;
10888
10889       if (tree_view->priv->search_column == -1)
10890         {
10891           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10892             {
10893               GType type = gtk_tree_model_get_column_type (model, i);
10894
10895               if (g_value_type_transformable (type, G_TYPE_STRING))
10896                 {
10897                   tree_view->priv->search_column = i;
10898                   break;
10899                 }
10900             }
10901         }
10902
10903       g_object_ref (tree_view->priv->model);
10904       g_signal_connect (tree_view->priv->model,
10905                         "row-changed",
10906                         G_CALLBACK (gtk_tree_view_row_changed),
10907                         tree_view);
10908       g_signal_connect (tree_view->priv->model,
10909                         "row-inserted",
10910                         G_CALLBACK (gtk_tree_view_row_inserted),
10911                         tree_view);
10912       g_signal_connect (tree_view->priv->model,
10913                         "row-has-child-toggled",
10914                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10915                         tree_view);
10916       g_signal_connect (tree_view->priv->model,
10917                         "row-deleted",
10918                         G_CALLBACK (gtk_tree_view_row_deleted),
10919                         tree_view);
10920       g_signal_connect (tree_view->priv->model,
10921                         "rows-reordered",
10922                         G_CALLBACK (gtk_tree_view_rows_reordered),
10923                         tree_view);
10924
10925       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10926       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10927         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10928       else
10929         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10930
10931       path = gtk_tree_path_new_first ();
10932       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10933         {
10934           tree_view->priv->tree = _gtk_rbtree_new ();
10935           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10936         }
10937       gtk_tree_path_free (path);
10938
10939       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10940       install_presize_handler (tree_view);
10941     }
10942
10943   g_object_notify (G_OBJECT (tree_view), "model");
10944
10945   if (tree_view->priv->selection)
10946   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10947
10948   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10949     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10950 }
10951
10952 /**
10953  * gtk_tree_view_get_selection:
10954  * @tree_view: A #GtkTreeView.
10955  *
10956  * Gets the #GtkTreeSelection associated with @tree_view.
10957  *
10958  * Return value: (transfer none): A #GtkTreeSelection object.
10959  **/
10960 GtkTreeSelection *
10961 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10962 {
10963   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10964
10965   return tree_view->priv->selection;
10966 }
10967
10968 /**
10969  * gtk_tree_view_get_hadjustment:
10970  * @tree_view: A #GtkTreeView
10971  *
10972  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10973  *
10974  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
10975  *     if none is currently being used.
10976  *
10977  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
10978  **/
10979 GtkAdjustment *
10980 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10981 {
10982   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10983
10984   return tree_view->priv->hadjustment;
10985 }
10986
10987 /**
10988  * gtk_tree_view_set_hadjustment:
10989  * @tree_view: A #GtkTreeView
10990  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10991  *
10992  * Sets the #GtkAdjustment for the current horizontal aspect.
10993  *
10994  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
10995  **/
10996 void
10997 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10998                                GtkAdjustment *adjustment)
10999 {
11000   GtkTreeViewPrivate *priv = tree_view->priv;
11001
11002   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11003   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11004
11005   if (adjustment && priv->hadjustment == adjustment)
11006     return;
11007
11008   if (priv->hadjustment != NULL)
11009     {
11010       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11011                                             gtk_tree_view_adjustment_changed,
11012                                             tree_view);
11013       g_object_unref (priv->hadjustment);
11014     }
11015
11016   if (adjustment == NULL)
11017     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11018                                      0.0, 0.0, 0.0);
11019
11020   g_signal_connect (adjustment, "value-changed",
11021                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11022   priv->hadjustment = g_object_ref_sink (adjustment);
11023   /* FIXME: Adjustment should probably be populated here with fresh values, but
11024    * internal details are too complicated for me to decipher right now.
11025    */
11026   gtk_tree_view_adjustment_changed (NULL, tree_view);
11027
11028   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11029 }
11030
11031 /**
11032  * gtk_tree_view_get_vadjustment:
11033  * @tree_view: A #GtkTreeView
11034  *
11035  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11036  *
11037  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11038  *     if none is currently being used.
11039  *
11040  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11041  **/
11042 GtkAdjustment *
11043 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11044 {
11045   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11046
11047   return tree_view->priv->vadjustment;
11048 }
11049
11050 /**
11051  * gtk_tree_view_set_vadjustment:
11052  * @tree_view: A #GtkTreeView
11053  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11054  *
11055  * Sets the #GtkAdjustment for the current vertical aspect.
11056  *
11057  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11058  **/
11059 void
11060 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11061                                GtkAdjustment *adjustment)
11062 {
11063   GtkTreeViewPrivate *priv = tree_view->priv;
11064
11065   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11066   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11067
11068   if (adjustment && priv->vadjustment == adjustment)
11069     return;
11070
11071   if (priv->vadjustment != NULL)
11072     {
11073       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11074                                             gtk_tree_view_adjustment_changed,
11075                                             tree_view);
11076       g_object_unref (priv->vadjustment);
11077     }
11078
11079   if (adjustment == NULL)
11080     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11081                                      0.0, 0.0, 0.0);
11082
11083   g_signal_connect (adjustment, "value-changed",
11084                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11085   priv->vadjustment = g_object_ref_sink (adjustment);
11086   /* FIXME: Adjustment should probably be populated here with fresh values, but
11087    * internal details are too complicated for me to decipher right now.
11088    */
11089   gtk_tree_view_adjustment_changed (NULL, tree_view);
11090   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11091 }
11092
11093 /* Column and header operations */
11094
11095 /**
11096  * gtk_tree_view_get_headers_visible:
11097  * @tree_view: A #GtkTreeView.
11098  *
11099  * Returns %TRUE if the headers on the @tree_view are visible.
11100  *
11101  * Return value: Whether the headers are visible or not.
11102  **/
11103 gboolean
11104 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11105 {
11106   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11107
11108   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11109 }
11110
11111 /**
11112  * gtk_tree_view_set_headers_visible:
11113  * @tree_view: A #GtkTreeView.
11114  * @headers_visible: %TRUE if the headers are visible
11115  *
11116  * Sets the visibility state of the headers.
11117  **/
11118 void
11119 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11120                                    gboolean     headers_visible)
11121 {
11122   gint x, y;
11123   GList *list;
11124   GtkTreeViewColumn *column;
11125   GtkAllocation allocation;
11126
11127   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11128
11129   headers_visible = !! headers_visible;
11130
11131   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
11132     return;
11133
11134   if (headers_visible)
11135     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11136   else
11137     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11138
11139   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11140     {
11141       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11142       if (headers_visible)
11143         {
11144           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11145           gdk_window_move_resize (tree_view->priv->bin_window,
11146                                   x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view),
11147                                   tree_view->priv->width, allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
11148
11149           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11150             gtk_tree_view_map_buttons (tree_view);
11151         }
11152       else
11153         {
11154           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11155
11156           for (list = tree_view->priv->columns; list; list = list->next)
11157             {
11158               column = list->data;
11159               gtk_widget_unmap (column->button);
11160             }
11161           gdk_window_hide (tree_view->priv->header_window);
11162         }
11163     }
11164
11165   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11166   tree_view->priv->vadjustment->page_size = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11167   tree_view->priv->vadjustment->page_increment = (allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11168   tree_view->priv->vadjustment->lower = 0;
11169   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11170   gtk_adjustment_changed (tree_view->priv->vadjustment);
11171
11172   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11173
11174   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11175 }
11176
11177 /**
11178  * gtk_tree_view_columns_autosize:
11179  * @tree_view: A #GtkTreeView.
11180  *
11181  * Resizes all columns to their optimal width. Only works after the
11182  * treeview has been realized.
11183  **/
11184 void
11185 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11186 {
11187   gboolean dirty = FALSE;
11188   GList *list;
11189   GtkTreeViewColumn *column;
11190
11191   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11192
11193   for (list = tree_view->priv->columns; list; list = list->next)
11194     {
11195       column = list->data;
11196       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11197         continue;
11198       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11199       dirty = TRUE;
11200     }
11201
11202   if (dirty)
11203     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11204 }
11205
11206 /**
11207  * gtk_tree_view_set_headers_clickable:
11208  * @tree_view: A #GtkTreeView.
11209  * @setting: %TRUE if the columns are clickable.
11210  *
11211  * Allow the column title buttons to be clicked.
11212  **/
11213 void
11214 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11215                                      gboolean   setting)
11216 {
11217   GList *list;
11218
11219   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11220
11221   for (list = tree_view->priv->columns; list; list = list->next)
11222     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11223
11224   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11225 }
11226
11227
11228 /**
11229  * gtk_tree_view_get_headers_clickable:
11230  * @tree_view: A #GtkTreeView.
11231  *
11232  * Returns whether all header columns are clickable.
11233  *
11234  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11235  *
11236  * Since: 2.10
11237  **/
11238 gboolean 
11239 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11240 {
11241   GList *list;
11242   
11243   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11244
11245   for (list = tree_view->priv->columns; list; list = list->next)
11246     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11247       return FALSE;
11248
11249   return TRUE;
11250 }
11251
11252 /**
11253  * gtk_tree_view_set_rules_hint
11254  * @tree_view: a #GtkTreeView
11255  * @setting: %TRUE if the tree requires reading across rows
11256  *
11257  * This function tells GTK+ that the user interface for your
11258  * application requires users to read across tree rows and associate
11259  * cells with one another. By default, GTK+ will then render the tree
11260  * with alternating row colors. Do <emphasis>not</emphasis> use it
11261  * just because you prefer the appearance of the ruled tree; that's a
11262  * question for the theme. Some themes will draw tree rows in
11263  * alternating colors even when rules are turned off, and users who
11264  * prefer that appearance all the time can choose those themes. You
11265  * should call this function only as a <emphasis>semantic</emphasis>
11266  * hint to the theme engine that your tree makes alternating colors
11267  * useful from a functional standpoint (since it has lots of columns,
11268  * generally).
11269  *
11270  **/
11271 void
11272 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11273                               gboolean      setting)
11274 {
11275   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11276
11277   setting = setting != FALSE;
11278
11279   if (tree_view->priv->has_rules != setting)
11280     {
11281       tree_view->priv->has_rules = setting;
11282       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11283     }
11284
11285   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11286 }
11287
11288 /**
11289  * gtk_tree_view_get_rules_hint
11290  * @tree_view: a #GtkTreeView
11291  *
11292  * Gets the setting set by gtk_tree_view_set_rules_hint().
11293  *
11294  * Return value: %TRUE if rules are useful for the user of this tree
11295  **/
11296 gboolean
11297 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11298 {
11299   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11300
11301   return tree_view->priv->has_rules;
11302 }
11303
11304 /* Public Column functions
11305  */
11306
11307 /**
11308  * gtk_tree_view_append_column:
11309  * @tree_view: A #GtkTreeView.
11310  * @column: The #GtkTreeViewColumn to add.
11311  *
11312  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11313  * mode enabled, then @column must have its "sizing" property set to be
11314  * GTK_TREE_VIEW_COLUMN_FIXED.
11315  *
11316  * Return value: The number of columns in @tree_view after appending.
11317  **/
11318 gint
11319 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11320                              GtkTreeViewColumn *column)
11321 {
11322   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11323   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11324   g_return_val_if_fail (column->tree_view == NULL, -1);
11325
11326   return gtk_tree_view_insert_column (tree_view, column, -1);
11327 }
11328
11329
11330 /**
11331  * gtk_tree_view_remove_column:
11332  * @tree_view: A #GtkTreeView.
11333  * @column: The #GtkTreeViewColumn to remove.
11334  *
11335  * Removes @column from @tree_view.
11336  *
11337  * Return value: The number of columns in @tree_view after removing.
11338  **/
11339 gint
11340 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11341                              GtkTreeViewColumn *column)
11342 {
11343   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11344   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11345   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11346
11347   if (tree_view->priv->focus_column == column)
11348     tree_view->priv->focus_column = NULL;
11349
11350   if (tree_view->priv->edited_column == column)
11351     {
11352       gtk_tree_view_stop_editing (tree_view, TRUE);
11353
11354       /* no need to, but just to be sure ... */
11355       tree_view->priv->edited_column = NULL;
11356     }
11357
11358   if (tree_view->priv->expander_column == column)
11359     tree_view->priv->expander_column = NULL;
11360
11361   g_signal_handlers_disconnect_by_func (column,
11362                                         G_CALLBACK (column_sizing_notify),
11363                                         tree_view);
11364
11365   _gtk_tree_view_column_unset_tree_view (column);
11366
11367   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11368   tree_view->priv->n_columns--;
11369
11370   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11371     {
11372       GList *list;
11373
11374       _gtk_tree_view_column_unrealize_button (column);
11375       for (list = tree_view->priv->columns; list; list = list->next)
11376         {
11377           GtkTreeViewColumn *tmp_column;
11378
11379           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11380           if (tmp_column->visible)
11381             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11382         }
11383
11384       if (tree_view->priv->n_columns == 0 &&
11385           gtk_tree_view_get_headers_visible (tree_view))
11386         gdk_window_hide (tree_view->priv->header_window);
11387
11388       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11389     }
11390
11391   g_object_unref (column);
11392   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11393
11394   return tree_view->priv->n_columns;
11395 }
11396
11397 /**
11398  * gtk_tree_view_insert_column:
11399  * @tree_view: A #GtkTreeView.
11400  * @column: The #GtkTreeViewColumn to be inserted.
11401  * @position: The position to insert @column in.
11402  *
11403  * This inserts the @column into the @tree_view at @position.  If @position is
11404  * -1, then the column is inserted at the end. If @tree_view has
11405  * "fixed_height" mode enabled, then @column must have its "sizing" property
11406  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11407  *
11408  * Return value: The number of columns in @tree_view after insertion.
11409  **/
11410 gint
11411 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11412                              GtkTreeViewColumn *column,
11413                              gint               position)
11414 {
11415   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11416   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11417   g_return_val_if_fail (column->tree_view == NULL, -1);
11418
11419   if (tree_view->priv->fixed_height_mode)
11420     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11421                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11422
11423   g_object_ref_sink (column);
11424
11425   if (tree_view->priv->n_columns == 0 &&
11426       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11427       gtk_tree_view_get_headers_visible (tree_view))
11428     {
11429       gdk_window_show (tree_view->priv->header_window);
11430     }
11431
11432   g_signal_connect (column, "notify::sizing",
11433                     G_CALLBACK (column_sizing_notify), tree_view);
11434
11435   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11436                                             column, position);
11437   tree_view->priv->n_columns++;
11438
11439   _gtk_tree_view_column_set_tree_view (column, tree_view);
11440
11441   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11442     {
11443       GList *list;
11444
11445       _gtk_tree_view_column_realize_button (column);
11446
11447       for (list = tree_view->priv->columns; list; list = list->next)
11448         {
11449           column = GTK_TREE_VIEW_COLUMN (list->data);
11450           if (column->visible)
11451             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11452         }
11453       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11454     }
11455
11456   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11457
11458   return tree_view->priv->n_columns;
11459 }
11460
11461 /**
11462  * gtk_tree_view_insert_column_with_attributes:
11463  * @tree_view: A #GtkTreeView
11464  * @position: The position to insert the new column in.
11465  * @title: The title to set the header to.
11466  * @cell: The #GtkCellRenderer.
11467  * @Varargs: A %NULL-terminated list of attributes.
11468  *
11469  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11470  * @position.  If @position is -1, then the newly created column is inserted at
11471  * the end.  The column is initialized with the attributes given. If @tree_view
11472  * has "fixed_height" mode enabled, then the new column will have its sizing
11473  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11474  *
11475  * Return value: The number of columns in @tree_view after insertion.
11476  **/
11477 gint
11478 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11479                                              gint             position,
11480                                              const gchar     *title,
11481                                              GtkCellRenderer *cell,
11482                                              ...)
11483 {
11484   GtkTreeViewColumn *column;
11485   gchar *attribute;
11486   va_list args;
11487   gint column_id;
11488
11489   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11490
11491   column = gtk_tree_view_column_new ();
11492   if (tree_view->priv->fixed_height_mode)
11493     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11494
11495   gtk_tree_view_column_set_title (column, title);
11496   gtk_tree_view_column_pack_start (column, cell, TRUE);
11497
11498   va_start (args, cell);
11499
11500   attribute = va_arg (args, gchar *);
11501
11502   while (attribute != NULL)
11503     {
11504       column_id = va_arg (args, gint);
11505       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11506       attribute = va_arg (args, gchar *);
11507     }
11508
11509   va_end (args);
11510
11511   gtk_tree_view_insert_column (tree_view, column, position);
11512
11513   return tree_view->priv->n_columns;
11514 }
11515
11516 /**
11517  * gtk_tree_view_insert_column_with_data_func:
11518  * @tree_view: a #GtkTreeView
11519  * @position: Position to insert, -1 for append
11520  * @title: column title
11521  * @cell: cell renderer for column
11522  * @func: function to set attributes of cell renderer
11523  * @data: data for @func
11524  * @dnotify: destroy notifier for @data
11525  *
11526  * Convenience function that inserts a new column into the #GtkTreeView
11527  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11528  * attributes (normally using data from the model). See also
11529  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11530  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11531  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11532  *
11533  * Return value: number of columns in the tree view post-insert
11534  **/
11535 gint
11536 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11537                                              gint                       position,
11538                                              const gchar               *title,
11539                                              GtkCellRenderer           *cell,
11540                                              GtkTreeCellDataFunc        func,
11541                                              gpointer                   data,
11542                                              GDestroyNotify             dnotify)
11543 {
11544   GtkTreeViewColumn *column;
11545
11546   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11547
11548   column = gtk_tree_view_column_new ();
11549   if (tree_view->priv->fixed_height_mode)
11550     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11551
11552   gtk_tree_view_column_set_title (column, title);
11553   gtk_tree_view_column_pack_start (column, cell, TRUE);
11554   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11555
11556   gtk_tree_view_insert_column (tree_view, column, position);
11557
11558   return tree_view->priv->n_columns;
11559 }
11560
11561 /**
11562  * gtk_tree_view_get_column:
11563  * @tree_view: A #GtkTreeView.
11564  * @n: The position of the column, counting from 0.
11565  *
11566  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11567  *
11568  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
11569  *     position is outside the range of columns.
11570  **/
11571 GtkTreeViewColumn *
11572 gtk_tree_view_get_column (GtkTreeView *tree_view,
11573                           gint         n)
11574 {
11575   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11576
11577   if (n < 0 || n >= tree_view->priv->n_columns)
11578     return NULL;
11579
11580   if (tree_view->priv->columns == NULL)
11581     return NULL;
11582
11583   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11584 }
11585
11586 /**
11587  * gtk_tree_view_get_columns:
11588  * @tree_view: A #GtkTreeView
11589  *
11590  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11591  * The returned list must be freed with g_list_free ().
11592  *
11593  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11594  **/
11595 GList *
11596 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11597 {
11598   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11599
11600   return g_list_copy (tree_view->priv->columns);
11601 }
11602
11603 /**
11604  * gtk_tree_view_move_column_after:
11605  * @tree_view: A #GtkTreeView
11606  * @column: The #GtkTreeViewColumn to be moved.
11607  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11608  *
11609  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11610  * @column is placed in the first position.
11611  **/
11612 void
11613 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11614                                  GtkTreeViewColumn *column,
11615                                  GtkTreeViewColumn *base_column)
11616 {
11617   GList *column_list_el, *base_el = NULL;
11618
11619   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11620
11621   column_list_el = g_list_find (tree_view->priv->columns, column);
11622   g_return_if_fail (column_list_el != NULL);
11623
11624   if (base_column)
11625     {
11626       base_el = g_list_find (tree_view->priv->columns, base_column);
11627       g_return_if_fail (base_el != NULL);
11628     }
11629
11630   if (column_list_el->prev == base_el)
11631     return;
11632
11633   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11634   if (base_el == NULL)
11635     {
11636       column_list_el->prev = NULL;
11637       column_list_el->next = tree_view->priv->columns;
11638       if (column_list_el->next)
11639         column_list_el->next->prev = column_list_el;
11640       tree_view->priv->columns = column_list_el;
11641     }
11642   else
11643     {
11644       column_list_el->prev = base_el;
11645       column_list_el->next = base_el->next;
11646       if (column_list_el->next)
11647         column_list_el->next->prev = column_list_el;
11648       base_el->next = column_list_el;
11649     }
11650
11651   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11652     {
11653       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11654       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11655     }
11656
11657   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11658 }
11659
11660 /**
11661  * gtk_tree_view_set_expander_column:
11662  * @tree_view: A #GtkTreeView
11663  * @column: %NULL, or the column to draw the expander arrow at.
11664  *
11665  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11666  * If @column is %NULL, then the expander arrow is always at the first 
11667  * visible column.
11668  *
11669  * If you do not want expander arrow to appear in your tree, set the 
11670  * expander column to a hidden column.
11671  **/
11672 void
11673 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11674                                    GtkTreeViewColumn *column)
11675 {
11676   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11677   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11678
11679   if (tree_view->priv->expander_column != column)
11680     {
11681       GList *list;
11682
11683       if (column)
11684         {
11685           /* Confirm that column is in tree_view */
11686           for (list = tree_view->priv->columns; list; list = list->next)
11687             if (list->data == column)
11688               break;
11689           g_return_if_fail (list != NULL);
11690         }
11691
11692       tree_view->priv->expander_column = column;
11693       g_object_notify (G_OBJECT (tree_view), "expander-column");
11694     }
11695 }
11696
11697 /**
11698  * gtk_tree_view_get_expander_column:
11699  * @tree_view: A #GtkTreeView
11700  *
11701  * Returns the column that is the current expander column.
11702  * This column has the expander arrow drawn next to it.
11703  *
11704  * Return value: (transfer none): The expander column.
11705  **/
11706 GtkTreeViewColumn *
11707 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11708 {
11709   GList *list;
11710
11711   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11712
11713   for (list = tree_view->priv->columns; list; list = list->next)
11714     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11715       return (GtkTreeViewColumn *) list->data;
11716   return NULL;
11717 }
11718
11719
11720 /**
11721  * gtk_tree_view_set_column_drag_function:
11722  * @tree_view: A #GtkTreeView.
11723  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
11724  * @user_data: (allow-none): User data to be passed to @func, or %NULL
11725  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
11726  *
11727  * Sets a user function for determining where a column may be dropped when
11728  * dragged.  This function is called on every column pair in turn at the
11729  * beginning of a column drag to determine where a drop can take place.  The
11730  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11731  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11732  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11733  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11734  * @tree_view reverts to the default behavior of allowing all columns to be
11735  * dropped everywhere.
11736  **/
11737 void
11738 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11739                                         GtkTreeViewColumnDropFunc  func,
11740                                         gpointer                   user_data,
11741                                         GDestroyNotify             destroy)
11742 {
11743   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11744
11745   if (tree_view->priv->column_drop_func_data_destroy)
11746     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11747
11748   tree_view->priv->column_drop_func = func;
11749   tree_view->priv->column_drop_func_data = user_data;
11750   tree_view->priv->column_drop_func_data_destroy = destroy;
11751 }
11752
11753 /**
11754  * gtk_tree_view_scroll_to_point:
11755  * @tree_view: a #GtkTreeView
11756  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11757  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11758  *
11759  * Scrolls the tree view such that the top-left corner of the visible
11760  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11761  * in tree coordinates.  The @tree_view must be realized before
11762  * this function is called.  If it isn't, you probably want to be
11763  * using gtk_tree_view_scroll_to_cell().
11764  *
11765  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11766  **/
11767 void
11768 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11769                                gint         tree_x,
11770                                gint         tree_y)
11771 {
11772   GtkAdjustment *hadj;
11773   GtkAdjustment *vadj;
11774
11775   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11776   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
11777
11778   hadj = tree_view->priv->hadjustment;
11779   vadj = tree_view->priv->vadjustment;
11780
11781   if (tree_x != -1)
11782     gtk_adjustment_set_value (hadj, tree_x);
11783   if (tree_y != -1)
11784     gtk_adjustment_set_value (vadj, tree_y);
11785 }
11786
11787 /**
11788  * gtk_tree_view_scroll_to_cell:
11789  * @tree_view: A #GtkTreeView.
11790  * @path: (allow-none): The path of the row to move to, or %NULL.
11791  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11792  * @use_align: whether to use alignment arguments, or %FALSE.
11793  * @row_align: The vertical alignment of the row specified by @path.
11794  * @col_align: The horizontal alignment of the column specified by @column.
11795  *
11796  * Moves the alignments of @tree_view to the position specified by @column and
11797  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11798  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11799  * or @path need to be non-%NULL.  @row_align determines where the row is
11800  * placed, and @col_align determines where @column is placed.  Both are expected
11801  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11802  * right/bottom alignment, 0.5 means center.
11803  *
11804  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11805  * tree does the minimum amount of work to scroll the cell onto the screen.
11806  * This means that the cell will be scrolled to the edge closest to its current
11807  * position.  If the cell is currently visible on the screen, nothing is done.
11808  *
11809  * This function only works if the model is set, and @path is a valid row on the
11810  * model.  If the model changes before the @tree_view is realized, the centered
11811  * path will be modified to reflect this change.
11812  **/
11813 void
11814 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11815                               GtkTreePath       *path,
11816                               GtkTreeViewColumn *column,
11817                               gboolean           use_align,
11818                               gfloat             row_align,
11819                               gfloat             col_align)
11820 {
11821   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11822   g_return_if_fail (tree_view->priv->model != NULL);
11823   g_return_if_fail (tree_view->priv->tree != NULL);
11824   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11825   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11826   g_return_if_fail (path != NULL || column != NULL);
11827
11828 #if 0
11829   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11830            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11831 #endif
11832   row_align = CLAMP (row_align, 0.0, 1.0);
11833   col_align = CLAMP (col_align, 0.0, 1.0);
11834
11835
11836   /* Note: Despite the benefits that come from having one code path for the
11837    * scrolling code, we short-circuit validate_visible_area's immplementation as
11838    * it is much slower than just going to the point.
11839    */
11840   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
11841       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
11842       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
11843       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11844     {
11845       if (tree_view->priv->scroll_to_path)
11846         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11847
11848       tree_view->priv->scroll_to_path = NULL;
11849       tree_view->priv->scroll_to_column = NULL;
11850
11851       if (path)
11852         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11853       if (column)
11854         tree_view->priv->scroll_to_column = column;
11855       tree_view->priv->scroll_to_use_align = use_align;
11856       tree_view->priv->scroll_to_row_align = row_align;
11857       tree_view->priv->scroll_to_col_align = col_align;
11858
11859       install_presize_handler (tree_view);
11860     }
11861   else
11862     {
11863       GdkRectangle cell_rect;
11864       GdkRectangle vis_rect;
11865       gint dest_x, dest_y;
11866
11867       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11868       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11869
11870       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11871
11872       dest_x = vis_rect.x;
11873       dest_y = vis_rect.y;
11874
11875       if (column)
11876         {
11877           if (use_align)
11878             {
11879               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11880             }
11881           else
11882             {
11883               if (cell_rect.x < vis_rect.x)
11884                 dest_x = cell_rect.x;
11885               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11886                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11887             }
11888         }
11889
11890       if (path)
11891         {
11892           if (use_align)
11893             {
11894               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11895               dest_y = MAX (dest_y, 0);
11896             }
11897           else
11898             {
11899               if (cell_rect.y < vis_rect.y)
11900                 dest_y = cell_rect.y;
11901               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11902                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11903             }
11904         }
11905
11906       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11907     }
11908 }
11909
11910 /**
11911  * gtk_tree_view_row_activated:
11912  * @tree_view: A #GtkTreeView
11913  * @path: The #GtkTreePath to be activated.
11914  * @column: The #GtkTreeViewColumn to be activated.
11915  *
11916  * Activates the cell determined by @path and @column.
11917  **/
11918 void
11919 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11920                              GtkTreePath       *path,
11921                              GtkTreeViewColumn *column)
11922 {
11923   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11924
11925   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11926 }
11927
11928
11929 static void
11930 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11931                                           GtkRBNode *node,
11932                                           gpointer   data)
11933 {
11934   GtkTreeView *tree_view = data;
11935
11936   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11937       node->children)
11938     {
11939       GtkTreePath *path;
11940       GtkTreeIter iter;
11941
11942       path = _gtk_tree_view_find_path (tree_view, tree, node);
11943       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11944
11945       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11946
11947       gtk_tree_path_free (path);
11948     }
11949
11950   if (node->children)
11951     _gtk_rbtree_traverse (node->children,
11952                           node->children->root,
11953                           G_PRE_ORDER,
11954                           gtk_tree_view_expand_all_emission_helper,
11955                           tree_view);
11956 }
11957
11958 /**
11959  * gtk_tree_view_expand_all:
11960  * @tree_view: A #GtkTreeView.
11961  *
11962  * Recursively expands all nodes in the @tree_view.
11963  **/
11964 void
11965 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11966 {
11967   GtkTreePath *path;
11968   GtkRBTree *tree;
11969   GtkRBNode *node;
11970
11971   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11972
11973   if (tree_view->priv->tree == NULL)
11974     return;
11975
11976   path = gtk_tree_path_new_first ();
11977   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11978
11979   while (node)
11980     {
11981       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11982       node = _gtk_rbtree_next (tree, node);
11983       gtk_tree_path_next (path);
11984   }
11985
11986   gtk_tree_path_free (path);
11987 }
11988
11989 /* Timeout to animate the expander during expands and collapses */
11990 static gboolean
11991 expand_collapse_timeout (gpointer data)
11992 {
11993   return do_expand_collapse (data);
11994 }
11995
11996 static void
11997 add_expand_collapse_timeout (GtkTreeView *tree_view,
11998                              GtkRBTree   *tree,
11999                              GtkRBNode   *node,
12000                              gboolean     expand)
12001 {
12002   if (tree_view->priv->expand_collapse_timeout != 0)
12003     return;
12004
12005   tree_view->priv->expand_collapse_timeout =
12006       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
12007   tree_view->priv->expanded_collapsed_tree = tree;
12008   tree_view->priv->expanded_collapsed_node = node;
12009
12010   if (expand)
12011     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12012   else
12013     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12014 }
12015
12016 static void
12017 remove_expand_collapse_timeout (GtkTreeView *tree_view)
12018 {
12019   if (tree_view->priv->expand_collapse_timeout)
12020     {
12021       g_source_remove (tree_view->priv->expand_collapse_timeout);
12022       tree_view->priv->expand_collapse_timeout = 0;
12023     }
12024
12025   if (tree_view->priv->expanded_collapsed_node != NULL)
12026     {
12027       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
12028       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12029
12030       tree_view->priv->expanded_collapsed_node = NULL;
12031     }
12032 }
12033
12034 static void
12035 cancel_arrow_animation (GtkTreeView *tree_view)
12036 {
12037   if (tree_view->priv->expand_collapse_timeout)
12038     {
12039       while (do_expand_collapse (tree_view));
12040
12041       remove_expand_collapse_timeout (tree_view);
12042     }
12043 }
12044
12045 static gboolean
12046 do_expand_collapse (GtkTreeView *tree_view)
12047 {
12048   GtkRBNode *node;
12049   GtkRBTree *tree;
12050   gboolean expanding;
12051   gboolean redraw;
12052
12053   redraw = FALSE;
12054   expanding = TRUE;
12055
12056   node = tree_view->priv->expanded_collapsed_node;
12057   tree = tree_view->priv->expanded_collapsed_tree;
12058
12059   if (node->children == NULL)
12060     expanding = FALSE;
12061
12062   if (expanding)
12063     {
12064       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12065         {
12066           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12067           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12068
12069           redraw = TRUE;
12070
12071         }
12072       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12073         {
12074           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12075
12076           redraw = TRUE;
12077         }
12078     }
12079   else
12080     {
12081       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12082         {
12083           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12084           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12085
12086           redraw = TRUE;
12087         }
12088       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12089         {
12090           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12091
12092           redraw = TRUE;
12093
12094         }
12095     }
12096
12097   if (redraw)
12098     {
12099       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
12100
12101       return TRUE;
12102     }
12103
12104   return FALSE;
12105 }
12106
12107 /**
12108  * gtk_tree_view_collapse_all:
12109  * @tree_view: A #GtkTreeView.
12110  *
12111  * Recursively collapses all visible, expanded nodes in @tree_view.
12112  **/
12113 void
12114 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12115 {
12116   GtkRBTree *tree;
12117   GtkRBNode *node;
12118   GtkTreePath *path;
12119   gint *indices;
12120
12121   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12122
12123   if (tree_view->priv->tree == NULL)
12124     return;
12125
12126   path = gtk_tree_path_new ();
12127   gtk_tree_path_down (path);
12128   indices = gtk_tree_path_get_indices (path);
12129
12130   tree = tree_view->priv->tree;
12131   node = tree->root;
12132   while (node && node->left != tree->nil)
12133     node = node->left;
12134
12135   while (node)
12136     {
12137       if (node->children)
12138         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12139       indices[0]++;
12140       node = _gtk_rbtree_next (tree, node);
12141     }
12142
12143   gtk_tree_path_free (path);
12144 }
12145
12146 /**
12147  * gtk_tree_view_expand_to_path:
12148  * @tree_view: A #GtkTreeView.
12149  * @path: path to a row.
12150  *
12151  * Expands the row at @path. This will also expand all parent rows of
12152  * @path as necessary.
12153  *
12154  * Since: 2.2
12155  **/
12156 void
12157 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12158                               GtkTreePath *path)
12159 {
12160   gint i, depth;
12161   gint *indices;
12162   GtkTreePath *tmp;
12163
12164   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12165   g_return_if_fail (path != NULL);
12166
12167   depth = gtk_tree_path_get_depth (path);
12168   indices = gtk_tree_path_get_indices (path);
12169
12170   tmp = gtk_tree_path_new ();
12171   g_return_if_fail (tmp != NULL);
12172
12173   for (i = 0; i < depth; i++)
12174     {
12175       gtk_tree_path_append_index (tmp, indices[i]);
12176       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12177     }
12178
12179   gtk_tree_path_free (tmp);
12180 }
12181
12182 /* FIXME the bool return values for expand_row and collapse_row are
12183  * not analagous; they should be TRUE if the row had children and
12184  * was not already in the requested state.
12185  */
12186
12187
12188 static gboolean
12189 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12190                                GtkTreePath *path,
12191                                GtkRBTree   *tree,
12192                                GtkRBNode   *node,
12193                                gboolean     open_all,
12194                                gboolean     animate)
12195 {
12196   GtkTreeIter iter;
12197   GtkTreeIter temp;
12198   gboolean expand;
12199
12200   if (animate)
12201     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12202                   "gtk-enable-animations", &animate,
12203                   NULL);
12204
12205   remove_auto_expand_timeout (tree_view);
12206
12207   if (node->children && !open_all)
12208     return FALSE;
12209
12210   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12211     return FALSE;
12212
12213   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12214   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12215     return FALSE;
12216
12217
12218    if (node->children && open_all)
12219     {
12220       gboolean retval = FALSE;
12221       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12222
12223       gtk_tree_path_append_index (tmp_path, 0);
12224       tree = node->children;
12225       node = tree->root;
12226       while (node->left != tree->nil)
12227         node = node->left;
12228       /* try to expand the children */
12229       do
12230         {
12231          gboolean t;
12232          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12233                                             TRUE, animate);
12234          if (t)
12235            retval = TRUE;
12236
12237          gtk_tree_path_next (tmp_path);
12238          node = _gtk_rbtree_next (tree, node);
12239        }
12240       while (node != NULL);
12241
12242       gtk_tree_path_free (tmp_path);
12243
12244       return retval;
12245     }
12246
12247   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12248
12249   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12250     return FALSE;
12251
12252   if (expand)
12253     return FALSE;
12254
12255   node->children = _gtk_rbtree_new ();
12256   node->children->parent_tree = tree;
12257   node->children->parent_node = node;
12258
12259   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12260
12261   gtk_tree_view_build_tree (tree_view,
12262                             node->children,
12263                             &temp,
12264                             gtk_tree_path_get_depth (path) + 1,
12265                             open_all);
12266
12267   remove_expand_collapse_timeout (tree_view);
12268
12269   if (animate)
12270     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12271
12272   install_presize_handler (tree_view);
12273
12274   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12275   if (open_all && node->children)
12276     {
12277       _gtk_rbtree_traverse (node->children,
12278                             node->children->root,
12279                             G_PRE_ORDER,
12280                             gtk_tree_view_expand_all_emission_helper,
12281                             tree_view);
12282     }
12283   return TRUE;
12284 }
12285
12286
12287 /**
12288  * gtk_tree_view_expand_row:
12289  * @tree_view: a #GtkTreeView
12290  * @path: path to a row
12291  * @open_all: whether to recursively expand, or just expand immediate children
12292  *
12293  * Opens the row so its children are visible.
12294  *
12295  * Return value: %TRUE if the row existed and had children
12296  **/
12297 gboolean
12298 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12299                           GtkTreePath *path,
12300                           gboolean     open_all)
12301 {
12302   GtkRBTree *tree;
12303   GtkRBNode *node;
12304
12305   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12306   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12307   g_return_val_if_fail (path != NULL, FALSE);
12308
12309   if (_gtk_tree_view_find_node (tree_view,
12310                                 path,
12311                                 &tree,
12312                                 &node))
12313     return FALSE;
12314
12315   if (tree != NULL)
12316     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12317   else
12318     return FALSE;
12319 }
12320
12321 static gboolean
12322 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12323                                  GtkTreePath *path,
12324                                  GtkRBTree   *tree,
12325                                  GtkRBNode   *node,
12326                                  gboolean     animate)
12327 {
12328   GtkTreeIter iter;
12329   GtkTreeIter children;
12330   gboolean collapse;
12331   gint x, y;
12332   GList *list;
12333   GdkWindow *child, *parent;
12334
12335   if (animate)
12336     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12337                   "gtk-enable-animations", &animate,
12338                   NULL);
12339
12340   remove_auto_expand_timeout (tree_view);
12341
12342   if (node->children == NULL)
12343     return FALSE;
12344
12345   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12346
12347   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12348
12349   if (collapse)
12350     return FALSE;
12351
12352   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12353    * a chance to prelight the correct node below */
12354
12355   if (tree_view->priv->prelight_tree)
12356     {
12357       GtkRBTree *parent_tree;
12358       GtkRBNode *parent_node;
12359
12360       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12361       parent_node = tree_view->priv->prelight_tree->parent_node;
12362       while (parent_tree)
12363         {
12364           if (parent_tree == tree && parent_node == node)
12365             {
12366               ensure_unprelighted (tree_view);
12367               break;
12368             }
12369           parent_node = parent_tree->parent_node;
12370           parent_tree = parent_tree->parent_tree;
12371         }
12372     }
12373
12374   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12375
12376   for (list = tree_view->priv->columns; list; list = list->next)
12377     {
12378       GtkTreeViewColumn *column = list->data;
12379
12380       if (column->visible == FALSE)
12381         continue;
12382       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12383         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12384     }
12385
12386   if (tree_view->priv->destroy_count_func)
12387     {
12388       GtkTreePath *child_path;
12389       gint child_count = 0;
12390       child_path = gtk_tree_path_copy (path);
12391       gtk_tree_path_down (child_path);
12392       if (node->children)
12393         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12394       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12395       gtk_tree_path_free (child_path);
12396     }
12397
12398   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12399     {
12400       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12401
12402       if (gtk_tree_path_is_ancestor (path, cursor_path))
12403         {
12404           gtk_tree_row_reference_free (tree_view->priv->cursor);
12405           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12406                                                                       tree_view->priv->model,
12407                                                                       path);
12408         }
12409       gtk_tree_path_free (cursor_path);
12410     }
12411
12412   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12413     {
12414       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12415       if (gtk_tree_path_is_ancestor (path, anchor_path))
12416         {
12417           gtk_tree_row_reference_free (tree_view->priv->anchor);
12418           tree_view->priv->anchor = NULL;
12419         }
12420       gtk_tree_path_free (anchor_path);
12421     }
12422
12423   /* Stop a pending double click */
12424   tree_view->priv->last_button_x = -1;
12425   tree_view->priv->last_button_y = -1;
12426
12427   remove_expand_collapse_timeout (tree_view);
12428
12429   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12430     {
12431       _gtk_rbtree_remove (node->children);
12432       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12433     }
12434   else
12435     _gtk_rbtree_remove (node->children);
12436   
12437   if (animate)
12438     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12439   
12440   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12441     {
12442       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12443     }
12444
12445   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12446
12447   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12448     {
12449       /* now that we've collapsed all rows, we want to try to set the prelight
12450        * again. To do this, we fake a motion event and send it to ourselves. */
12451
12452       child = tree_view->priv->bin_window;
12453       parent = gdk_window_get_parent (child);
12454
12455       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12456         {
12457           GdkEventMotion event;
12458           gint child_x, child_y;
12459
12460           gdk_window_get_position (child, &child_x, &child_y);
12461
12462           event.window = tree_view->priv->bin_window;
12463           event.x = x - child_x;
12464           event.y = y - child_y;
12465
12466           /* despite the fact this isn't a real event, I'm almost positive it will
12467            * never trigger a drag event.  maybe_drag is the only function that uses
12468            * more than just event.x and event.y. */
12469           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12470         }
12471     }
12472
12473   return TRUE;
12474 }
12475
12476 /**
12477  * gtk_tree_view_collapse_row:
12478  * @tree_view: a #GtkTreeView
12479  * @path: path to a row in the @tree_view
12480  *
12481  * Collapses a row (hides its child rows, if they exist).
12482  *
12483  * Return value: %TRUE if the row was collapsed.
12484  **/
12485 gboolean
12486 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12487                             GtkTreePath *path)
12488 {
12489   GtkRBTree *tree;
12490   GtkRBNode *node;
12491
12492   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12493   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12494   g_return_val_if_fail (path != NULL, FALSE);
12495
12496   if (_gtk_tree_view_find_node (tree_view,
12497                                 path,
12498                                 &tree,
12499                                 &node))
12500     return FALSE;
12501
12502   if (tree == NULL || node->children == NULL)
12503     return FALSE;
12504
12505   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12506 }
12507
12508 static void
12509 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12510                                         GtkRBTree              *tree,
12511                                         GtkTreePath            *path,
12512                                         GtkTreeViewMappingFunc  func,
12513                                         gpointer                user_data)
12514 {
12515   GtkRBNode *node;
12516
12517   if (tree == NULL || tree->root == NULL)
12518     return;
12519
12520   node = tree->root;
12521
12522   while (node && node->left != tree->nil)
12523     node = node->left;
12524
12525   while (node)
12526     {
12527       if (node->children)
12528         {
12529           (* func) (tree_view, path, user_data);
12530           gtk_tree_path_down (path);
12531           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12532           gtk_tree_path_up (path);
12533         }
12534       gtk_tree_path_next (path);
12535       node = _gtk_rbtree_next (tree, node);
12536     }
12537 }
12538
12539 /**
12540  * gtk_tree_view_map_expanded_rows:
12541  * @tree_view: A #GtkTreeView
12542  * @func: (scope call): A function to be called
12543  * @data: User data to be passed to the function.
12544  *
12545  * Calls @func on all expanded rows.
12546  **/
12547 void
12548 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12549                                  GtkTreeViewMappingFunc  func,
12550                                  gpointer                user_data)
12551 {
12552   GtkTreePath *path;
12553
12554   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12555   g_return_if_fail (func != NULL);
12556
12557   path = gtk_tree_path_new_first ();
12558
12559   gtk_tree_view_map_expanded_rows_helper (tree_view,
12560                                           tree_view->priv->tree,
12561                                           path, func, user_data);
12562
12563   gtk_tree_path_free (path);
12564 }
12565
12566 /**
12567  * gtk_tree_view_row_expanded:
12568  * @tree_view: A #GtkTreeView.
12569  * @path: A #GtkTreePath to test expansion state.
12570  *
12571  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12572  *
12573  * Return value: %TRUE if #path is expanded.
12574  **/
12575 gboolean
12576 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12577                             GtkTreePath *path)
12578 {
12579   GtkRBTree *tree;
12580   GtkRBNode *node;
12581
12582   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12583   g_return_val_if_fail (path != NULL, FALSE);
12584
12585   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12586
12587   if (node == NULL)
12588     return FALSE;
12589
12590   return (node->children != NULL);
12591 }
12592
12593 /**
12594  * gtk_tree_view_get_reorderable:
12595  * @tree_view: a #GtkTreeView
12596  *
12597  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12598  * gtk_tree_view_set_reorderable().
12599  *
12600  * Return value: %TRUE if the tree can be reordered.
12601  **/
12602 gboolean
12603 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12604 {
12605   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12606
12607   return tree_view->priv->reorderable;
12608 }
12609
12610 /**
12611  * gtk_tree_view_set_reorderable:
12612  * @tree_view: A #GtkTreeView.
12613  * @reorderable: %TRUE, if the tree can be reordered.
12614  *
12615  * This function is a convenience function to allow you to reorder
12616  * models that support the #GtkDragSourceIface and the
12617  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12618  * these.  If @reorderable is %TRUE, then the user can reorder the
12619  * model by dragging and dropping rows. The developer can listen to
12620  * these changes by connecting to the model's row_inserted and
12621  * row_deleted signals. The reordering is implemented by setting up
12622  * the tree view as a drag source and destination. Therefore, drag and
12623  * drop can not be used in a reorderable view for any other purpose.
12624  *
12625  * This function does not give you any degree of control over the order -- any
12626  * reordering is allowed.  If more control is needed, you should probably
12627  * handle drag and drop manually.
12628  **/
12629 void
12630 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12631                                gboolean     reorderable)
12632 {
12633   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12634
12635   reorderable = reorderable != FALSE;
12636
12637   if (tree_view->priv->reorderable == reorderable)
12638     return;
12639
12640   if (reorderable)
12641     {
12642       const GtkTargetEntry row_targets[] = {
12643         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12644       };
12645
12646       gtk_tree_view_enable_model_drag_source (tree_view,
12647                                               GDK_BUTTON1_MASK,
12648                                               row_targets,
12649                                               G_N_ELEMENTS (row_targets),
12650                                               GDK_ACTION_MOVE);
12651       gtk_tree_view_enable_model_drag_dest (tree_view,
12652                                             row_targets,
12653                                             G_N_ELEMENTS (row_targets),
12654                                             GDK_ACTION_MOVE);
12655     }
12656   else
12657     {
12658       gtk_tree_view_unset_rows_drag_source (tree_view);
12659       gtk_tree_view_unset_rows_drag_dest (tree_view);
12660     }
12661
12662   tree_view->priv->reorderable = reorderable;
12663
12664   g_object_notify (G_OBJECT (tree_view), "reorderable");
12665 }
12666
12667 static void
12668 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12669                                GtkTreePath     *path,
12670                                gboolean         clear_and_select,
12671                                gboolean         clamp_node)
12672 {
12673   GtkRBTree *tree = NULL;
12674   GtkRBNode *node = NULL;
12675
12676   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12677     {
12678       GtkTreePath *cursor_path;
12679       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12680       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12681       gtk_tree_path_free (cursor_path);
12682     }
12683
12684   gtk_tree_row_reference_free (tree_view->priv->cursor);
12685   tree_view->priv->cursor = NULL;
12686
12687   /* One cannot set the cursor on a separator.   Also, if
12688    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12689    * before finding the tree and node belonging to path.  The
12690    * path maps to a non-existing path and we will silently bail out.
12691    * We unset tree and node to avoid further processing.
12692    */
12693   if (!row_is_separator (tree_view, NULL, path)
12694       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12695     {
12696       tree_view->priv->cursor =
12697           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12698                                             tree_view->priv->model,
12699                                             path);
12700     }
12701   else
12702     {
12703       tree = NULL;
12704       node = NULL;
12705     }
12706
12707   if (tree != NULL)
12708     {
12709       GtkRBTree *new_tree = NULL;
12710       GtkRBNode *new_node = NULL;
12711
12712       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12713         {
12714           GtkTreeSelectMode mode = 0;
12715
12716           if (tree_view->priv->ctrl_pressed)
12717             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12718           if (tree_view->priv->shift_pressed)
12719             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12720
12721           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12722                                                     node, tree, path, mode,
12723                                                     FALSE);
12724         }
12725
12726       /* We have to re-find tree and node here again, somebody might have
12727        * cleared the node or the whole tree in the GtkTreeSelection::changed
12728        * callback. If the nodes differ we bail out here.
12729        */
12730       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12731
12732       if (tree != new_tree || node != new_node)
12733         return;
12734
12735       if (clamp_node)
12736         {
12737           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12738           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12739         }
12740     }
12741
12742   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12743 }
12744
12745 /**
12746  * gtk_tree_view_get_cursor:
12747  * @tree_view: A #GtkTreeView
12748  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
12749  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
12750  *
12751  * Fills in @path and @focus_column with the current path and focus column.  If
12752  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12753  * currently has focus, then *@focus_column will be %NULL.
12754  *
12755  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12756  * you are done with it.
12757  **/
12758 void
12759 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12760                           GtkTreePath       **path,
12761                           GtkTreeViewColumn **focus_column)
12762 {
12763   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12764
12765   if (path)
12766     {
12767       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12768         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12769       else
12770         *path = NULL;
12771     }
12772
12773   if (focus_column)
12774     {
12775       *focus_column = tree_view->priv->focus_column;
12776     }
12777 }
12778
12779 /**
12780  * gtk_tree_view_set_cursor:
12781  * @tree_view: A #GtkTreeView
12782  * @path: A #GtkTreePath
12783  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12784  * @start_editing: %TRUE if the specified cell should start being edited.
12785  *
12786  * Sets the current keyboard focus to be at @path, and selects it.  This is
12787  * useful when you want to focus the user's attention on a particular row.  If
12788  * @focus_column is not %NULL, then focus is given to the column specified by 
12789  * it. Additionally, if @focus_column is specified, and @start_editing is 
12790  * %TRUE, then editing should be started in the specified cell.  
12791  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12792  * in order to give keyboard focus to the widget.  Please note that editing 
12793  * can only happen when the widget is realized.
12794  *
12795  * If @path is invalid for @model, the current cursor (if any) will be unset
12796  * and the function will return without failing.
12797  **/
12798 void
12799 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12800                           GtkTreePath       *path,
12801                           GtkTreeViewColumn *focus_column,
12802                           gboolean           start_editing)
12803 {
12804   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12805                                     NULL, start_editing);
12806 }
12807
12808 /**
12809  * gtk_tree_view_set_cursor_on_cell:
12810  * @tree_view: A #GtkTreeView
12811  * @path: A #GtkTreePath
12812  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12813  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12814  * @start_editing: %TRUE if the specified cell should start being edited.
12815  *
12816  * Sets the current keyboard focus to be at @path, and selects it.  This is
12817  * useful when you want to focus the user's attention on a particular row.  If
12818  * @focus_column is not %NULL, then focus is given to the column specified by
12819  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12820  * contains 2 or more editable or activatable cells, then focus is given to
12821  * the cell specified by @focus_cell. Additionally, if @focus_column is
12822  * specified, and @start_editing is %TRUE, then editing should be started in
12823  * the specified cell.  This function is often followed by
12824  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12825  * widget.  Please note that editing can only happen when the widget is
12826  * realized.
12827  *
12828  * If @path is invalid for @model, the current cursor (if any) will be unset
12829  * and the function will return without failing.
12830  *
12831  * Since: 2.2
12832  **/
12833 void
12834 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12835                                   GtkTreePath       *path,
12836                                   GtkTreeViewColumn *focus_column,
12837                                   GtkCellRenderer   *focus_cell,
12838                                   gboolean           start_editing)
12839 {
12840   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12841   g_return_if_fail (path != NULL);
12842   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12843
12844   if (!tree_view->priv->model)
12845     return;
12846
12847   if (focus_cell)
12848     {
12849       g_return_if_fail (focus_column);
12850       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12851     }
12852
12853   /* cancel the current editing, if it exists */
12854   if (tree_view->priv->edited_column &&
12855       tree_view->priv->edited_column->editable_widget)
12856     gtk_tree_view_stop_editing (tree_view, TRUE);
12857
12858   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12859
12860   if (focus_column && focus_column->visible)
12861     {
12862       GList *list;
12863       gboolean column_in_tree = FALSE;
12864
12865       for (list = tree_view->priv->columns; list; list = list->next)
12866         if (list->data == focus_column)
12867           {
12868             column_in_tree = TRUE;
12869             break;
12870           }
12871       g_return_if_fail (column_in_tree);
12872       tree_view->priv->focus_column = focus_column;
12873       if (focus_cell)
12874         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12875       if (start_editing)
12876         gtk_tree_view_start_editing (tree_view, path);
12877     }
12878 }
12879
12880 /**
12881  * gtk_tree_view_get_bin_window:
12882  * @tree_view: A #GtkTreeView
12883  *
12884  * Returns the window that @tree_view renders to.
12885  * This is used primarily to compare to <literal>event->window</literal>
12886  * to confirm that the event on @tree_view is on the right window.
12887  *
12888  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
12889  *     hasn't been realized yet
12890  **/
12891 GdkWindow *
12892 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12893 {
12894   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12895
12896   return tree_view->priv->bin_window;
12897 }
12898
12899 /**
12900  * gtk_tree_view_get_path_at_pos:
12901  * @tree_view: A #GtkTreeView.
12902  * @x: The x position to be identified (relative to bin_window).
12903  * @y: The y position to be identified (relative to bin_window).
12904  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12905  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12906  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
12907  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12908  *
12909  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12910  * (please see gtk_tree_view_get_bin_window()).
12911  * That is, @x and @y are relative to an events coordinates. @x and @y must
12912  * come from an event on the @tree_view only where <literal>event->window ==
12913  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12914  * things like popup menus. If @path is non-%NULL, then it will be filled
12915  * with the #GtkTreePath at that point.  This path should be freed with
12916  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12917  * with the column at that point.  @cell_x and @cell_y return the coordinates
12918  * relative to the cell background (i.e. the @background_area passed to
12919  * gtk_cell_renderer_render()).  This function is only meaningful if
12920  * @tree_view is realized.  Therefore this function will always return %FALSE
12921  * if @tree_view is not realized or does not have a model.
12922  *
12923  * For converting widget coordinates (eg. the ones you get from
12924  * GtkWidget::query-tooltip), please see
12925  * gtk_tree_view_convert_widget_to_bin_window_coords().
12926  *
12927  * Return value: %TRUE if a row exists at that coordinate.
12928  **/
12929 gboolean
12930 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12931                                gint                x,
12932                                gint                y,
12933                                GtkTreePath       **path,
12934                                GtkTreeViewColumn **column,
12935                                gint               *cell_x,
12936                                gint               *cell_y)
12937 {
12938   GtkRBTree *tree;
12939   GtkRBNode *node;
12940   gint y_offset;
12941
12942   g_return_val_if_fail (tree_view != NULL, FALSE);
12943
12944   if (path)
12945     *path = NULL;
12946   if (column)
12947     *column = NULL;
12948
12949   if (tree_view->priv->bin_window == NULL)
12950     return FALSE;
12951
12952   if (tree_view->priv->tree == NULL)
12953     return FALSE;
12954
12955   if (x > tree_view->priv->hadjustment->upper)
12956     return FALSE;
12957
12958   if (x < 0 || y < 0)
12959     return FALSE;
12960
12961   if (column || cell_x)
12962     {
12963       GtkTreeViewColumn *tmp_column;
12964       GtkTreeViewColumn *last_column = NULL;
12965       GList *list;
12966       gint remaining_x = x;
12967       gboolean found = FALSE;
12968       gboolean rtl;
12969
12970       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12971       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12972            list;
12973            list = (rtl ? list->prev : list->next))
12974         {
12975           tmp_column = list->data;
12976
12977           if (tmp_column->visible == FALSE)
12978             continue;
12979
12980           last_column = tmp_column;
12981           if (remaining_x <= tmp_column->width)
12982             {
12983               found = TRUE;
12984
12985               if (column)
12986                 *column = tmp_column;
12987
12988               if (cell_x)
12989                 *cell_x = remaining_x;
12990
12991               break;
12992             }
12993           remaining_x -= tmp_column->width;
12994         }
12995
12996       /* If found is FALSE and there is a last_column, then it the remainder
12997        * space is in that area
12998        */
12999       if (!found)
13000         {
13001           if (last_column)
13002             {
13003               if (column)
13004                 *column = last_column;
13005               
13006               if (cell_x)
13007                 *cell_x = last_column->width + remaining_x;
13008             }
13009           else
13010             {
13011               return FALSE;
13012             }
13013         }
13014     }
13015
13016   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13017                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13018                                       &tree, &node);
13019
13020   if (tree == NULL)
13021     return FALSE;
13022
13023   if (cell_y)
13024     *cell_y = y_offset;
13025
13026   if (path)
13027     *path = _gtk_tree_view_find_path (tree_view, tree, node);
13028
13029   return TRUE;
13030 }
13031
13032
13033 /**
13034  * gtk_tree_view_get_cell_area:
13035  * @tree_view: a #GtkTreeView
13036  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13037  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13038  * @rect: rectangle to fill with cell rect
13039  *
13040  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13041  * row specified by @path and the column specified by @column.  If @path is
13042  * %NULL, or points to a path not currently displayed, the @y and @height fields
13043  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13044  * fields will be filled with 0.  The sum of all cell rects does not cover the
13045  * entire tree; there are extra pixels in between rows, for example. The
13046  * returned rectangle is equivalent to the @cell_area passed to
13047  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13048  * realized.
13049  **/
13050 void
13051 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13052                              GtkTreePath        *path,
13053                              GtkTreeViewColumn  *column,
13054                              GdkRectangle       *rect)
13055 {
13056   GtkAllocation allocation;
13057   GtkRBTree *tree = NULL;
13058   GtkRBNode *node = NULL;
13059   gint vertical_separator;
13060   gint horizontal_separator;
13061
13062   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13063   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13064   g_return_if_fail (rect != NULL);
13065   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
13066   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13067
13068   gtk_widget_style_get (GTK_WIDGET (tree_view),
13069                         "vertical-separator", &vertical_separator,
13070                         "horizontal-separator", &horizontal_separator,
13071                         NULL);
13072
13073   rect->x = 0;
13074   rect->y = 0;
13075   rect->width = 0;
13076   rect->height = 0;
13077
13078   if (column)
13079     {
13080       gtk_widget_get_allocation (column->button, &allocation);
13081       rect->x = allocation.x + horizontal_separator/2;
13082       rect->width = allocation.width - horizontal_separator;
13083     }
13084
13085   if (path)
13086     {
13087       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13088
13089       /* Get vertical coords */
13090       if ((!ret && tree == NULL) || ret)
13091         return;
13092
13093       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
13094       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
13095
13096       if (column &&
13097           gtk_tree_view_is_expander_column (tree_view, column))
13098         {
13099           gint depth = gtk_tree_path_get_depth (path);
13100           gboolean rtl;
13101
13102           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13103
13104           if (!rtl)
13105             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13106           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13107
13108           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
13109             {
13110               if (!rtl)
13111                 rect->x += depth * tree_view->priv->expander_size;
13112               rect->width -= depth * tree_view->priv->expander_size;
13113             }
13114
13115           rect->width = MAX (rect->width, 0);
13116         }
13117     }
13118 }
13119
13120 /**
13121  * gtk_tree_view_get_background_area:
13122  * @tree_view: a #GtkTreeView
13123  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13124  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13125  * @rect: rectangle to fill with cell background rect
13126  *
13127  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13128  * row specified by @path and the column specified by @column.  If @path is
13129  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13130  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13131  * fields will be filled with 0.  The returned rectangle is equivalent to the
13132  * @background_area passed to gtk_cell_renderer_render().  These background
13133  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13134  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13135  * itself, excluding surrounding borders and the tree expander area.
13136  *
13137  **/
13138 void
13139 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13140                                    GtkTreePath        *path,
13141                                    GtkTreeViewColumn  *column,
13142                                    GdkRectangle       *rect)
13143 {
13144   GtkRBTree *tree = NULL;
13145   GtkRBNode *node = NULL;
13146
13147   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13148   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13149   g_return_if_fail (rect != NULL);
13150
13151   rect->x = 0;
13152   rect->y = 0;
13153   rect->width = 0;
13154   rect->height = 0;
13155
13156   if (path)
13157     {
13158       /* Get vertical coords */
13159
13160       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13161           tree == NULL)
13162         return;
13163
13164       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13165
13166       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13167     }
13168
13169   if (column)
13170     {
13171       gint x2 = 0;
13172
13173       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13174       rect->width = x2 - rect->x;
13175     }
13176 }
13177
13178 /**
13179  * gtk_tree_view_get_visible_rect:
13180  * @tree_view: a #GtkTreeView
13181  * @visible_rect: rectangle to fill
13182  *
13183  * Fills @visible_rect with the currently-visible region of the
13184  * buffer, in tree coordinates. Convert to bin_window coordinates with
13185  * gtk_tree_view_convert_tree_to_bin_window_coords().
13186  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13187  * scrollable area of the tree.
13188  **/
13189 void
13190 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13191                                 GdkRectangle *visible_rect)
13192 {
13193   GtkAllocation allocation;
13194   GtkWidget *widget;
13195
13196   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13197
13198   widget = GTK_WIDGET (tree_view);
13199
13200   if (visible_rect)
13201     {
13202       gtk_widget_get_allocation (widget, &allocation);
13203       visible_rect->x = tree_view->priv->hadjustment->value;
13204       visible_rect->y = tree_view->priv->vadjustment->value;
13205       visible_rect->width = allocation.width;
13206       visible_rect->height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13207     }
13208 }
13209
13210 /**
13211  * gtk_tree_view_convert_widget_to_tree_coords:
13212  * @tree_view: a #GtkTreeView
13213  * @wx: X coordinate relative to the widget
13214  * @wy: Y coordinate relative to the widget
13215  * @tx: return location for tree X coordinate
13216  * @ty: return location for tree Y coordinate
13217  *
13218  * Converts widget coordinates to coordinates for the
13219  * tree (the full scrollable area of the tree).
13220  *
13221  * Since: 2.12
13222  **/
13223 void
13224 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13225                                              gint         wx,
13226                                              gint         wy,
13227                                              gint        *tx,
13228                                              gint        *ty)
13229 {
13230   gint x, y;
13231
13232   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13233
13234   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13235                                                      wx, wy,
13236                                                      &x, &y);
13237   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13238                                                    x, y,
13239                                                    tx, ty);
13240 }
13241
13242 /**
13243  * gtk_tree_view_convert_tree_to_widget_coords:
13244  * @tree_view: a #GtkTreeView
13245  * @tx: X coordinate relative to the tree
13246  * @ty: Y coordinate relative to the tree
13247  * @wx: return location for widget X coordinate
13248  * @wy: return location for widget Y coordinate
13249  *
13250  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13251  * to widget coordinates.
13252  *
13253  * Since: 2.12
13254  **/
13255 void
13256 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13257                                              gint         tx,
13258                                              gint         ty,
13259                                              gint        *wx,
13260                                              gint        *wy)
13261 {
13262   gint x, y;
13263
13264   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13265
13266   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13267                                                    tx, ty,
13268                                                    &x, &y);
13269   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13270                                                      x, y,
13271                                                      wx, wy);
13272 }
13273
13274 /**
13275  * gtk_tree_view_convert_widget_to_bin_window_coords:
13276  * @tree_view: a #GtkTreeView
13277  * @wx: X coordinate relative to the widget
13278  * @wy: Y coordinate relative to the widget
13279  * @bx: return location for bin_window X coordinate
13280  * @by: return location for bin_window Y coordinate
13281  *
13282  * Converts widget coordinates to coordinates for the bin_window
13283  * (see gtk_tree_view_get_bin_window()).
13284  *
13285  * Since: 2.12
13286  **/
13287 void
13288 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13289                                                    gint         wx,
13290                                                    gint         wy,
13291                                                    gint        *bx,
13292                                                    gint        *by)
13293 {
13294   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13295
13296   if (bx)
13297     *bx = wx + tree_view->priv->hadjustment->value;
13298   if (by)
13299     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13300 }
13301
13302 /**
13303  * gtk_tree_view_convert_bin_window_to_widget_coords:
13304  * @tree_view: a #GtkTreeView
13305  * @bx: bin_window X coordinate
13306  * @by: bin_window Y coordinate
13307  * @wx: return location for widget X coordinate
13308  * @wy: return location for widget Y coordinate
13309  *
13310  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13311  * to widget relative coordinates.
13312  *
13313  * Since: 2.12
13314  **/
13315 void
13316 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13317                                                    gint         bx,
13318                                                    gint         by,
13319                                                    gint        *wx,
13320                                                    gint        *wy)
13321 {
13322   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13323
13324   if (wx)
13325     *wx = bx - tree_view->priv->hadjustment->value;
13326   if (wy)
13327     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13328 }
13329
13330 /**
13331  * gtk_tree_view_convert_tree_to_bin_window_coords:
13332  * @tree_view: a #GtkTreeView
13333  * @tx: tree X coordinate
13334  * @ty: tree Y coordinate
13335  * @bx: return location for X coordinate relative to bin_window
13336  * @by: return location for Y coordinate relative to bin_window
13337  *
13338  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13339  * to bin_window coordinates.
13340  *
13341  * Since: 2.12
13342  **/
13343 void
13344 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13345                                                  gint         tx,
13346                                                  gint         ty,
13347                                                  gint        *bx,
13348                                                  gint        *by)
13349 {
13350   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13351
13352   if (bx)
13353     *bx = tx;
13354   if (by)
13355     *by = ty - tree_view->priv->dy;
13356 }
13357
13358 /**
13359  * gtk_tree_view_convert_bin_window_to_tree_coords:
13360  * @tree_view: a #GtkTreeView
13361  * @bx: X coordinate relative to bin_window
13362  * @by: Y coordinate relative to bin_window
13363  * @tx: return location for tree X coordinate
13364  * @ty: return location for tree Y coordinate
13365  *
13366  * Converts bin_window coordinates to coordinates for the
13367  * tree (the full scrollable area of the tree).
13368  *
13369  * Since: 2.12
13370  **/
13371 void
13372 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13373                                                  gint         bx,
13374                                                  gint         by,
13375                                                  gint        *tx,
13376                                                  gint        *ty)
13377 {
13378   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13379
13380   if (tx)
13381     *tx = bx;
13382   if (ty)
13383     *ty = by + tree_view->priv->dy;
13384 }
13385
13386
13387
13388 /**
13389  * gtk_tree_view_get_visible_range:
13390  * @tree_view: A #GtkTreeView
13391  * @start_path: (allow-none): Return location for start of region, or %NULL.
13392  * @end_path: (allow-none): Return location for end of region, or %NULL.
13393  *
13394  * Sets @start_path and @end_path to be the first and last visible path.
13395  * Note that there may be invisible paths in between.
13396  *
13397  * The paths should be freed with gtk_tree_path_free() after use.
13398  *
13399  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13400  *
13401  * Since: 2.8
13402  **/
13403 gboolean
13404 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13405                                  GtkTreePath **start_path,
13406                                  GtkTreePath **end_path)
13407 {
13408   GtkRBTree *tree;
13409   GtkRBNode *node;
13410   gboolean retval;
13411   
13412   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13413
13414   if (!tree_view->priv->tree)
13415     return FALSE;
13416
13417   retval = TRUE;
13418
13419   if (start_path)
13420     {
13421       _gtk_rbtree_find_offset (tree_view->priv->tree,
13422                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13423                                &tree, &node);
13424       if (node)
13425         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13426       else
13427         retval = FALSE;
13428     }
13429
13430   if (end_path)
13431     {
13432       gint y;
13433
13434       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13435         y = tree_view->priv->height - 1;
13436       else
13437         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13438
13439       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13440       if (node)
13441         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13442       else
13443         retval = FALSE;
13444     }
13445
13446   return retval;
13447 }
13448
13449 static void
13450 unset_reorderable (GtkTreeView *tree_view)
13451 {
13452   if (tree_view->priv->reorderable)
13453     {
13454       tree_view->priv->reorderable = FALSE;
13455       g_object_notify (G_OBJECT (tree_view), "reorderable");
13456     }
13457 }
13458
13459 /**
13460  * gtk_tree_view_enable_model_drag_source:
13461  * @tree_view: a #GtkTreeView
13462  * @start_button_mask: Mask of allowed buttons to start drag
13463  * @targets: the table of targets that the drag will support
13464  * @n_targets: the number of items in @targets
13465  * @actions: the bitmask of possible actions for a drag from this
13466  *    widget
13467  *
13468  * Turns @tree_view into a drag source for automatic DND. Calling this
13469  * method sets #GtkTreeView:reorderable to %FALSE.
13470  **/
13471 void
13472 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13473                                         GdkModifierType           start_button_mask,
13474                                         const GtkTargetEntry     *targets,
13475                                         gint                      n_targets,
13476                                         GdkDragAction             actions)
13477 {
13478   TreeViewDragInfo *di;
13479
13480   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13481
13482   gtk_drag_source_set (GTK_WIDGET (tree_view),
13483                        0,
13484                        targets,
13485                        n_targets,
13486                        actions);
13487
13488   di = ensure_info (tree_view);
13489
13490   di->start_button_mask = start_button_mask;
13491   di->source_actions = actions;
13492   di->source_set = TRUE;
13493
13494   unset_reorderable (tree_view);
13495 }
13496
13497 /**
13498  * gtk_tree_view_enable_model_drag_dest:
13499  * @tree_view: a #GtkTreeView
13500  * @targets: the table of targets that the drag will support
13501  * @n_targets: the number of items in @targets
13502  * @actions: the bitmask of possible actions for a drag from this
13503  *    widget
13504  * 
13505  * Turns @tree_view into a drop destination for automatic DND. Calling
13506  * this method sets #GtkTreeView:reorderable to %FALSE.
13507  **/
13508 void
13509 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13510                                       const GtkTargetEntry     *targets,
13511                                       gint                      n_targets,
13512                                       GdkDragAction             actions)
13513 {
13514   TreeViewDragInfo *di;
13515
13516   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13517
13518   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13519                      0,
13520                      targets,
13521                      n_targets,
13522                      actions);
13523
13524   di = ensure_info (tree_view);
13525   di->dest_set = TRUE;
13526
13527   unset_reorderable (tree_view);
13528 }
13529
13530 /**
13531  * gtk_tree_view_unset_rows_drag_source:
13532  * @tree_view: a #GtkTreeView
13533  *
13534  * Undoes the effect of
13535  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13536  * #GtkTreeView:reorderable to %FALSE.
13537  **/
13538 void
13539 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13540 {
13541   TreeViewDragInfo *di;
13542
13543   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13544
13545   di = get_info (tree_view);
13546
13547   if (di)
13548     {
13549       if (di->source_set)
13550         {
13551           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13552           di->source_set = FALSE;
13553         }
13554
13555       if (!di->dest_set && !di->source_set)
13556         remove_info (tree_view);
13557     }
13558   
13559   unset_reorderable (tree_view);
13560 }
13561
13562 /**
13563  * gtk_tree_view_unset_rows_drag_dest:
13564  * @tree_view: a #GtkTreeView
13565  *
13566  * Undoes the effect of
13567  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13568  * #GtkTreeView:reorderable to %FALSE.
13569  **/
13570 void
13571 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13572 {
13573   TreeViewDragInfo *di;
13574
13575   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13576
13577   di = get_info (tree_view);
13578
13579   if (di)
13580     {
13581       if (di->dest_set)
13582         {
13583           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13584           di->dest_set = FALSE;
13585         }
13586
13587       if (!di->dest_set && !di->source_set)
13588         remove_info (tree_view);
13589     }
13590
13591   unset_reorderable (tree_view);
13592 }
13593
13594 /**
13595  * gtk_tree_view_set_drag_dest_row:
13596  * @tree_view: a #GtkTreeView
13597  * @path: (allow-none): The path of the row to highlight, or %NULL.
13598  * @pos: Specifies whether to drop before, after or into the row
13599  * 
13600  * Sets the row that is highlighted for feedback.
13601  **/
13602 void
13603 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13604                                  GtkTreePath            *path,
13605                                  GtkTreeViewDropPosition pos)
13606 {
13607   GtkTreePath *current_dest;
13608
13609   /* Note; this function is exported to allow a custom DND
13610    * implementation, so it can't touch TreeViewDragInfo
13611    */
13612
13613   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13614
13615   current_dest = NULL;
13616
13617   if (tree_view->priv->drag_dest_row)
13618     {
13619       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13620       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13621     }
13622
13623   /* special case a drop on an empty model */
13624   tree_view->priv->empty_view_drop = 0;
13625
13626   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13627       && gtk_tree_path_get_depth (path) == 1
13628       && gtk_tree_path_get_indices (path)[0] == 0)
13629     {
13630       gint n_children;
13631
13632       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13633                                                    NULL);
13634
13635       if (!n_children)
13636         tree_view->priv->empty_view_drop = 1;
13637     }
13638
13639   tree_view->priv->drag_dest_pos = pos;
13640
13641   if (path)
13642     {
13643       tree_view->priv->drag_dest_row =
13644         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13645       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13646     }
13647   else
13648     tree_view->priv->drag_dest_row = NULL;
13649
13650   if (current_dest)
13651     {
13652       GtkRBTree *tree, *new_tree;
13653       GtkRBNode *node, *new_node;
13654
13655       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13656       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13657
13658       if (tree && node)
13659         {
13660           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13661           if (new_tree && new_node)
13662             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13663
13664           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13665           if (new_tree && new_node)
13666             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13667         }
13668       gtk_tree_path_free (current_dest);
13669     }
13670 }
13671
13672 /**
13673  * gtk_tree_view_get_drag_dest_row:
13674  * @tree_view: a #GtkTreeView
13675  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13676  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13677  * 
13678  * Gets information about the row that is highlighted for feedback.
13679  **/
13680 void
13681 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13682                                  GtkTreePath             **path,
13683                                  GtkTreeViewDropPosition  *pos)
13684 {
13685   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13686
13687   if (path)
13688     {
13689       if (tree_view->priv->drag_dest_row)
13690         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13691       else
13692         {
13693           if (tree_view->priv->empty_view_drop)
13694             *path = gtk_tree_path_new_from_indices (0, -1);
13695           else
13696             *path = NULL;
13697         }
13698     }
13699
13700   if (pos)
13701     *pos = tree_view->priv->drag_dest_pos;
13702 }
13703
13704 /**
13705  * gtk_tree_view_get_dest_row_at_pos:
13706  * @tree_view: a #GtkTreeView
13707  * @drag_x: the position to determine the destination row for
13708  * @drag_y: the position to determine the destination row for
13709  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13710  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13711  * 
13712  * Determines the destination row for a given position.  @drag_x and
13713  * @drag_y are expected to be in widget coordinates.  This function is only
13714  * meaningful if @tree_view is realized.  Therefore this function will always
13715  * return %FALSE if @tree_view is not realized or does not have a model.
13716  * 
13717  * Return value: whether there is a row at the given position, %TRUE if this
13718  * is indeed the case.
13719  **/
13720 gboolean
13721 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13722                                    gint                     drag_x,
13723                                    gint                     drag_y,
13724                                    GtkTreePath            **path,
13725                                    GtkTreeViewDropPosition *pos)
13726 {
13727   gint cell_y;
13728   gint bin_x, bin_y;
13729   gdouble offset_into_row;
13730   gdouble third;
13731   GdkRectangle cell;
13732   GtkTreeViewColumn *column = NULL;
13733   GtkTreePath *tmp_path = NULL;
13734
13735   /* Note; this function is exported to allow a custom DND
13736    * implementation, so it can't touch TreeViewDragInfo
13737    */
13738
13739   g_return_val_if_fail (tree_view != NULL, FALSE);
13740   g_return_val_if_fail (drag_x >= 0, FALSE);
13741   g_return_val_if_fail (drag_y >= 0, FALSE);
13742
13743   if (path)
13744     *path = NULL;
13745
13746   if (tree_view->priv->bin_window == NULL)
13747     return FALSE;
13748
13749   if (tree_view->priv->tree == NULL)
13750     return FALSE;
13751
13752   /* If in the top third of a row, we drop before that row; if
13753    * in the bottom third, drop after that row; if in the middle,
13754    * and the row has children, drop into the row.
13755    */
13756   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13757                                                      &bin_x, &bin_y);
13758
13759   if (!gtk_tree_view_get_path_at_pos (tree_view,
13760                                       bin_x,
13761                                       bin_y,
13762                                       &tmp_path,
13763                                       &column,
13764                                       NULL,
13765                                       &cell_y))
13766     return FALSE;
13767
13768   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13769                                      &cell);
13770
13771   offset_into_row = cell_y;
13772
13773   if (path)
13774     *path = tmp_path;
13775   else
13776     gtk_tree_path_free (tmp_path);
13777
13778   tmp_path = NULL;
13779
13780   third = cell.height / 3.0;
13781
13782   if (pos)
13783     {
13784       if (offset_into_row < third)
13785         {
13786           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13787         }
13788       else if (offset_into_row < (cell.height / 2.0))
13789         {
13790           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13791         }
13792       else if (offset_into_row < third * 2.0)
13793         {
13794           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13795         }
13796       else
13797         {
13798           *pos = GTK_TREE_VIEW_DROP_AFTER;
13799         }
13800     }
13801
13802   return TRUE;
13803 }
13804
13805
13806
13807 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13808 /**
13809  * gtk_tree_view_create_row_drag_icon:
13810  * @tree_view: a #GtkTreeView
13811  * @path: a #GtkTreePath in @tree_view
13812  *
13813  * Creates a #cairo_surface_t representation of the row at @path.  
13814  * This image is used for a drag icon.
13815  *
13816  * Return value: (transfer full): a newly-allocated surface of the drag icon.
13817  **/
13818 cairo_surface_t *
13819 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13820                                     GtkTreePath  *path)
13821 {
13822   GtkTreeIter   iter;
13823   GtkRBTree    *tree;
13824   GtkRBNode    *node;
13825   GtkStyle *style;
13826   gint cell_offset;
13827   GList *list;
13828   GdkRectangle background_area;
13829   GtkWidget *widget;
13830   gint depth;
13831   /* start drawing inside the black outline */
13832   gint x = 1, y = 1;
13833   cairo_surface_t *surface;
13834   gint bin_window_width;
13835   gboolean is_separator = FALSE;
13836   gboolean rtl;
13837   cairo_t *cr;
13838
13839   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13840   g_return_val_if_fail (path != NULL, NULL);
13841
13842   widget = GTK_WIDGET (tree_view);
13843
13844   if (!gtk_widget_get_realized (widget))
13845     return NULL;
13846
13847   depth = gtk_tree_path_get_depth (path);
13848
13849   _gtk_tree_view_find_node (tree_view,
13850                             path,
13851                             &tree,
13852                             &node);
13853
13854   if (tree == NULL)
13855     return NULL;
13856
13857   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13858                                 &iter,
13859                                 path))
13860     return NULL;
13861
13862   style = gtk_widget_get_style (widget);
13863
13864   is_separator = row_is_separator (tree_view, &iter, NULL);
13865
13866   cell_offset = x;
13867
13868   background_area.y = y;
13869   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13870
13871   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
13872
13873   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
13874                                                CAIRO_CONTENT_COLOR,
13875                                                bin_window_width + 2,
13876                                                background_area.height + 2);
13877
13878   cr = cairo_create (surface);
13879   gdk_cairo_set_source_color (cr, &style->base [gtk_widget_get_state (widget)]);
13880   cairo_paint (cr);
13881
13882   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13883
13884   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13885       list;
13886       list = (rtl ? list->prev : list->next))
13887     {
13888       GtkTreeViewColumn *column = list->data;
13889       GdkRectangle cell_area;
13890       gint vertical_separator;
13891
13892       if (!column->visible)
13893         continue;
13894
13895       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13896                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13897                                                node->children?TRUE:FALSE);
13898
13899       background_area.x = cell_offset;
13900       background_area.width = column->width;
13901
13902       gtk_widget_style_get (widget,
13903                             "vertical-separator", &vertical_separator,
13904                             NULL);
13905
13906       cell_area = background_area;
13907
13908       cell_area.y += vertical_separator / 2;
13909       cell_area.height -= vertical_separator;
13910
13911       if (gtk_tree_view_is_expander_column (tree_view, column))
13912         {
13913           if (!rtl)
13914             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13915           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13916
13917           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13918             {
13919               if (!rtl)
13920                 cell_area.x += depth * tree_view->priv->expander_size;
13921               cell_area.width -= depth * tree_view->priv->expander_size;
13922             }
13923         }
13924
13925       if (gtk_tree_view_column_cell_is_visible (column))
13926         {
13927           if (is_separator)
13928             gtk_paint_hline (style,
13929                                    cr,
13930                                    GTK_STATE_NORMAL,
13931                                    widget,
13932                                    NULL,
13933                                    cell_area.x,
13934                                    cell_area.x + cell_area.width,
13935                                    cell_area.y + cell_area.height / 2);
13936           else
13937             _gtk_tree_view_column_cell_render (column,
13938                                                cr,
13939                                                &background_area,
13940                                                &cell_area,
13941                                                0);
13942         }
13943       cell_offset += column->width;
13944     }
13945
13946   cairo_set_source_rgb (cr, 0, 0, 0);
13947   cairo_rectangle (cr, 
13948                    0.5, 0.5, 
13949                    bin_window_width + 1,
13950                    background_area.height + 1);
13951   cairo_set_line_width (cr, 1.0);
13952   cairo_stroke (cr);
13953
13954   cairo_destroy (cr);
13955
13956   cairo_surface_set_device_offset (surface, 2, 2);
13957
13958   return surface;
13959 }
13960
13961
13962 /**
13963  * gtk_tree_view_set_destroy_count_func:
13964  * @tree_view: A #GtkTreeView
13965  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
13966  * @data: (allow-none): User data to be passed to @func, or %NULL
13967  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
13968  *
13969  * This function should almost never be used.  It is meant for private use by
13970  * ATK for determining the number of visible children that are removed when the
13971  * user collapses a row, or a row is deleted.
13972  **/
13973 void
13974 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13975                                       GtkTreeDestroyCountFunc  func,
13976                                       gpointer                 data,
13977                                       GDestroyNotify           destroy)
13978 {
13979   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13980
13981   if (tree_view->priv->destroy_count_destroy)
13982     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13983
13984   tree_view->priv->destroy_count_func = func;
13985   tree_view->priv->destroy_count_data = data;
13986   tree_view->priv->destroy_count_destroy = destroy;
13987 }
13988
13989
13990 /*
13991  * Interactive search
13992  */
13993
13994 /**
13995  * gtk_tree_view_set_enable_search:
13996  * @tree_view: A #GtkTreeView
13997  * @enable_search: %TRUE, if the user can search interactively
13998  *
13999  * If @enable_search is set, then the user can type in text to search through
14000  * the tree interactively (this is sometimes called "typeahead find").
14001  * 
14002  * Note that even if this is %FALSE, the user can still initiate a search 
14003  * using the "start-interactive-search" key binding.
14004  */
14005 void
14006 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14007                                  gboolean     enable_search)
14008 {
14009   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14010
14011   enable_search = !!enable_search;
14012   
14013   if (tree_view->priv->enable_search != enable_search)
14014     {
14015        tree_view->priv->enable_search = enable_search;
14016        g_object_notify (G_OBJECT (tree_view), "enable-search");
14017     }
14018 }
14019
14020 /**
14021  * gtk_tree_view_get_enable_search:
14022  * @tree_view: A #GtkTreeView
14023  *
14024  * Returns whether or not the tree allows to start interactive searching 
14025  * by typing in text.
14026  *
14027  * Return value: whether or not to let the user search interactively
14028  */
14029 gboolean
14030 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14031 {
14032   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14033
14034   return tree_view->priv->enable_search;
14035 }
14036
14037
14038 /**
14039  * gtk_tree_view_get_search_column:
14040  * @tree_view: A #GtkTreeView
14041  *
14042  * Gets the column searched on by the interactive search code.
14043  *
14044  * Return value: the column the interactive search code searches in.
14045  */
14046 gint
14047 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14048 {
14049   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14050
14051   return (tree_view->priv->search_column);
14052 }
14053
14054 /**
14055  * gtk_tree_view_set_search_column:
14056  * @tree_view: A #GtkTreeView
14057  * @column: the column of the model to search in, or -1 to disable searching
14058  *
14059  * Sets @column as the column where the interactive search code should
14060  * search in for the current model. 
14061  * 
14062  * If the search column is set, users can use the "start-interactive-search"
14063  * key binding to bring up search popup. The enable-search property controls
14064  * whether simply typing text will also start an interactive search.
14065  *
14066  * Note that @column refers to a column of the current model. The search 
14067  * column is reset to -1 when the model is changed.
14068  */
14069 void
14070 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14071                                  gint         column)
14072 {
14073   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14074   g_return_if_fail (column >= -1);
14075
14076   if (tree_view->priv->search_column == column)
14077     return;
14078
14079   tree_view->priv->search_column = column;
14080   g_object_notify (G_OBJECT (tree_view), "search-column");
14081 }
14082
14083 /**
14084  * gtk_tree_view_get_search_equal_func:
14085  * @tree_view: A #GtkTreeView
14086  *
14087  * Returns the compare function currently in use.
14088  *
14089  * Return value: the currently used compare function for the search code.
14090  */
14091
14092 GtkTreeViewSearchEqualFunc
14093 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14094 {
14095   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14096
14097   return tree_view->priv->search_equal_func;
14098 }
14099
14100 /**
14101  * gtk_tree_view_set_search_equal_func:
14102  * @tree_view: A #GtkTreeView
14103  * @search_equal_func: the compare function to use during the search
14104  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14105  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14106  *
14107  * Sets the compare function for the interactive search capabilities; note
14108  * that somewhat like strcmp() returning 0 for equality
14109  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14110  **/
14111 void
14112 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14113                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14114                                      gpointer                    search_user_data,
14115                                      GDestroyNotify              search_destroy)
14116 {
14117   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14118   g_return_if_fail (search_equal_func != NULL);
14119
14120   if (tree_view->priv->search_destroy)
14121     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14122
14123   tree_view->priv->search_equal_func = search_equal_func;
14124   tree_view->priv->search_user_data = search_user_data;
14125   tree_view->priv->search_destroy = search_destroy;
14126   if (tree_view->priv->search_equal_func == NULL)
14127     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14128 }
14129
14130 /**
14131  * gtk_tree_view_get_search_entry:
14132  * @tree_view: A #GtkTreeView
14133  *
14134  * Returns the #GtkEntry which is currently in use as interactive search
14135  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14136  * will be returned.
14137  *
14138  * Return value: (transfer none): the entry currently in use as search entry.
14139  *
14140  * Since: 2.10
14141  */
14142 GtkEntry *
14143 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14144 {
14145   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14146
14147   if (tree_view->priv->search_custom_entry_set)
14148     return GTK_ENTRY (tree_view->priv->search_entry);
14149
14150   return NULL;
14151 }
14152
14153 /**
14154  * gtk_tree_view_set_search_entry:
14155  * @tree_view: A #GtkTreeView
14156  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14157  *
14158  * Sets the entry which the interactive search code will use for this
14159  * @tree_view.  This is useful when you want to provide a search entry
14160  * in our interface at all time at a fixed position.  Passing %NULL for
14161  * @entry will make the interactive search code use the built-in popup
14162  * entry again.
14163  *
14164  * Since: 2.10
14165  */
14166 void
14167 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14168                                 GtkEntry    *entry)
14169 {
14170   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14171   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14172
14173   if (tree_view->priv->search_custom_entry_set)
14174     {
14175       if (tree_view->priv->search_entry_changed_id)
14176         {
14177           g_signal_handler_disconnect (tree_view->priv->search_entry,
14178                                        tree_view->priv->search_entry_changed_id);
14179           tree_view->priv->search_entry_changed_id = 0;
14180         }
14181       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14182                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14183                                             tree_view);
14184
14185       g_object_unref (tree_view->priv->search_entry);
14186     }
14187   else if (tree_view->priv->search_window)
14188     {
14189       gtk_widget_destroy (tree_view->priv->search_window);
14190
14191       tree_view->priv->search_window = NULL;
14192     }
14193
14194   if (entry)
14195     {
14196       tree_view->priv->search_entry = g_object_ref (entry);
14197       tree_view->priv->search_custom_entry_set = TRUE;
14198
14199       if (tree_view->priv->search_entry_changed_id == 0)
14200         {
14201           tree_view->priv->search_entry_changed_id =
14202             g_signal_connect (tree_view->priv->search_entry, "changed",
14203                               G_CALLBACK (gtk_tree_view_search_init),
14204                               tree_view);
14205         }
14206       
14207         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14208                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14209                           tree_view);
14210
14211         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14212     }
14213   else
14214     {
14215       tree_view->priv->search_entry = NULL;
14216       tree_view->priv->search_custom_entry_set = FALSE;
14217     }
14218 }
14219
14220 /**
14221  * gtk_tree_view_set_search_position_func:
14222  * @tree_view: A #GtkTreeView
14223  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14224  *    to use the default search position function
14225  * @data: (allow-none): user data to pass to @func, or %NULL
14226  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14227  *
14228  * Sets the function to use when positioning the search dialog.
14229  *
14230  * Since: 2.10
14231  **/
14232 void
14233 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14234                                         GtkTreeViewSearchPositionFunc  func,
14235                                         gpointer                       user_data,
14236                                         GDestroyNotify                 destroy)
14237 {
14238   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14239
14240   if (tree_view->priv->search_position_destroy)
14241     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14242
14243   tree_view->priv->search_position_func = func;
14244   tree_view->priv->search_position_user_data = user_data;
14245   tree_view->priv->search_position_destroy = destroy;
14246   if (tree_view->priv->search_position_func == NULL)
14247     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14248 }
14249
14250 /**
14251  * gtk_tree_view_get_search_position_func:
14252  * @tree_view: A #GtkTreeView
14253  *
14254  * Returns the positioning function currently in use.
14255  *
14256  * Return value: the currently used function for positioning the search dialog.
14257  *
14258  * Since: 2.10
14259  */
14260 GtkTreeViewSearchPositionFunc
14261 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14262 {
14263   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14264
14265   return tree_view->priv->search_position_func;
14266 }
14267
14268
14269 static void
14270 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14271                                   GtkTreeView *tree_view,
14272                                   GdkDevice   *device)
14273 {
14274   if (tree_view->priv->disable_popdown)
14275     return;
14276
14277   if (tree_view->priv->search_entry_changed_id)
14278     {
14279       g_signal_handler_disconnect (tree_view->priv->search_entry,
14280                                    tree_view->priv->search_entry_changed_id);
14281       tree_view->priv->search_entry_changed_id = 0;
14282     }
14283   if (tree_view->priv->typeselect_flush_timeout)
14284     {
14285       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14286       tree_view->priv->typeselect_flush_timeout = 0;
14287     }
14288         
14289   if (gtk_widget_get_visible (search_dialog))
14290     {
14291       /* send focus-in event */
14292       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14293       gtk_widget_hide (search_dialog);
14294       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14295       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14296     }
14297 }
14298
14299 static void
14300 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14301                                     GtkWidget   *search_dialog,
14302                                     gpointer     user_data)
14303 {
14304   gint x, y;
14305   gint tree_x, tree_y;
14306   gint tree_width, tree_height;
14307   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14308   GdkScreen *screen = gdk_window_get_screen (tree_window);
14309   GtkRequisition requisition;
14310   gint monitor_num;
14311   GdkRectangle monitor;
14312
14313   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14314   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14315
14316   gtk_widget_realize (search_dialog);
14317
14318   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14319   tree_width = gdk_window_get_width (tree_window);
14320   tree_height = gdk_window_get_height (tree_window);
14321   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14322
14323   if (tree_x + tree_width > gdk_screen_get_width (screen))
14324     x = gdk_screen_get_width (screen) - requisition.width;
14325   else if (tree_x + tree_width - requisition.width < 0)
14326     x = 0;
14327   else
14328     x = tree_x + tree_width - requisition.width;
14329
14330   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14331     y = gdk_screen_get_height (screen) - requisition.height;
14332   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14333     y = 0;
14334   else
14335     y = tree_y + tree_height;
14336
14337   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14338 }
14339
14340 static void
14341 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14342                                       GtkMenu  *menu,
14343                                       gpointer  data)
14344 {
14345   GtkTreeView *tree_view = (GtkTreeView *)data;
14346
14347   tree_view->priv->disable_popdown = 1;
14348   g_signal_connect (menu, "hide",
14349                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14350 }
14351
14352 /* Because we're visible but offscreen, we just set a flag in the preedit
14353  * callback.
14354  */
14355 static void
14356 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14357                                       GtkTreeView  *tree_view)
14358 {
14359   tree_view->priv->imcontext_changed = 1;
14360   if (tree_view->priv->typeselect_flush_timeout)
14361     {
14362       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14363       tree_view->priv->typeselect_flush_timeout =
14364         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14365                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14366                        tree_view);
14367     }
14368
14369 }
14370
14371 static void
14372 gtk_tree_view_search_activate (GtkEntry    *entry,
14373                                GtkTreeView *tree_view)
14374 {
14375   GtkTreePath *path;
14376   GtkRBNode *node;
14377   GtkRBTree *tree;
14378
14379   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14380                                     tree_view,
14381                                     gtk_get_current_event_device ());
14382
14383   /* If we have a row selected and it's the cursor row, we activate
14384    * the row XXX */
14385   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14386     {
14387       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14388       
14389       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14390       
14391       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14392         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14393       
14394       gtk_tree_path_free (path);
14395     }
14396 }
14397
14398 static gboolean
14399 gtk_tree_view_real_search_enable_popdown (gpointer data)
14400 {
14401   GtkTreeView *tree_view = (GtkTreeView *)data;
14402
14403   tree_view->priv->disable_popdown = 0;
14404
14405   return FALSE;
14406 }
14407
14408 static void
14409 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14410                                      gpointer   data)
14411 {
14412   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14413 }
14414
14415 static gboolean
14416 gtk_tree_view_search_delete_event (GtkWidget *widget,
14417                                    GdkEventAny *event,
14418                                    GtkTreeView *tree_view)
14419 {
14420   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14421
14422   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14423
14424   return TRUE;
14425 }
14426
14427 static gboolean
14428 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14429                                          GdkEventButton *event,
14430                                          GtkTreeView *tree_view)
14431 {
14432   GdkDevice *keyb_device;
14433
14434   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14435
14436   keyb_device = gdk_device_get_associated_device (event->device);
14437   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14438
14439   if (event->window == tree_view->priv->bin_window)
14440     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14441
14442   return TRUE;
14443 }
14444
14445 static gboolean
14446 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14447                                    GdkEventScroll *event,
14448                                    GtkTreeView *tree_view)
14449 {
14450   gboolean retval = FALSE;
14451
14452   if (event->direction == GDK_SCROLL_UP)
14453     {
14454       gtk_tree_view_search_move (widget, tree_view, TRUE);
14455       retval = TRUE;
14456     }
14457   else if (event->direction == GDK_SCROLL_DOWN)
14458     {
14459       gtk_tree_view_search_move (widget, tree_view, FALSE);
14460       retval = TRUE;
14461     }
14462
14463   /* renew the flush timeout */
14464   if (retval && tree_view->priv->typeselect_flush_timeout
14465       && !tree_view->priv->search_custom_entry_set)
14466     {
14467       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14468       tree_view->priv->typeselect_flush_timeout =
14469         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14470                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14471                        tree_view);
14472     }
14473
14474   return retval;
14475 }
14476
14477 static gboolean
14478 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14479                                       GdkEventKey *event,
14480                                       GtkTreeView *tree_view)
14481 {
14482   gboolean retval = FALSE;
14483
14484   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14485   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14486
14487   /* close window and cancel the search */
14488   if (!tree_view->priv->search_custom_entry_set
14489       && (event->keyval == GDK_KEY_Escape ||
14490           event->keyval == GDK_KEY_Tab ||
14491             event->keyval == GDK_KEY_KP_Tab ||
14492             event->keyval == GDK_KEY_ISO_Left_Tab))
14493     {
14494       gtk_tree_view_search_dialog_hide (widget, tree_view,
14495                                         gdk_event_get_device ((GdkEvent *) event));
14496       return TRUE;
14497     }
14498
14499   /* select previous matching iter */
14500   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
14501     {
14502       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14503         gtk_widget_error_bell (widget);
14504
14505       retval = TRUE;
14506     }
14507
14508   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14509       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14510     {
14511       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14512         gtk_widget_error_bell (widget);
14513
14514       retval = TRUE;
14515     }
14516
14517   /* select next matching iter */
14518   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
14519     {
14520       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14521         gtk_widget_error_bell (widget);
14522
14523       retval = TRUE;
14524     }
14525
14526   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14527       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14528     {
14529       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14530         gtk_widget_error_bell (widget);
14531
14532       retval = TRUE;
14533     }
14534
14535   /* renew the flush timeout */
14536   if (retval && tree_view->priv->typeselect_flush_timeout
14537       && !tree_view->priv->search_custom_entry_set)
14538     {
14539       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14540       tree_view->priv->typeselect_flush_timeout =
14541         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14542                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14543                        tree_view);
14544     }
14545
14546   return retval;
14547 }
14548
14549 /*  this function returns FALSE if there is a search string but
14550  *  nothing was found, and TRUE otherwise.
14551  */
14552 static gboolean
14553 gtk_tree_view_search_move (GtkWidget   *window,
14554                            GtkTreeView *tree_view,
14555                            gboolean     up)
14556 {
14557   gboolean ret;
14558   gint len;
14559   gint count = 0;
14560   const gchar *text;
14561   GtkTreeIter iter;
14562   GtkTreeModel *model;
14563   GtkTreeSelection *selection;
14564
14565   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14566
14567   g_return_val_if_fail (text != NULL, FALSE);
14568
14569   len = strlen (text);
14570
14571   if (up && tree_view->priv->selected_iter == 1)
14572     return strlen (text) < 1;
14573
14574   len = strlen (text);
14575
14576   if (len < 1)
14577     return TRUE;
14578
14579   model = gtk_tree_view_get_model (tree_view);
14580   selection = gtk_tree_view_get_selection (tree_view);
14581
14582   /* search */
14583   gtk_tree_selection_unselect_all (selection);
14584   if (!gtk_tree_model_get_iter_first (model, &iter))
14585     return TRUE;
14586
14587   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14588                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14589
14590   if (ret)
14591     {
14592       /* found */
14593       tree_view->priv->selected_iter += up?(-1):(1);
14594       return TRUE;
14595     }
14596   else
14597     {
14598       /* return to old iter */
14599       count = 0;
14600       gtk_tree_model_get_iter_first (model, &iter);
14601       gtk_tree_view_search_iter (model, selection,
14602                                  &iter, text,
14603                                  &count, tree_view->priv->selected_iter);
14604       return FALSE;
14605     }
14606 }
14607
14608 static gboolean
14609 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14610                                  gint          column,
14611                                  const gchar  *key,
14612                                  GtkTreeIter  *iter,
14613                                  gpointer      search_data)
14614 {
14615   gboolean retval = TRUE;
14616   const gchar *str;
14617   gchar *normalized_string;
14618   gchar *normalized_key;
14619   gchar *case_normalized_string = NULL;
14620   gchar *case_normalized_key = NULL;
14621   GValue value = {0,};
14622   GValue transformed = {0,};
14623
14624   gtk_tree_model_get_value (model, iter, column, &value);
14625
14626   g_value_init (&transformed, G_TYPE_STRING);
14627
14628   if (!g_value_transform (&value, &transformed))
14629     {
14630       g_value_unset (&value);
14631       return TRUE;
14632     }
14633
14634   g_value_unset (&value);
14635
14636   str = g_value_get_string (&transformed);
14637   if (!str)
14638     {
14639       g_value_unset (&transformed);
14640       return TRUE;
14641     }
14642
14643   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14644   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14645
14646   if (normalized_string && normalized_key)
14647     {
14648       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14649       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14650
14651       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14652         retval = FALSE;
14653     }
14654
14655   g_value_unset (&transformed);
14656   g_free (normalized_key);
14657   g_free (normalized_string);
14658   g_free (case_normalized_key);
14659   g_free (case_normalized_string);
14660
14661   return retval;
14662 }
14663
14664 static gboolean
14665 gtk_tree_view_search_iter (GtkTreeModel     *model,
14666                            GtkTreeSelection *selection,
14667                            GtkTreeIter      *iter,
14668                            const gchar      *text,
14669                            gint             *count,
14670                            gint              n)
14671 {
14672   GtkRBTree *tree = NULL;
14673   GtkRBNode *node = NULL;
14674   GtkTreePath *path;
14675
14676   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14677
14678   path = gtk_tree_model_get_path (model, iter);
14679   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14680
14681   do
14682     {
14683       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14684         {
14685           (*count)++;
14686           if (*count == n)
14687             {
14688               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14689                                             TRUE, 0.5, 0.0);
14690               gtk_tree_selection_select_iter (selection, iter);
14691               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14692
14693               if (path)
14694                 gtk_tree_path_free (path);
14695
14696               return TRUE;
14697             }
14698         }
14699
14700       if (node->children)
14701         {
14702           gboolean has_child;
14703           GtkTreeIter tmp;
14704
14705           tree = node->children;
14706           node = tree->root;
14707
14708           while (node->left != tree->nil)
14709             node = node->left;
14710
14711           tmp = *iter;
14712           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14713           gtk_tree_path_down (path);
14714
14715           /* sanity check */
14716           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14717         }
14718       else
14719         {
14720           gboolean done = FALSE;
14721
14722           do
14723             {
14724               node = _gtk_rbtree_next (tree, node);
14725
14726               if (node)
14727                 {
14728                   gboolean has_next;
14729
14730                   has_next = gtk_tree_model_iter_next (model, iter);
14731
14732                   done = TRUE;
14733                   gtk_tree_path_next (path);
14734
14735                   /* sanity check */
14736                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14737                 }
14738               else
14739                 {
14740                   gboolean has_parent;
14741                   GtkTreeIter tmp_iter = *iter;
14742
14743                   node = tree->parent_node;
14744                   tree = tree->parent_tree;
14745
14746                   if (!tree)
14747                     {
14748                       if (path)
14749                         gtk_tree_path_free (path);
14750
14751                       /* we've run out of tree, done with this func */
14752                       return FALSE;
14753                     }
14754
14755                   has_parent = gtk_tree_model_iter_parent (model,
14756                                                            iter,
14757                                                            &tmp_iter);
14758                   gtk_tree_path_up (path);
14759
14760                   /* sanity check */
14761                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14762                 }
14763             }
14764           while (!done);
14765         }
14766     }
14767   while (1);
14768
14769   return FALSE;
14770 }
14771
14772 static void
14773 gtk_tree_view_search_init (GtkWidget   *entry,
14774                            GtkTreeView *tree_view)
14775 {
14776   gint ret;
14777   gint count = 0;
14778   const gchar *text;
14779   GtkTreeIter iter;
14780   GtkTreeModel *model;
14781   GtkTreeSelection *selection;
14782
14783   g_return_if_fail (GTK_IS_ENTRY (entry));
14784   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14785
14786   text = gtk_entry_get_text (GTK_ENTRY (entry));
14787
14788   model = gtk_tree_view_get_model (tree_view);
14789   selection = gtk_tree_view_get_selection (tree_view);
14790
14791   /* search */
14792   gtk_tree_selection_unselect_all (selection);
14793   if (tree_view->priv->typeselect_flush_timeout
14794       && !tree_view->priv->search_custom_entry_set)
14795     {
14796       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14797       tree_view->priv->typeselect_flush_timeout =
14798         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14799                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14800                        tree_view);
14801     }
14802
14803   if (*text == '\0')
14804     return;
14805
14806   if (!gtk_tree_model_get_iter_first (model, &iter))
14807     return;
14808
14809   ret = gtk_tree_view_search_iter (model, selection,
14810                                    &iter, text,
14811                                    &count, 1);
14812
14813   if (ret)
14814     tree_view->priv->selected_iter = 1;
14815 }
14816
14817 static void
14818 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14819                              GtkTreeView     *tree_view)
14820 {
14821   if (tree_view->priv->edited_column == NULL)
14822     return;
14823
14824   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14825   tree_view->priv->edited_column = NULL;
14826
14827   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
14828     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14829
14830   g_signal_handlers_disconnect_by_func (cell_editable,
14831                                         gtk_tree_view_remove_widget,
14832                                         tree_view);
14833
14834   gtk_container_remove (GTK_CONTAINER (tree_view),
14835                         GTK_WIDGET (cell_editable));  
14836
14837   /* FIXME should only redraw a single node */
14838   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14839 }
14840
14841 static gboolean
14842 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14843                              GtkTreePath *cursor_path)
14844 {
14845   GtkTreeIter iter;
14846   GdkRectangle background_area;
14847   GdkRectangle cell_area;
14848   GtkCellEditable *editable_widget = NULL;
14849   gchar *path_string;
14850   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14851   gint retval = FALSE;
14852   GtkRBTree *cursor_tree;
14853   GtkRBNode *cursor_node;
14854
14855   g_assert (tree_view->priv->focus_column);
14856
14857   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
14858     return FALSE;
14859
14860   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14861       cursor_node == NULL)
14862     return FALSE;
14863
14864   path_string = gtk_tree_path_to_string (cursor_path);
14865   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14866
14867   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14868
14869   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14870                                            tree_view->priv->model,
14871                                            &iter,
14872                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14873                                            cursor_node->children?TRUE:FALSE);
14874   gtk_tree_view_get_background_area (tree_view,
14875                                      cursor_path,
14876                                      tree_view->priv->focus_column,
14877                                      &background_area);
14878   gtk_tree_view_get_cell_area (tree_view,
14879                                cursor_path,
14880                                tree_view->priv->focus_column,
14881                                &cell_area);
14882
14883   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14884                                         &editable_widget,
14885                                         NULL,
14886                                         path_string,
14887                                         &background_area,
14888                                         &cell_area,
14889                                         flags))
14890     {
14891       retval = TRUE;
14892       if (editable_widget != NULL)
14893         {
14894           gint left, right;
14895           GdkRectangle area;
14896           GtkCellRenderer *cell;
14897
14898           area = cell_area;
14899           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14900
14901           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14902
14903           area.x += left;
14904           area.width -= right + left;
14905
14906           gtk_tree_view_real_start_editing (tree_view,
14907                                             tree_view->priv->focus_column,
14908                                             cursor_path,
14909                                             editable_widget,
14910                                             &area,
14911                                             NULL,
14912                                             flags);
14913         }
14914
14915     }
14916   g_free (path_string);
14917   return retval;
14918 }
14919
14920 static void
14921 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14922                                   GtkTreeViewColumn *column,
14923                                   GtkTreePath       *path,
14924                                   GtkCellEditable   *cell_editable,
14925                                   GdkRectangle      *cell_area,
14926                                   GdkEvent          *event,
14927                                   guint              flags)
14928 {
14929   gint pre_val = tree_view->priv->vadjustment->value;
14930   GtkRequisition requisition;
14931
14932   tree_view->priv->edited_column = column;
14933   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14934
14935   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14936   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14937
14938   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
14939                                  &requisition, NULL);
14940
14941   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14942
14943   if (requisition.height < cell_area->height)
14944     {
14945       gint diff = cell_area->height - requisition.height;
14946       gtk_tree_view_put (tree_view,
14947                          GTK_WIDGET (cell_editable),
14948                          cell_area->x, cell_area->y + diff/2,
14949                          cell_area->width, requisition.height);
14950     }
14951   else
14952     {
14953       gtk_tree_view_put (tree_view,
14954                          GTK_WIDGET (cell_editable),
14955                          cell_area->x, cell_area->y,
14956                          cell_area->width, cell_area->height);
14957     }
14958
14959   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14960                                    (GdkEvent *)event);
14961
14962   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14963   g_signal_connect (cell_editable, "remove-widget",
14964                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14965 }
14966
14967 static void
14968 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14969                             gboolean     cancel_editing)
14970 {
14971   GtkTreeViewColumn *column;
14972   GtkCellRenderer *cell;
14973
14974   if (tree_view->priv->edited_column == NULL)
14975     return;
14976
14977   /*
14978    * This is very evil. We need to do this, because
14979    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14980    * later on. If gtk_tree_view_row_changed notices
14981    * tree_view->priv->edited_column != NULL, it'll call
14982    * gtk_tree_view_stop_editing again. Bad things will happen then.
14983    *
14984    * Please read that again if you intend to modify anything here.
14985    */
14986
14987   column = tree_view->priv->edited_column;
14988   tree_view->priv->edited_column = NULL;
14989
14990   cell = _gtk_tree_view_column_get_edited_cell (column);
14991   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14992
14993   if (!cancel_editing)
14994     gtk_cell_editable_editing_done (column->editable_widget);
14995
14996   tree_view->priv->edited_column = column;
14997
14998   gtk_cell_editable_remove_widget (column->editable_widget);
14999 }
15000
15001
15002 /**
15003  * gtk_tree_view_set_hover_selection:
15004  * @tree_view: a #GtkTreeView
15005  * @hover: %TRUE to enable hover selection mode
15006  *
15007  * Enables of disables the hover selection mode of @tree_view.
15008  * Hover selection makes the selected row follow the pointer.
15009  * Currently, this works only for the selection modes 
15010  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15011  * 
15012  * Since: 2.6
15013  **/
15014 void     
15015 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15016                                    gboolean     hover)
15017 {
15018   hover = hover != FALSE;
15019
15020   if (hover != tree_view->priv->hover_selection)
15021     {
15022       tree_view->priv->hover_selection = hover;
15023
15024       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15025     }
15026 }
15027
15028 /**
15029  * gtk_tree_view_get_hover_selection:
15030  * @tree_view: a #GtkTreeView
15031  * 
15032  * Returns whether hover selection mode is turned on for @tree_view.
15033  * 
15034  * Return value: %TRUE if @tree_view is in hover selection mode
15035  *
15036  * Since: 2.6 
15037  **/
15038 gboolean 
15039 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15040 {
15041   return tree_view->priv->hover_selection;
15042 }
15043
15044 /**
15045  * gtk_tree_view_set_hover_expand:
15046  * @tree_view: a #GtkTreeView
15047  * @expand: %TRUE to enable hover selection mode
15048  *
15049  * Enables of disables the hover expansion mode of @tree_view.
15050  * Hover expansion makes rows expand or collapse if the pointer 
15051  * moves over them.
15052  * 
15053  * Since: 2.6
15054  **/
15055 void     
15056 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15057                                 gboolean     expand)
15058 {
15059   expand = expand != FALSE;
15060
15061   if (expand != tree_view->priv->hover_expand)
15062     {
15063       tree_view->priv->hover_expand = expand;
15064
15065       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15066     }
15067 }
15068
15069 /**
15070  * gtk_tree_view_get_hover_expand:
15071  * @tree_view: a #GtkTreeView
15072  * 
15073  * Returns whether hover expansion mode is turned on for @tree_view.
15074  * 
15075  * Return value: %TRUE if @tree_view is in hover expansion mode
15076  *
15077  * Since: 2.6 
15078  **/
15079 gboolean 
15080 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15081 {
15082   return tree_view->priv->hover_expand;
15083 }
15084
15085 /**
15086  * gtk_tree_view_set_rubber_banding:
15087  * @tree_view: a #GtkTreeView
15088  * @enable: %TRUE to enable rubber banding
15089  *
15090  * Enables or disables rubber banding in @tree_view.  If the selection mode
15091  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15092  * multiple rows by dragging the mouse.
15093  * 
15094  * Since: 2.10
15095  **/
15096 void
15097 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15098                                   gboolean     enable)
15099 {
15100   enable = enable != FALSE;
15101
15102   if (enable != tree_view->priv->rubber_banding_enable)
15103     {
15104       tree_view->priv->rubber_banding_enable = enable;
15105
15106       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15107     }
15108 }
15109
15110 /**
15111  * gtk_tree_view_get_rubber_banding:
15112  * @tree_view: a #GtkTreeView
15113  * 
15114  * Returns whether rubber banding is turned on for @tree_view.  If the
15115  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15116  * user to select multiple rows by dragging the mouse.
15117  * 
15118  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15119  *
15120  * Since: 2.10
15121  **/
15122 gboolean
15123 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15124 {
15125   return tree_view->priv->rubber_banding_enable;
15126 }
15127
15128 /**
15129  * gtk_tree_view_is_rubber_banding_active:
15130  * @tree_view: a #GtkTreeView
15131  * 
15132  * Returns whether a rubber banding operation is currently being done
15133  * in @tree_view.
15134  *
15135  * Return value: %TRUE if a rubber banding operation is currently being
15136  * done in @tree_view.
15137  *
15138  * Since: 2.12
15139  **/
15140 gboolean
15141 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15142 {
15143   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15144
15145   if (tree_view->priv->rubber_banding_enable
15146       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15147     return TRUE;
15148
15149   return FALSE;
15150 }
15151
15152 /**
15153  * gtk_tree_view_get_row_separator_func:
15154  * @tree_view: a #GtkTreeView
15155  * 
15156  * Returns the current row separator function.
15157  * 
15158  * Return value: the current row separator function.
15159  *
15160  * Since: 2.6
15161  **/
15162 GtkTreeViewRowSeparatorFunc 
15163 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15164 {
15165   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15166
15167   return tree_view->priv->row_separator_func;
15168 }
15169
15170 /**
15171  * gtk_tree_view_set_row_separator_func:
15172  * @tree_view: a #GtkTreeView
15173  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15174  * @data: (allow-none): user data to pass to @func, or %NULL
15175  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15176  * 
15177  * Sets the row separator function, which is used to determine
15178  * whether a row should be drawn as a separator. If the row separator
15179  * function is %NULL, no separators are drawn. This is the default value.
15180  *
15181  * Since: 2.6
15182  **/
15183 void
15184 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15185                                       GtkTreeViewRowSeparatorFunc  func,
15186                                       gpointer                     data,
15187                                       GDestroyNotify               destroy)
15188 {
15189   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15190
15191   if (tree_view->priv->row_separator_destroy)
15192     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15193
15194   tree_view->priv->row_separator_func = func;
15195   tree_view->priv->row_separator_data = data;
15196   tree_view->priv->row_separator_destroy = destroy;
15197
15198   /* Have the tree recalculate heights */
15199   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15200   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15201 }
15202
15203   
15204 static void
15205 gtk_tree_view_grab_notify (GtkWidget *widget,
15206                            gboolean   was_grabbed)
15207 {
15208   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15209
15210   tree_view->priv->in_grab = !was_grabbed;
15211
15212   if (!was_grabbed)
15213     {
15214       tree_view->priv->pressed_button = -1;
15215
15216       if (tree_view->priv->rubber_band_status)
15217         gtk_tree_view_stop_rubber_band (tree_view);
15218     }
15219 }
15220
15221 static void
15222 gtk_tree_view_state_changed (GtkWidget      *widget,
15223                              GtkStateType    previous_state)
15224 {
15225   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15226
15227   if (gtk_widget_get_realized (widget))
15228     {
15229       gdk_window_set_background (tree_view->priv->bin_window,
15230                                  &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
15231     }
15232
15233   gtk_widget_queue_draw (widget);
15234 }
15235
15236 /**
15237  * gtk_tree_view_get_grid_lines:
15238  * @tree_view: a #GtkTreeView
15239  *
15240  * Returns which grid lines are enabled in @tree_view.
15241  *
15242  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15243  * are enabled.
15244  *
15245  * Since: 2.10
15246  */
15247 GtkTreeViewGridLines
15248 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15249 {
15250   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15251
15252   return tree_view->priv->grid_lines;
15253 }
15254
15255 /**
15256  * gtk_tree_view_set_grid_lines:
15257  * @tree_view: a #GtkTreeView
15258  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15259  * enable.
15260  *
15261  * Sets which grid lines to draw in @tree_view.
15262  *
15263  * Since: 2.10
15264  */
15265 void
15266 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15267                               GtkTreeViewGridLines   grid_lines)
15268 {
15269   GtkTreeViewPrivate *priv;
15270   GtkWidget *widget;
15271   GtkTreeViewGridLines old_grid_lines;
15272
15273   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15274
15275   priv = tree_view->priv;
15276   widget = GTK_WIDGET (tree_view);
15277
15278   old_grid_lines = priv->grid_lines;
15279   priv->grid_lines = grid_lines;
15280   
15281   if (gtk_widget_get_realized (widget))
15282     {
15283       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15284           priv->grid_line_width)
15285         {
15286           priv->grid_line_width = 0;
15287         }
15288       
15289       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15290           !priv->grid_line_width)
15291         {
15292           gint8 *dash_list;
15293
15294           gtk_widget_style_get (widget,
15295                                 "grid-line-width", &priv->grid_line_width,
15296                                 "grid-line-pattern", (gchar *)&dash_list,
15297                                 NULL);
15298       
15299           if (dash_list)
15300             {
15301               priv->grid_line_dashes[0] = dash_list[0];
15302               if (dash_list[0])
15303                 priv->grid_line_dashes[1] = dash_list[1];
15304               
15305               g_free (dash_list);
15306             }
15307           else
15308             {
15309               priv->grid_line_dashes[0] = 1;
15310               priv->grid_line_dashes[1] = 1;
15311             }
15312         }      
15313     }
15314
15315   if (old_grid_lines != grid_lines)
15316     {
15317       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15318       
15319       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15320     }
15321 }
15322
15323 /**
15324  * gtk_tree_view_get_enable_tree_lines:
15325  * @tree_view: a #GtkTreeView.
15326  *
15327  * Returns whether or not tree lines are drawn in @tree_view.
15328  *
15329  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15330  * otherwise.
15331  *
15332  * Since: 2.10
15333  */
15334 gboolean
15335 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15336 {
15337   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15338
15339   return tree_view->priv->tree_lines_enabled;
15340 }
15341
15342 /**
15343  * gtk_tree_view_set_enable_tree_lines:
15344  * @tree_view: a #GtkTreeView
15345  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15346  *
15347  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15348  * This does not have any visible effects for lists.
15349  *
15350  * Since: 2.10
15351  */
15352 void
15353 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15354                                      gboolean     enabled)
15355 {
15356   GtkTreeViewPrivate *priv;
15357   GtkWidget *widget;
15358   gboolean was_enabled;
15359
15360   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15361
15362   enabled = enabled != FALSE;
15363
15364   priv = tree_view->priv;
15365   widget = GTK_WIDGET (tree_view);
15366
15367   was_enabled = priv->tree_lines_enabled;
15368
15369   priv->tree_lines_enabled = enabled;
15370
15371   if (gtk_widget_get_realized (widget))
15372     {
15373       if (!enabled && priv->tree_line_width)
15374         {
15375           priv->tree_line_width = 0;
15376         }
15377       
15378       if (enabled && !priv->tree_line_width)
15379         {
15380           gint8 *dash_list;
15381           gtk_widget_style_get (widget,
15382                                 "tree-line-width", &priv->tree_line_width,
15383                                 "tree-line-pattern", (gchar *)&dash_list,
15384                                 NULL);
15385           
15386           if (dash_list)
15387             {
15388               priv->tree_line_dashes[0] = dash_list[0];
15389               if (dash_list[0])
15390                 priv->tree_line_dashes[1] = dash_list[1];
15391               
15392               g_free (dash_list);
15393             }
15394           else
15395             {
15396               priv->tree_line_dashes[0] = 1;
15397               priv->tree_line_dashes[1] = 1;
15398             }
15399         }
15400     }
15401
15402   if (was_enabled != enabled)
15403     {
15404       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15405
15406       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15407     }
15408 }
15409
15410
15411 /**
15412  * gtk_tree_view_set_show_expanders:
15413  * @tree_view: a #GtkTreeView
15414  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15415  *
15416  * Sets whether to draw and enable expanders and indent child rows in
15417  * @tree_view.  When disabled there will be no expanders visible in trees
15418  * and there will be no way to expand and collapse rows by default.  Also
15419  * note that hiding the expanders will disable the default indentation.  You
15420  * can set a custom indentation in this case using
15421  * gtk_tree_view_set_level_indentation().
15422  * This does not have any visible effects for lists.
15423  *
15424  * Since: 2.12
15425  */
15426 void
15427 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15428                                   gboolean     enabled)
15429 {
15430   gboolean was_enabled;
15431
15432   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15433
15434   enabled = enabled != FALSE;
15435   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15436
15437   if (enabled)
15438     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15439   else
15440     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15441
15442   if (enabled != was_enabled)
15443     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15444 }
15445
15446 /**
15447  * gtk_tree_view_get_show_expanders:
15448  * @tree_view: a #GtkTreeView.
15449  *
15450  * Returns whether or not expanders are drawn in @tree_view.
15451  *
15452  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15453  * otherwise.
15454  *
15455  * Since: 2.12
15456  */
15457 gboolean
15458 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15459 {
15460   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15461
15462   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15463 }
15464
15465 /**
15466  * gtk_tree_view_set_level_indentation:
15467  * @tree_view: a #GtkTreeView
15468  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15469  *
15470  * Sets the amount of extra indentation for child levels to use in @tree_view
15471  * in addition to the default indentation.  The value should be specified in
15472  * pixels, a value of 0 disables this feature and in this case only the default
15473  * indentation will be used.
15474  * This does not have any visible effects for lists.
15475  *
15476  * Since: 2.12
15477  */
15478 void
15479 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15480                                      gint         indentation)
15481 {
15482   tree_view->priv->level_indentation = indentation;
15483
15484   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15485 }
15486
15487 /**
15488  * gtk_tree_view_get_level_indentation:
15489  * @tree_view: a #GtkTreeView.
15490  *
15491  * Returns the amount, in pixels, of extra indentation for child levels
15492  * in @tree_view.
15493  *
15494  * Return value: the amount of extra indentation for child levels in
15495  * @tree_view.  A return value of 0 means that this feature is disabled.
15496  *
15497  * Since: 2.12
15498  */
15499 gint
15500 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15501 {
15502   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15503
15504   return tree_view->priv->level_indentation;
15505 }
15506
15507 /**
15508  * gtk_tree_view_set_tooltip_row:
15509  * @tree_view: a #GtkTreeView
15510  * @tooltip: a #GtkTooltip
15511  * @path: a #GtkTreePath
15512  *
15513  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15514  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15515  * See also gtk_tooltip_set_tip_area().
15516  *
15517  * Since: 2.12
15518  */
15519 void
15520 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15521                                GtkTooltip  *tooltip,
15522                                GtkTreePath *path)
15523 {
15524   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15525   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15526
15527   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15528 }
15529
15530 /**
15531  * gtk_tree_view_set_tooltip_cell:
15532  * @tree_view: a #GtkTreeView
15533  * @tooltip: a #GtkTooltip
15534  * @path: (allow-none): a #GtkTreePath or %NULL
15535  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
15536  * @cell: (allow-none): a #GtkCellRenderer or %NULL
15537  *
15538  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15539  * in common.  For example if @path is %NULL and @column is set, the tip
15540  * area will be set to the full area covered by @column.  See also
15541  * gtk_tooltip_set_tip_area().
15542  *
15543  * Note that if @path is not specified and @cell is set and part of a column
15544  * containing the expander, the tooltip might not show and hide at the correct
15545  * position.  In such cases @path must be set to the current node under the
15546  * mouse cursor for this function to operate correctly.
15547  *
15548  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15549  *
15550  * Since: 2.12
15551  */
15552 void
15553 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15554                                 GtkTooltip        *tooltip,
15555                                 GtkTreePath       *path,
15556                                 GtkTreeViewColumn *column,
15557                                 GtkCellRenderer   *cell)
15558 {
15559   GtkAllocation allocation;
15560   GdkRectangle rect;
15561
15562   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15563   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15564   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15565   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15566
15567   /* Determine x values. */
15568   if (column && cell)
15569     {
15570       GdkRectangle tmp;
15571       gint start, width;
15572
15573       /* We always pass in path here, whether it is NULL or not.
15574        * For cells in expander columns path must be specified so that
15575        * we can correctly account for the indentation.  This also means
15576        * that the tooltip is constrained vertically by the "Determine y
15577        * values" code below; this is not a real problem since cells actually
15578        * don't stretch vertically in constrast to columns.
15579        */
15580       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15581       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15582
15583       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15584                                                          tmp.x + start, 0,
15585                                                          &rect.x, NULL);
15586       rect.width = width;
15587     }
15588   else if (column)
15589     {
15590       GdkRectangle tmp;
15591
15592       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15593       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15594                                                          tmp.x, 0,
15595                                                          &rect.x, NULL);
15596       rect.width = tmp.width;
15597     }
15598   else
15599     {
15600       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
15601       rect.x = 0;
15602       rect.width = allocation.width;
15603     }
15604
15605   /* Determine y values. */
15606   if (path)
15607     {
15608       GdkRectangle tmp;
15609
15610       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15611       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15612                                                          0, tmp.y,
15613                                                          NULL, &rect.y);
15614       rect.height = tmp.height;
15615     }
15616   else
15617     {
15618       rect.y = 0;
15619       rect.height = tree_view->priv->vadjustment->page_size;
15620     }
15621
15622   gtk_tooltip_set_tip_area (tooltip, &rect);
15623 }
15624
15625 /**
15626  * gtk_tree_view_get_tooltip_context:
15627  * @tree_view: a #GtkTreeView
15628  * @x: the x coordinate (relative to widget coordinates)
15629  * @y: the y coordinate (relative to widget coordinates)
15630  * @keyboard_tip: whether this is a keyboard tooltip or not
15631  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
15632  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
15633  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
15634  *
15635  * This function is supposed to be used in a #GtkWidget::query-tooltip
15636  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15637  * which are received in the signal handler, should be passed to this
15638  * function without modification.
15639  *
15640  * The return value indicates whether there is a tree view row at the given
15641  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15642  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15643  * @model, @path and @iter which have been provided will be set to point to
15644  * that row and the corresponding model.  @x and @y will always be converted
15645  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15646  *
15647  * Return value: whether or not the given tooltip context points to a row.
15648  *
15649  * Since: 2.12
15650  */
15651 gboolean
15652 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15653                                    gint          *x,
15654                                    gint          *y,
15655                                    gboolean       keyboard_tip,
15656                                    GtkTreeModel **model,
15657                                    GtkTreePath  **path,
15658                                    GtkTreeIter   *iter)
15659 {
15660   GtkTreePath *tmppath = NULL;
15661
15662   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15663   g_return_val_if_fail (x != NULL, FALSE);
15664   g_return_val_if_fail (y != NULL, FALSE);
15665
15666   if (keyboard_tip)
15667     {
15668       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15669
15670       if (!tmppath)
15671         return FALSE;
15672     }
15673   else
15674     {
15675       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15676                                                          x, y);
15677
15678       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15679                                           &tmppath, NULL, NULL, NULL))
15680         return FALSE;
15681     }
15682
15683   if (model)
15684     *model = gtk_tree_view_get_model (tree_view);
15685
15686   if (iter)
15687     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15688                              iter, tmppath);
15689
15690   if (path)
15691     *path = tmppath;
15692   else
15693     gtk_tree_path_free (tmppath);
15694
15695   return TRUE;
15696 }
15697
15698 static gboolean
15699 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15700                                     gint        x,
15701                                     gint        y,
15702                                     gboolean    keyboard_tip,
15703                                     GtkTooltip *tooltip,
15704                                     gpointer    data)
15705 {
15706   GValue value = { 0, };
15707   GValue transformed = { 0, };
15708   GtkTreeIter iter;
15709   GtkTreePath *path;
15710   GtkTreeModel *model;
15711   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15712
15713   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15714                                           &x, &y,
15715                                           keyboard_tip,
15716                                           &model, &path, &iter))
15717     return FALSE;
15718
15719   gtk_tree_model_get_value (model, &iter,
15720                             tree_view->priv->tooltip_column, &value);
15721
15722   g_value_init (&transformed, G_TYPE_STRING);
15723
15724   if (!g_value_transform (&value, &transformed))
15725     {
15726       g_value_unset (&value);
15727       gtk_tree_path_free (path);
15728
15729       return FALSE;
15730     }
15731
15732   g_value_unset (&value);
15733
15734   if (!g_value_get_string (&transformed))
15735     {
15736       g_value_unset (&transformed);
15737       gtk_tree_path_free (path);
15738
15739       return FALSE;
15740     }
15741
15742   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15743   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15744
15745   gtk_tree_path_free (path);
15746   g_value_unset (&transformed);
15747
15748   return TRUE;
15749 }
15750
15751 /**
15752  * gtk_tree_view_set_tooltip_column:
15753  * @tree_view: a #GtkTreeView
15754  * @column: an integer, which is a valid column number for @tree_view's model
15755  *
15756  * If you only plan to have simple (text-only) tooltips on full rows, you
15757  * can use this function to have #GtkTreeView handle these automatically
15758  * for you. @column should be set to the column in @tree_view's model
15759  * containing the tooltip texts, or -1 to disable this feature.
15760  *
15761  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15762  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15763  *
15764  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15765  * so &amp;, &lt;, etc have to be escaped in the text.
15766  *
15767  * Since: 2.12
15768  */
15769 void
15770 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15771                                   gint         column)
15772 {
15773   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15774
15775   if (column == tree_view->priv->tooltip_column)
15776     return;
15777
15778   if (column == -1)
15779     {
15780       g_signal_handlers_disconnect_by_func (tree_view,
15781                                             gtk_tree_view_set_tooltip_query_cb,
15782                                             NULL);
15783       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15784     }
15785   else
15786     {
15787       if (tree_view->priv->tooltip_column == -1)
15788         {
15789           g_signal_connect (tree_view, "query-tooltip",
15790                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15791           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15792         }
15793     }
15794
15795   tree_view->priv->tooltip_column = column;
15796   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15797 }
15798
15799 /**
15800  * gtk_tree_view_get_tooltip_column:
15801  * @tree_view: a #GtkTreeView
15802  *
15803  * Returns the column of @tree_view's model which is being used for
15804  * displaying tooltips on @tree_view's rows.
15805  *
15806  * Return value: the index of the tooltip column that is currently being
15807  * used, or -1 if this is disabled.
15808  *
15809  * Since: 2.12
15810  */
15811 gint
15812 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15813 {
15814   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15815
15816   return tree_view->priv->tooltip_column;
15817 }