]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Update about dialog design to not use a swarm of dialogs
[~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 #include "gtkentryprivate.h"
51
52
53 /**
54  * SECTION:gtktreeview
55  * @Short_description: A widget for displaying both trees and lists
56  * @Title: GtkTreeView
57  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
58  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
59  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
60  *   #GtkCellRendererText, #GtkCellRendererToggle
61  *
62  * Widget that displays any object that implements the #GtkTreeModel interface.
63  *
64  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
65  * overview</link> for an overview of all the objects and data types related
66  * to the tree widget and how they work together.
67  *
68  * Several different coordinate systems are exposed in the GtkTreeView API.
69  * These are:
70  *
71  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
72  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
73  * <varlistentry><term>Widget coordinates</term>
74  * <listitem>
75  * <para>
76  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
77  * </para>
78  * </listitem>
79  * </varlistentry>
80  * <varlistentry><term>Bin window coordinates</term>
81  * <listitem>
82  * <para>
83  * Coordinates relative to the window that GtkTreeView renders to.
84  * </para>
85  * </listitem>
86  * </varlistentry>
87  * <varlistentry><term>Tree coordinates</term>
88  * <listitem>
89  * <para>
90  * Coordinates relative to the entire scrollable area of GtkTreeView. These
91  * coordinates start at (0, 0) for row 0 of the tree.
92  * </para>
93  * </listitem>
94  * </varlistentry>
95  * </variablelist>
96  *
97  * Several functions are available for converting between the different
98  * coordinate systems.  The most common translations are between widget and bin
99  * window coordinates and between bin window and tree coordinates. For the
100  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
101  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
102  * (and vice versa).
103  *
104  * <refsect2 id="GtkTreeView-BUILDER-UI">
105  * <title>GtkTreeView as GtkBuildable</title>
106  * The GtkTreeView implementation of the GtkBuildable interface accepts
107  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
108  * internal #GtkTreeSelection in UI definitions.
109  * <example>
110  * <title>A UI definition fragment with GtkTreeView</title>
111  * <programlisting><![CDATA[
112  * <object class="GtkTreeView" id="treeview">
113  *   <property name="model">liststore1</property>
114  *   <child>
115  *     <object class="GtkTreeViewColumn" id="test-column">
116  *       <property name="title">Test</property>
117  *       <child>
118  *         <object class="GtkCellRendererText" id="test-renderer"/>
119  *         <attributes>
120  *           <attribute name="text">1</attribute>
121  *         </attributes>
122  *       </child>
123  *     </object>
124  *   </child>
125  *   <child internal-child="selection">
126  *     <object class="GtkTreeSelection" id="selection">
127  *       <signal name="changed" handler="on_treeview_selection_changed"/>
128  *     </object>
129  *   </child>
130  * </object>
131  * ]]></programlisting>
132  * </example>
133  * </refsect2>
134  */
135
136
137 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
138 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
139 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
140 #define SCROLL_EDGE_SIZE 15
141 #define EXPANDER_EXTRA_PADDING 4
142 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
143 #define AUTO_EXPAND_TIMEOUT 500
144
145 /* The "background" areas of all rows/cells add up to cover the entire tree.
146  * The background includes all inter-row and inter-cell spacing.
147  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
148  * i.e. just the cells, no spacing.
149  */
150
151 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
152 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
153
154 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
155  * vice versa.
156  */
157 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
158 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
159
160 /* This is in bin_window coordinates */
161 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
162 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
163
164 #define ROW_HEIGHT(tree_view,height) \
165   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
166
167
168 typedef struct _GtkTreeViewChild GtkTreeViewChild;
169 struct _GtkTreeViewChild
170 {
171   GtkWidget *widget;
172   gint x;
173   gint y;
174   gint width;
175   gint height;
176 };
177
178
179 typedef struct _TreeViewDragInfo TreeViewDragInfo;
180 struct _TreeViewDragInfo
181 {
182   GdkModifierType start_button_mask;
183   GtkTargetList *_unused_source_target_list;
184   GdkDragAction source_actions;
185
186   GtkTargetList *_unused_dest_target_list;
187
188   guint source_set : 1;
189   guint dest_set : 1;
190 };
191
192
193 /* Signals */
194 enum
195 {
196   ROW_ACTIVATED,
197   TEST_EXPAND_ROW,
198   TEST_COLLAPSE_ROW,
199   ROW_EXPANDED,
200   ROW_COLLAPSED,
201   COLUMNS_CHANGED,
202   CURSOR_CHANGED,
203   MOVE_CURSOR,
204   SELECT_ALL,
205   UNSELECT_ALL,
206   SELECT_CURSOR_ROW,
207   TOGGLE_CURSOR_ROW,
208   EXPAND_COLLAPSE_CURSOR_ROW,
209   SELECT_CURSOR_PARENT,
210   START_INTERACTIVE_SEARCH,
211   LAST_SIGNAL
212 };
213
214 /* Properties */
215 enum {
216   PROP_0,
217   PROP_MODEL,
218   PROP_HADJUSTMENT,
219   PROP_VADJUSTMENT,
220   PROP_HSCROLL_POLICY,
221   PROP_VSCROLL_POLICY,
222   PROP_HEADERS_VISIBLE,
223   PROP_HEADERS_CLICKABLE,
224   PROP_EXPANDER_COLUMN,
225   PROP_REORDERABLE,
226   PROP_RULES_HINT,
227   PROP_ENABLE_SEARCH,
228   PROP_SEARCH_COLUMN,
229   PROP_FIXED_HEIGHT_MODE,
230   PROP_HOVER_SELECTION,
231   PROP_HOVER_EXPAND,
232   PROP_SHOW_EXPANDERS,
233   PROP_LEVEL_INDENTATION,
234   PROP_RUBBER_BANDING,
235   PROP_ENABLE_GRID_LINES,
236   PROP_ENABLE_TREE_LINES,
237   PROP_TOOLTIP_COLUMN
238 };
239
240 /* object signals */
241 static void     gtk_tree_view_finalize             (GObject          *object);
242 static void     gtk_tree_view_set_property         (GObject         *object,
243                                                     guint            prop_id,
244                                                     const GValue    *value,
245                                                     GParamSpec      *pspec);
246 static void     gtk_tree_view_get_property         (GObject         *object,
247                                                     guint            prop_id,
248                                                     GValue          *value,
249                                                     GParamSpec      *pspec);
250
251 /* gtkwidget signals */
252 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
253 static void     gtk_tree_view_realize              (GtkWidget        *widget);
254 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
255 static void     gtk_tree_view_map                  (GtkWidget        *widget);
256 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
257                                                     gint             *minimum,
258                                                     gint             *natural);
259 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
260                                                     gint             *minimum,
261                                                     gint             *natural);
262 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
263                                                     GtkRequisition   *requisition);
264 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
265                                                     GtkAllocation    *allocation);
266 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
267                                                     cairo_t          *cr);
268 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
269                                                     GdkEventKey      *event);
270 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
271                                                     GdkEventKey      *event);
272 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
273                                                     GdkEventMotion   *event);
274 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
275                                                     GdkEventCrossing *event);
276 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
277                                                     GdkEventCrossing *event);
278 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
279                                                     GdkEventButton   *event);
280 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
281                                                     GdkEventButton   *event);
282 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
283                                                     GdkEventGrabBroken *event);
284 #if 0
285 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
286                                                     GdkEventConfigure *event);
287 #endif
288
289 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
290                                                     GtkWidget        *child);
291 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
292                                                     GdkEventFocus    *event);
293 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
294                                                     GtkDirectionType  direction);
295 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
296 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
297                                                     GtkStyle         *previous_style);
298 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
299                                                     gboolean          was_grabbed);
300 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
301                                                     GtkStateType      previous_state);
302
303 /* container signals */
304 static void     gtk_tree_view_remove               (GtkContainer     *container,
305                                                     GtkWidget        *widget);
306 static void     gtk_tree_view_forall               (GtkContainer     *container,
307                                                     gboolean          include_internals,
308                                                     GtkCallback       callback,
309                                                     gpointer          callback_data);
310
311 /* Source side drag signals */
312 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
313                                             GdkDragContext   *context);
314 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
315                                             GdkDragContext   *context);
316 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
317                                             GdkDragContext   *context,
318                                             GtkSelectionData *selection_data,
319                                             guint             info,
320                                             guint             time);
321 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
322                                             GdkDragContext   *context);
323
324 /* Target side drag signals */
325 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
326                                                   GdkDragContext   *context,
327                                                   guint             time);
328 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
329                                                   GdkDragContext   *context,
330                                                   gint              x,
331                                                   gint              y,
332                                                   guint             time);
333 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
334                                                   GdkDragContext   *context,
335                                                   gint              x,
336                                                   gint              y,
337                                                   guint             time);
338 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
339                                                   GdkDragContext   *context,
340                                                   gint              x,
341                                                   gint              y,
342                                                   GtkSelectionData *selection_data,
343                                                   guint             info,
344                                                   guint             time);
345
346 /* tree_model signals */
347 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
348                                                            GtkAdjustment   *adjustment);
349 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
350                                                            GtkAdjustment   *adjustment);
351 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
352                                                            GtkMovementStep  step,
353                                                            gint             count);
354 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
355 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
356 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
357                                                            gboolean         start_editing);
358 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
359 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
360                                                                gboolean         logical,
361                                                                gboolean         expand,
362                                                                gboolean         open_all);
363 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
364 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
365                                                            GtkTreePath     *path,
366                                                            GtkTreeIter     *iter,
367                                                            gpointer         data);
368 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
369                                                            GtkTreePath     *path,
370                                                            GtkTreeIter     *iter,
371                                                            gpointer         data);
372 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
373                                                            GtkTreePath     *path,
374                                                            GtkTreeIter     *iter,
375                                                            gpointer         data);
376 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
377                                                            GtkTreePath     *path,
378                                                            gpointer         data);
379 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
380                                                            GtkTreePath     *parent,
381                                                            GtkTreeIter     *iter,
382                                                            gint            *new_order,
383                                                            gpointer         data);
384
385 /* Incremental reflow */
386 static gboolean validate_row             (GtkTreeView *tree_view,
387                                           GtkRBTree   *tree,
388                                           GtkRBNode   *node,
389                                           GtkTreeIter *iter,
390                                           GtkTreePath *path);
391 static void     validate_visible_area    (GtkTreeView *tree_view);
392 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
393 static gboolean do_validate_rows         (GtkTreeView *tree_view,
394                                           gboolean     size_request);
395 static gboolean validate_rows            (GtkTreeView *tree_view);
396 static gboolean presize_handler_callback (gpointer     data);
397 static void     install_presize_handler  (GtkTreeView *tree_view);
398 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
399 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
400                                              GtkTreePath *path,
401                                              gint         offset);
402 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
403 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
404 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
405
406 /* Internal functions */
407 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
408                                                               GtkTreeViewColumn  *column);
409 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
410                                                               guint               keyval,
411                                                               guint               modmask,
412                                                               gboolean            add_shifted_binding,
413                                                               GtkMovementStep     step,
414                                                               gint                count);
415 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
416                                                               GtkRBTree          *tree);
417 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
418                                                               GtkTreePath        *path,
419                                                               const GdkRectangle *clip_rect);
420 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
421                                                               GtkRBTree          *tree,
422                                                               GtkRBNode          *node);
423 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
424                                                               cairo_t            *cr,
425                                                               GtkRBTree          *tree,
426                                                               GtkRBNode          *node,
427                                                               gint                x,
428                                                               gint                y);
429 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
430                                                               GtkRBTree          *tree,
431                                                               gint               *x1,
432                                                               gint               *x2);
433 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
434                                                               gint                i,
435                                                               gint               *x);
436 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
437                                                               GtkTreeView        *tree_view);
438 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
439                                                               GtkRBTree          *tree,
440                                                               GtkTreeIter        *iter,
441                                                               gint                depth,
442                                                               gboolean            recurse);
443 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
444                                                               GtkRBTree          *tree,
445                                                               GtkRBNode          *node);
446 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
447                                                               GtkTreeViewColumn  *column,
448                                                               gboolean            focus_to_cell);
449 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
450                                                               GdkEventMotion     *event);
451 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
452 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
453                                                               gint                count);
454 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
455                                                               gint                count);
456 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
457                                                               gint                count);
458 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
459                                                               gint                count);
460 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
461                                                               GtkTreePath        *path,
462                                                               GtkRBTree          *tree,
463                                                               GtkRBNode          *node,
464                                                               gboolean            animate);
465 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
466                                                               GtkTreePath        *path,
467                                                               GtkRBTree          *tree,
468                                                               GtkRBNode          *node,
469                                                               gboolean            open_all,
470                                                               gboolean            animate);
471 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
472                                                               GtkTreePath        *path,
473                                                               gboolean            clear_and_select,
474                                                               gboolean            clamp_node);
475 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
476 static void     column_sizing_notify                         (GObject            *object,
477                                                               GParamSpec         *pspec,
478                                                               gpointer            data);
479 static gboolean expand_collapse_timeout                      (gpointer            data);
480 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
481                                                               GtkRBTree          *tree,
482                                                               GtkRBNode          *node,
483                                                               gboolean            expand);
484 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
485 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
486 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
487 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
488 static void     update_prelight                              (GtkTreeView        *tree_view,
489                                                               int                 x,
490                                                               int                 y);
491
492 /* interactive search */
493 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
494 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
495                                                          GtkTreeView      *tree_view,
496                                                          GdkDevice        *device);
497 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
498                                                          GtkWidget        *search_dialog,
499                                                          gpointer          user_data);
500 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
501                                                          GtkMenu          *menu,
502                                                          gpointer          data);
503 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
504                                                          GtkTreeView      *tree_view);
505 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
506                                                          GtkTreeView      *tree_view);
507 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
508 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
509                                                          gpointer          data);
510 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
511                                                          GdkEventAny      *event,
512                                                          GtkTreeView      *tree_view);
513 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
514                                                          GdkEventButton   *event,
515                                                          GtkTreeView      *tree_view);
516 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
517                                                          GdkEventScroll   *event,
518                                                          GtkTreeView      *tree_view);
519 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
520                                                          GdkEventKey      *event,
521                                                          GtkTreeView      *tree_view);
522 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
523                                                          GtkTreeView      *tree_view,
524                                                          gboolean          up);
525 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
526                                                          gint              column,
527                                                          const gchar      *key,
528                                                          GtkTreeIter      *iter,
529                                                          gpointer          search_data);
530 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
531                                                          GtkTreeSelection *selection,
532                                                          GtkTreeIter      *iter,
533                                                          const gchar      *text,
534                                                          gint             *count,
535                                                          gint              n);
536 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
537                                                          GtkTreeView      *tree_view);
538 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
539                                                          GtkWidget        *child_widget,
540                                                          gint              x,
541                                                          gint              y,
542                                                          gint              width,
543                                                          gint              height);
544 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
545                                                          GtkTreePath      *cursor_path);
546 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
547                                               GtkTreeViewColumn *column,
548                                               GtkTreePath       *path,
549                                               GtkCellEditable   *cell_editable,
550                                               GdkRectangle      *cell_area,
551                                               GdkEvent          *event,
552                                               guint              flags);
553 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
554                                                          gboolean     cancel_editing);
555 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
556                                                              GdkDevice   *device,
557                                                              gboolean     keybinding);
558 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
559 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
560                                                          GtkTreeViewColumn *column,
561                                                          gint               drop_position);
562
563 /* GtkBuildable */
564 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
565                                                             GtkBuilder        *builder,
566                                                             GObject           *child,
567                                                             const gchar       *type);
568 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
569                                                             GtkBuilder        *builder,
570                                                             const gchar       *childname);
571 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
572
573
574 static gboolean scroll_row_timeout                   (gpointer     data);
575 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
576 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
577
578 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
579
580 \f
581
582 /* GType Methods
583  */
584
585 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
586                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
587                                                 gtk_tree_view_buildable_init)
588                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
589
590 static void
591 gtk_tree_view_class_init (GtkTreeViewClass *class)
592 {
593   GObjectClass *o_class;
594   GtkWidgetClass *widget_class;
595   GtkContainerClass *container_class;
596   GtkBindingSet *binding_set;
597
598   binding_set = gtk_binding_set_by_class (class);
599
600   o_class = (GObjectClass *) class;
601   widget_class = (GtkWidgetClass *) class;
602   container_class = (GtkContainerClass *) class;
603
604   /* GObject signals */
605   o_class->set_property = gtk_tree_view_set_property;
606   o_class->get_property = gtk_tree_view_get_property;
607   o_class->finalize = gtk_tree_view_finalize;
608
609   /* GtkWidget signals */
610   widget_class->destroy = gtk_tree_view_destroy;
611   widget_class->map = gtk_tree_view_map;
612   widget_class->realize = gtk_tree_view_realize;
613   widget_class->unrealize = gtk_tree_view_unrealize;
614   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
615   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
616   widget_class->size_allocate = gtk_tree_view_size_allocate;
617   widget_class->button_press_event = gtk_tree_view_button_press;
618   widget_class->button_release_event = gtk_tree_view_button_release;
619   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
620   /*widget_class->configure_event = gtk_tree_view_configure;*/
621   widget_class->motion_notify_event = gtk_tree_view_motion;
622   widget_class->draw = gtk_tree_view_draw;
623   widget_class->key_press_event = gtk_tree_view_key_press;
624   widget_class->key_release_event = gtk_tree_view_key_release;
625   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
626   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
627   widget_class->focus_out_event = gtk_tree_view_focus_out;
628   widget_class->drag_begin = gtk_tree_view_drag_begin;
629   widget_class->drag_end = gtk_tree_view_drag_end;
630   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
631   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
632   widget_class->drag_leave = gtk_tree_view_drag_leave;
633   widget_class->drag_motion = gtk_tree_view_drag_motion;
634   widget_class->drag_drop = gtk_tree_view_drag_drop;
635   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
636   widget_class->focus = gtk_tree_view_focus;
637   widget_class->grab_focus = gtk_tree_view_grab_focus;
638   widget_class->style_set = gtk_tree_view_style_set;
639   widget_class->grab_notify = gtk_tree_view_grab_notify;
640   widget_class->state_changed = gtk_tree_view_state_changed;
641
642   /* GtkContainer signals */
643   container_class->remove = gtk_tree_view_remove;
644   container_class->forall = gtk_tree_view_forall;
645   container_class->set_focus_child = gtk_tree_view_set_focus_child;
646
647   class->move_cursor = gtk_tree_view_real_move_cursor;
648   class->select_all = gtk_tree_view_real_select_all;
649   class->unselect_all = gtk_tree_view_real_unselect_all;
650   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
651   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
652   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
653   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
654   class->start_interactive_search = gtk_tree_view_start_interactive_search;
655
656   /* Properties */
657
658   g_object_class_install_property (o_class,
659                                    PROP_MODEL,
660                                    g_param_spec_object ("model",
661                                                         P_("TreeView Model"),
662                                                         P_("The model for the tree view"),
663                                                         GTK_TYPE_TREE_MODEL,
664                                                         GTK_PARAM_READWRITE));
665
666   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
667   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
668   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
669   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
670
671   g_object_class_install_property (o_class,
672                                    PROP_HEADERS_VISIBLE,
673                                    g_param_spec_boolean ("headers-visible",
674                                                          P_("Headers Visible"),
675                                                          P_("Show the column header buttons"),
676                                                          TRUE,
677                                                          GTK_PARAM_READWRITE));
678
679   g_object_class_install_property (o_class,
680                                    PROP_HEADERS_CLICKABLE,
681                                    g_param_spec_boolean ("headers-clickable",
682                                                          P_("Headers Clickable"),
683                                                          P_("Column headers respond to click events"),
684                                                          TRUE,
685                                                          GTK_PARAM_READWRITE));
686
687   g_object_class_install_property (o_class,
688                                    PROP_EXPANDER_COLUMN,
689                                    g_param_spec_object ("expander-column",
690                                                         P_("Expander Column"),
691                                                         P_("Set the column for the expander column"),
692                                                         GTK_TYPE_TREE_VIEW_COLUMN,
693                                                         GTK_PARAM_READWRITE));
694
695   g_object_class_install_property (o_class,
696                                    PROP_REORDERABLE,
697                                    g_param_spec_boolean ("reorderable",
698                                                          P_("Reorderable"),
699                                                          P_("View is reorderable"),
700                                                          FALSE,
701                                                          GTK_PARAM_READWRITE));
702
703   g_object_class_install_property (o_class,
704                                    PROP_RULES_HINT,
705                                    g_param_spec_boolean ("rules-hint",
706                                                          P_("Rules Hint"),
707                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
708                                                          FALSE,
709                                                          GTK_PARAM_READWRITE));
710
711     g_object_class_install_property (o_class,
712                                      PROP_ENABLE_SEARCH,
713                                      g_param_spec_boolean ("enable-search",
714                                                            P_("Enable Search"),
715                                                            P_("View allows user to search through columns interactively"),
716                                                            TRUE,
717                                                            GTK_PARAM_READWRITE));
718
719     g_object_class_install_property (o_class,
720                                      PROP_SEARCH_COLUMN,
721                                      g_param_spec_int ("search-column",
722                                                        P_("Search Column"),
723                                                        P_("Model column to search through during interactive search"),
724                                                        -1,
725                                                        G_MAXINT,
726                                                        -1,
727                                                        GTK_PARAM_READWRITE));
728
729     /**
730      * GtkTreeView:fixed-height-mode:
731      *
732      * Setting the ::fixed-height-mode property to %TRUE speeds up 
733      * #GtkTreeView by assuming that all rows have the same height. 
734      * Only enable this option if all rows are the same height.  
735      * Please see gtk_tree_view_set_fixed_height_mode() for more 
736      * information on this option.
737      *
738      * Since: 2.4
739      **/
740     g_object_class_install_property (o_class,
741                                      PROP_FIXED_HEIGHT_MODE,
742                                      g_param_spec_boolean ("fixed-height-mode",
743                                                            P_("Fixed Height Mode"),
744                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
745                                                            FALSE,
746                                                            GTK_PARAM_READWRITE));
747     
748     /**
749      * GtkTreeView:hover-selection:
750      * 
751      * Enables or disables the hover selection mode of @tree_view.
752      * Hover selection makes the selected row follow the pointer.
753      * Currently, this works only for the selection modes 
754      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
755      *
756      * This mode is primarily intended for treeviews in popups, e.g.
757      * in #GtkComboBox or #GtkEntryCompletion.
758      *
759      * Since: 2.6
760      */
761     g_object_class_install_property (o_class,
762                                      PROP_HOVER_SELECTION,
763                                      g_param_spec_boolean ("hover-selection",
764                                                            P_("Hover Selection"),
765                                                            P_("Whether the selection should follow the pointer"),
766                                                            FALSE,
767                                                            GTK_PARAM_READWRITE));
768
769     /**
770      * GtkTreeView:hover-expand:
771      * 
772      * Enables or disables the hover expansion mode of @tree_view.
773      * Hover expansion makes rows expand or collapse if the pointer moves 
774      * over them.
775      *
776      * This mode is primarily intended for treeviews in popups, e.g.
777      * in #GtkComboBox or #GtkEntryCompletion.
778      *
779      * Since: 2.6
780      */
781     g_object_class_install_property (o_class,
782                                      PROP_HOVER_EXPAND,
783                                      g_param_spec_boolean ("hover-expand",
784                                                            P_("Hover Expand"),
785                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
786                                                            FALSE,
787                                                            GTK_PARAM_READWRITE));
788
789     /**
790      * GtkTreeView:show-expanders:
791      *
792      * %TRUE if the view has expanders.
793      *
794      * Since: 2.12
795      */
796     g_object_class_install_property (o_class,
797                                      PROP_SHOW_EXPANDERS,
798                                      g_param_spec_boolean ("show-expanders",
799                                                            P_("Show Expanders"),
800                                                            P_("View has expanders"),
801                                                            TRUE,
802                                                            GTK_PARAM_READWRITE));
803
804     /**
805      * GtkTreeView:level-indentation:
806      *
807      * Extra indentation for each level.
808      *
809      * Since: 2.12
810      */
811     g_object_class_install_property (o_class,
812                                      PROP_LEVEL_INDENTATION,
813                                      g_param_spec_int ("level-indentation",
814                                                        P_("Level Indentation"),
815                                                        P_("Extra indentation for each level"),
816                                                        0,
817                                                        G_MAXINT,
818                                                        0,
819                                                        GTK_PARAM_READWRITE));
820
821     g_object_class_install_property (o_class,
822                                      PROP_RUBBER_BANDING,
823                                      g_param_spec_boolean ("rubber-banding",
824                                                            P_("Rubber Banding"),
825                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
826                                                            FALSE,
827                                                            GTK_PARAM_READWRITE));
828
829     g_object_class_install_property (o_class,
830                                      PROP_ENABLE_GRID_LINES,
831                                      g_param_spec_enum ("enable-grid-lines",
832                                                         P_("Enable Grid Lines"),
833                                                         P_("Whether grid lines should be drawn in the tree view"),
834                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
835                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
836                                                         GTK_PARAM_READWRITE));
837
838     g_object_class_install_property (o_class,
839                                      PROP_ENABLE_TREE_LINES,
840                                      g_param_spec_boolean ("enable-tree-lines",
841                                                            P_("Enable Tree Lines"),
842                                                            P_("Whether tree lines should be drawn in the tree view"),
843                                                            FALSE,
844                                                            GTK_PARAM_READWRITE));
845
846     g_object_class_install_property (o_class,
847                                      PROP_TOOLTIP_COLUMN,
848                                      g_param_spec_int ("tooltip-column",
849                                                        P_("Tooltip Column"),
850                                                        P_("The column in the model containing the tooltip texts for the rows"),
851                                                        -1,
852                                                        G_MAXINT,
853                                                        -1,
854                                                        GTK_PARAM_READWRITE));
855
856   /* Style properties */
857 #define _TREE_VIEW_EXPANDER_SIZE 12
858 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
859 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
860
861   gtk_widget_class_install_style_property (widget_class,
862                                            g_param_spec_int ("expander-size",
863                                                              P_("Expander Size"),
864                                                              P_("Size of the expander arrow"),
865                                                              0,
866                                                              G_MAXINT,
867                                                              _TREE_VIEW_EXPANDER_SIZE,
868                                                              GTK_PARAM_READABLE));
869
870   gtk_widget_class_install_style_property (widget_class,
871                                            g_param_spec_int ("vertical-separator",
872                                                              P_("Vertical Separator Width"),
873                                                              P_("Vertical space between cells.  Must be an even number"),
874                                                              0,
875                                                              G_MAXINT,
876                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
877                                                              GTK_PARAM_READABLE));
878
879   gtk_widget_class_install_style_property (widget_class,
880                                            g_param_spec_int ("horizontal-separator",
881                                                              P_("Horizontal Separator Width"),
882                                                              P_("Horizontal space between cells.  Must be an even number"),
883                                                              0,
884                                                              G_MAXINT,
885                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
886                                                              GTK_PARAM_READABLE));
887
888   gtk_widget_class_install_style_property (widget_class,
889                                            g_param_spec_boolean ("allow-rules",
890                                                                  P_("Allow Rules"),
891                                                                  P_("Allow drawing of alternating color rows"),
892                                                                  TRUE,
893                                                                  GTK_PARAM_READABLE));
894
895   gtk_widget_class_install_style_property (widget_class,
896                                            g_param_spec_boolean ("indent-expanders",
897                                                                  P_("Indent Expanders"),
898                                                                  P_("Make the expanders indented"),
899                                                                  TRUE,
900                                                                  GTK_PARAM_READABLE));
901
902   gtk_widget_class_install_style_property (widget_class,
903                                            g_param_spec_boxed ("even-row-color",
904                                                                P_("Even Row Color"),
905                                                                P_("Color to use for even rows"),
906                                                                GDK_TYPE_COLOR,
907                                                                GTK_PARAM_READABLE));
908
909   gtk_widget_class_install_style_property (widget_class,
910                                            g_param_spec_boxed ("odd-row-color",
911                                                                P_("Odd Row Color"),
912                                                                P_("Color to use for odd rows"),
913                                                                GDK_TYPE_COLOR,
914                                                                GTK_PARAM_READABLE));
915
916   gtk_widget_class_install_style_property (widget_class,
917                                            g_param_spec_int ("grid-line-width",
918                                                              P_("Grid line width"),
919                                                              P_("Width, in pixels, of the tree view grid lines"),
920                                                              0, G_MAXINT, 1,
921                                                              GTK_PARAM_READABLE));
922
923   gtk_widget_class_install_style_property (widget_class,
924                                            g_param_spec_int ("tree-line-width",
925                                                              P_("Tree line width"),
926                                                              P_("Width, in pixels, of the tree view lines"),
927                                                              0, G_MAXINT, 1,
928                                                              GTK_PARAM_READABLE));
929
930   gtk_widget_class_install_style_property (widget_class,
931                                            g_param_spec_string ("grid-line-pattern",
932                                                                 P_("Grid line pattern"),
933                                                                 P_("Dash pattern used to draw the tree view grid lines"),
934                                                                 "\1\1",
935                                                                 GTK_PARAM_READABLE));
936
937   gtk_widget_class_install_style_property (widget_class,
938                                            g_param_spec_string ("tree-line-pattern",
939                                                                 P_("Tree line pattern"),
940                                                                 P_("Dash pattern used to draw the tree view lines"),
941                                                                 "\1\1",
942                                                                 GTK_PARAM_READABLE));
943
944   /* Signals */
945   /**
946    * GtkTreeView::row-activated:
947    * @tree_view: the object on which the signal is emitted
948    * @path: the #GtkTreePath for the activated row
949    * @column: the #GtkTreeViewColumn in which the activation occurred
950    *
951    * The "row-activated" signal is emitted when the method
952    * gtk_tree_view_row_activated() is called or the user double clicks 
953    * a treeview row. It is also emitted when a non-editable row is 
954    * selected and one of the keys: Space, Shift+Space, Return or 
955    * Enter is pressed.
956    * 
957    * For selection handling refer to the <link linkend="TreeWidget">tree 
958    * widget conceptual overview</link> as well as #GtkTreeSelection.
959    */
960   tree_view_signals[ROW_ACTIVATED] =
961     g_signal_new (I_("row-activated"),
962                   G_TYPE_FROM_CLASS (o_class),
963                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
964                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
965                   NULL, NULL,
966                   _gtk_marshal_VOID__BOXED_OBJECT,
967                   G_TYPE_NONE, 2,
968                   GTK_TYPE_TREE_PATH,
969                   GTK_TYPE_TREE_VIEW_COLUMN);
970
971   /**
972    * GtkTreeView::test-expand-row:
973    * @tree_view: the object on which the signal is emitted
974    * @iter: the tree iter of the row to expand
975    * @path: a tree path that points to the row 
976    * 
977    * The given row is about to be expanded (show its children nodes). Use this
978    * signal if you need to control the expandability of individual rows.
979    *
980    * Returns: %FALSE to allow expansion, %TRUE to reject
981    */
982   tree_view_signals[TEST_EXPAND_ROW] =
983     g_signal_new (I_("test-expand-row"),
984                   G_TYPE_FROM_CLASS (o_class),
985                   G_SIGNAL_RUN_LAST,
986                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
987                   _gtk_boolean_handled_accumulator, NULL,
988                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
989                   G_TYPE_BOOLEAN, 2,
990                   GTK_TYPE_TREE_ITER,
991                   GTK_TYPE_TREE_PATH);
992
993   /**
994    * GtkTreeView::test-collapse-row:
995    * @tree_view: the object on which the signal is emitted
996    * @iter: the tree iter of the row to collapse
997    * @path: a tree path that points to the row 
998    * 
999    * The given row is about to be collapsed (hide its children nodes). Use this
1000    * signal if you need to control the collapsibility of individual rows.
1001    *
1002    * Returns: %FALSE to allow collapsing, %TRUE to reject
1003    */
1004   tree_view_signals[TEST_COLLAPSE_ROW] =
1005     g_signal_new (I_("test-collapse-row"),
1006                   G_TYPE_FROM_CLASS (o_class),
1007                   G_SIGNAL_RUN_LAST,
1008                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1009                   _gtk_boolean_handled_accumulator, NULL,
1010                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1011                   G_TYPE_BOOLEAN, 2,
1012                   GTK_TYPE_TREE_ITER,
1013                   GTK_TYPE_TREE_PATH);
1014
1015   /**
1016    * GtkTreeView::row-expanded:
1017    * @tree_view: the object on which the signal is emitted
1018    * @iter: the tree iter of the expanded row
1019    * @path: a tree path that points to the row 
1020    * 
1021    * The given row has been expanded (child nodes are shown).
1022    */
1023   tree_view_signals[ROW_EXPANDED] =
1024     g_signal_new (I_("row-expanded"),
1025                   G_TYPE_FROM_CLASS (o_class),
1026                   G_SIGNAL_RUN_LAST,
1027                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1028                   NULL, NULL,
1029                   _gtk_marshal_VOID__BOXED_BOXED,
1030                   G_TYPE_NONE, 2,
1031                   GTK_TYPE_TREE_ITER,
1032                   GTK_TYPE_TREE_PATH);
1033
1034   /**
1035    * GtkTreeView::row-collapsed:
1036    * @tree_view: the object on which the signal is emitted
1037    * @iter: the tree iter of the collapsed row
1038    * @path: a tree path that points to the row 
1039    * 
1040    * The given row has been collapsed (child nodes are hidden).
1041    */
1042   tree_view_signals[ROW_COLLAPSED] =
1043     g_signal_new (I_("row-collapsed"),
1044                   G_TYPE_FROM_CLASS (o_class),
1045                   G_SIGNAL_RUN_LAST,
1046                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1047                   NULL, NULL,
1048                   _gtk_marshal_VOID__BOXED_BOXED,
1049                   G_TYPE_NONE, 2,
1050                   GTK_TYPE_TREE_ITER,
1051                   GTK_TYPE_TREE_PATH);
1052
1053   /**
1054    * GtkTreeView::columns-changed:
1055    * @tree_view: the object on which the signal is emitted 
1056    * 
1057    * The number of columns of the treeview has changed.
1058    */
1059   tree_view_signals[COLUMNS_CHANGED] =
1060     g_signal_new (I_("columns-changed"),
1061                   G_TYPE_FROM_CLASS (o_class),
1062                   G_SIGNAL_RUN_LAST,
1063                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1064                   NULL, NULL,
1065                   _gtk_marshal_VOID__VOID,
1066                   G_TYPE_NONE, 0);
1067
1068   /**
1069    * GtkTreeView::cursor-changed:
1070    * @tree_view: the object on which the signal is emitted
1071    * 
1072    * The position of the cursor (focused cell) has changed.
1073    */
1074   tree_view_signals[CURSOR_CHANGED] =
1075     g_signal_new (I_("cursor-changed"),
1076                   G_TYPE_FROM_CLASS (o_class),
1077                   G_SIGNAL_RUN_LAST,
1078                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1079                   NULL, NULL,
1080                   _gtk_marshal_VOID__VOID,
1081                   G_TYPE_NONE, 0);
1082
1083   tree_view_signals[MOVE_CURSOR] =
1084     g_signal_new (I_("move-cursor"),
1085                   G_TYPE_FROM_CLASS (o_class),
1086                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1087                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1088                   NULL, NULL,
1089                   _gtk_marshal_BOOLEAN__ENUM_INT,
1090                   G_TYPE_BOOLEAN, 2,
1091                   GTK_TYPE_MOVEMENT_STEP,
1092                   G_TYPE_INT);
1093
1094   tree_view_signals[SELECT_ALL] =
1095     g_signal_new (I_("select-all"),
1096                   G_TYPE_FROM_CLASS (o_class),
1097                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1098                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1099                   NULL, NULL,
1100                   _gtk_marshal_BOOLEAN__VOID,
1101                   G_TYPE_BOOLEAN, 0);
1102
1103   tree_view_signals[UNSELECT_ALL] =
1104     g_signal_new (I_("unselect-all"),
1105                   G_TYPE_FROM_CLASS (o_class),
1106                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1107                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1108                   NULL, NULL,
1109                   _gtk_marshal_BOOLEAN__VOID,
1110                   G_TYPE_BOOLEAN, 0);
1111
1112   tree_view_signals[SELECT_CURSOR_ROW] =
1113     g_signal_new (I_("select-cursor-row"),
1114                   G_TYPE_FROM_CLASS (o_class),
1115                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1116                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1117                   NULL, NULL,
1118                   _gtk_marshal_BOOLEAN__BOOLEAN,
1119                   G_TYPE_BOOLEAN, 1,
1120                   G_TYPE_BOOLEAN);
1121
1122   tree_view_signals[TOGGLE_CURSOR_ROW] =
1123     g_signal_new (I_("toggle-cursor-row"),
1124                   G_TYPE_FROM_CLASS (o_class),
1125                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1126                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1127                   NULL, NULL,
1128                   _gtk_marshal_BOOLEAN__VOID,
1129                   G_TYPE_BOOLEAN, 0);
1130
1131   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1132     g_signal_new (I_("expand-collapse-cursor-row"),
1133                   G_TYPE_FROM_CLASS (o_class),
1134                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1135                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1136                   NULL, NULL,
1137                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1138                   G_TYPE_BOOLEAN, 3,
1139                   G_TYPE_BOOLEAN,
1140                   G_TYPE_BOOLEAN,
1141                   G_TYPE_BOOLEAN);
1142
1143   tree_view_signals[SELECT_CURSOR_PARENT] =
1144     g_signal_new (I_("select-cursor-parent"),
1145                   G_TYPE_FROM_CLASS (o_class),
1146                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1147                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1148                   NULL, NULL,
1149                   _gtk_marshal_BOOLEAN__VOID,
1150                   G_TYPE_BOOLEAN, 0);
1151
1152   tree_view_signals[START_INTERACTIVE_SEARCH] =
1153     g_signal_new (I_("start-interactive-search"),
1154                   G_TYPE_FROM_CLASS (o_class),
1155                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1156                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1157                   NULL, NULL,
1158                   _gtk_marshal_BOOLEAN__VOID,
1159                   G_TYPE_BOOLEAN, 0);
1160
1161   /* Key bindings */
1162   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1163                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1164   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1165                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1166
1167   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1168                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1169   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1170                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1171
1172   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1173                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1174
1175   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1176                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1177
1178   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1179                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1180   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1181                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1182
1183   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1184                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1185   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1186                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1187
1188   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1189                                   GTK_MOVEMENT_PAGES, -1);
1190   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1191                                   GTK_MOVEMENT_PAGES, -1);
1192
1193   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1194                                   GTK_MOVEMENT_PAGES, 1);
1195   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1196                                   GTK_MOVEMENT_PAGES, 1);
1197
1198
1199   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1200                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1201                                 G_TYPE_INT, 1);
1202
1203   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1204                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1205                                 G_TYPE_INT, -1);
1206
1207   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1208                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1209                                 G_TYPE_INT, 1);
1210
1211   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1212                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1213                                 G_TYPE_INT, -1);
1214
1215   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1216                                 "move-cursor", 2,
1217                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1218                                 G_TYPE_INT, 1);
1219
1220   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1221                                 "move-cursor", 2,
1222                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1223                                 G_TYPE_INT, -1);
1224
1225   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1226                                 "move-cursor", 2,
1227                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1228                                 G_TYPE_INT, 1);
1229
1230   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1231                                 "move-cursor", 2,
1232                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1233                                 G_TYPE_INT, -1);
1234
1235   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1236   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1237
1238   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1239   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1240
1241   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1242   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1243
1244   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1245                                 G_TYPE_BOOLEAN, TRUE);
1246   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1247                                 G_TYPE_BOOLEAN, TRUE);
1248
1249   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1250                                 G_TYPE_BOOLEAN, TRUE);
1251   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1252                                 G_TYPE_BOOLEAN, TRUE);
1253   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1254                                 G_TYPE_BOOLEAN, TRUE);
1255   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1256                                 G_TYPE_BOOLEAN, TRUE);
1257   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1258                                 G_TYPE_BOOLEAN, TRUE);
1259
1260   /* expand and collapse rows */
1261   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1262                                 G_TYPE_BOOLEAN, TRUE,
1263                                 G_TYPE_BOOLEAN, TRUE,
1264                                 G_TYPE_BOOLEAN, FALSE);
1265
1266   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1267                                 "expand-collapse-cursor-row", 3,
1268                                 G_TYPE_BOOLEAN, TRUE,
1269                                 G_TYPE_BOOLEAN, TRUE,
1270                                 G_TYPE_BOOLEAN, TRUE);
1271   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1272                                 "expand-collapse-cursor-row", 3,
1273                                 G_TYPE_BOOLEAN, TRUE,
1274                                 G_TYPE_BOOLEAN, TRUE,
1275                                 G_TYPE_BOOLEAN, TRUE);
1276
1277   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1278                                 "expand-collapse-cursor-row", 3,
1279                                 G_TYPE_BOOLEAN, TRUE,
1280                                 G_TYPE_BOOLEAN, FALSE,
1281                                 G_TYPE_BOOLEAN, FALSE);
1282   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1283                                 "expand-collapse-cursor-row", 3,
1284                                 G_TYPE_BOOLEAN, TRUE,
1285                                 G_TYPE_BOOLEAN, FALSE,
1286                                 G_TYPE_BOOLEAN, FALSE);
1287
1288   /* Not doable on US keyboards */
1289   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1290                                 G_TYPE_BOOLEAN, TRUE,
1291                                 G_TYPE_BOOLEAN, TRUE,
1292                                 G_TYPE_BOOLEAN, TRUE);
1293   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1294                                 G_TYPE_BOOLEAN, TRUE,
1295                                 G_TYPE_BOOLEAN, TRUE,
1296                                 G_TYPE_BOOLEAN, FALSE);
1297   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1298                                 G_TYPE_BOOLEAN, TRUE,
1299                                 G_TYPE_BOOLEAN, TRUE,
1300                                 G_TYPE_BOOLEAN, TRUE);
1301   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1302                                 G_TYPE_BOOLEAN, TRUE,
1303                                 G_TYPE_BOOLEAN, TRUE,
1304                                 G_TYPE_BOOLEAN, TRUE);
1305   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1306                                 "expand-collapse-cursor-row", 3,
1307                                 G_TYPE_BOOLEAN, FALSE,
1308                                 G_TYPE_BOOLEAN, TRUE,
1309                                 G_TYPE_BOOLEAN, TRUE);
1310   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1311                                 "expand-collapse-cursor-row", 3,
1312                                 G_TYPE_BOOLEAN, FALSE,
1313                                 G_TYPE_BOOLEAN, TRUE,
1314                                 G_TYPE_BOOLEAN, TRUE);
1315   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1316                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1317                                 "expand-collapse-cursor-row", 3,
1318                                 G_TYPE_BOOLEAN, FALSE,
1319                                 G_TYPE_BOOLEAN, TRUE,
1320                                 G_TYPE_BOOLEAN, TRUE);
1321   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1322                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1323                                 "expand-collapse-cursor-row", 3,
1324                                 G_TYPE_BOOLEAN, FALSE,
1325                                 G_TYPE_BOOLEAN, TRUE,
1326                                 G_TYPE_BOOLEAN, TRUE);
1327
1328   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1329                                 G_TYPE_BOOLEAN, TRUE,
1330                                 G_TYPE_BOOLEAN, FALSE,
1331                                 G_TYPE_BOOLEAN, FALSE);
1332   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1333                                 G_TYPE_BOOLEAN, TRUE,
1334                                 G_TYPE_BOOLEAN, FALSE,
1335                                 G_TYPE_BOOLEAN, TRUE);
1336   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1337                                 G_TYPE_BOOLEAN, TRUE,
1338                                 G_TYPE_BOOLEAN, FALSE,
1339                                 G_TYPE_BOOLEAN, FALSE);
1340   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1341                                 G_TYPE_BOOLEAN, TRUE,
1342                                 G_TYPE_BOOLEAN, FALSE,
1343                                 G_TYPE_BOOLEAN, TRUE);
1344   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1345                                 "expand-collapse-cursor-row", 3,
1346                                 G_TYPE_BOOLEAN, FALSE,
1347                                 G_TYPE_BOOLEAN, FALSE,
1348                                 G_TYPE_BOOLEAN, TRUE);
1349   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1350                                 "expand-collapse-cursor-row", 3,
1351                                 G_TYPE_BOOLEAN, FALSE,
1352                                 G_TYPE_BOOLEAN, FALSE,
1353                                 G_TYPE_BOOLEAN, TRUE);
1354   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1355                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1356                                 "expand-collapse-cursor-row", 3,
1357                                 G_TYPE_BOOLEAN, FALSE,
1358                                 G_TYPE_BOOLEAN, FALSE,
1359                                 G_TYPE_BOOLEAN, TRUE);
1360   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1361                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1362                                 "expand-collapse-cursor-row", 3,
1363                                 G_TYPE_BOOLEAN, FALSE,
1364                                 G_TYPE_BOOLEAN, FALSE,
1365                                 G_TYPE_BOOLEAN, TRUE);
1366
1367   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1368   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1369
1370   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1371
1372   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1373
1374   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1375 }
1376
1377 static void
1378 gtk_tree_view_init (GtkTreeView *tree_view)
1379 {
1380   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1381
1382   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1383   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1384
1385   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1386                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1387                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1388
1389   /* We need some padding */
1390   tree_view->priv->dy = 0;
1391   tree_view->priv->cursor_offset = 0;
1392   tree_view->priv->n_columns = 0;
1393   tree_view->priv->header_height = 1;
1394   tree_view->priv->x_drag = 0;
1395   tree_view->priv->drag_pos = -1;
1396   tree_view->priv->header_has_focus = FALSE;
1397   tree_view->priv->pressed_button = -1;
1398   tree_view->priv->press_start_x = -1;
1399   tree_view->priv->press_start_y = -1;
1400   tree_view->priv->reorderable = FALSE;
1401   tree_view->priv->presize_handler_timer = 0;
1402   tree_view->priv->scroll_sync_timer = 0;
1403   tree_view->priv->fixed_height = -1;
1404   tree_view->priv->fixed_height_mode = FALSE;
1405   tree_view->priv->fixed_height_check = 0;
1406   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1407   tree_view->priv->enable_search = TRUE;
1408   tree_view->priv->search_column = -1;
1409   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1410   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1411   tree_view->priv->search_custom_entry_set = FALSE;
1412   tree_view->priv->typeselect_flush_timeout = 0;
1413   tree_view->priv->init_hadjust_value = TRUE;    
1414   tree_view->priv->width = 0;
1415           
1416   tree_view->priv->hover_selection = FALSE;
1417   tree_view->priv->hover_expand = FALSE;
1418
1419   tree_view->priv->level_indentation = 0;
1420
1421   tree_view->priv->rubber_banding_enable = FALSE;
1422
1423   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1424   tree_view->priv->tree_lines_enabled = FALSE;
1425
1426   tree_view->priv->tooltip_column = -1;
1427
1428   tree_view->priv->post_validation_flag = FALSE;
1429
1430   tree_view->priv->last_button_x = -1;
1431   tree_view->priv->last_button_y = -1;
1432
1433   tree_view->priv->event_last_x = -10000;
1434   tree_view->priv->event_last_y = -10000;
1435
1436   gtk_tree_view_set_vadjustment (tree_view, NULL);
1437   gtk_tree_view_set_hadjustment (tree_view, NULL);
1438 }
1439
1440 \f
1441
1442 /* GObject Methods
1443  */
1444
1445 static void
1446 gtk_tree_view_set_property (GObject         *object,
1447                             guint            prop_id,
1448                             const GValue    *value,
1449                             GParamSpec      *pspec)
1450 {
1451   GtkTreeView *tree_view;
1452
1453   tree_view = GTK_TREE_VIEW (object);
1454
1455   switch (prop_id)
1456     {
1457     case PROP_MODEL:
1458       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1459       break;
1460     case PROP_HADJUSTMENT:
1461       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1462       break;
1463     case PROP_VADJUSTMENT:
1464       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1465       break;
1466     case PROP_HSCROLL_POLICY:
1467       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1468       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1469       break;
1470     case PROP_VSCROLL_POLICY:
1471       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1472       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1473       break;
1474     case PROP_HEADERS_VISIBLE:
1475       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1476       break;
1477     case PROP_HEADERS_CLICKABLE:
1478       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1479       break;
1480     case PROP_EXPANDER_COLUMN:
1481       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1482       break;
1483     case PROP_REORDERABLE:
1484       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1485       break;
1486     case PROP_RULES_HINT:
1487       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1488       break;
1489     case PROP_ENABLE_SEARCH:
1490       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1491       break;
1492     case PROP_SEARCH_COLUMN:
1493       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1494       break;
1495     case PROP_FIXED_HEIGHT_MODE:
1496       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1497       break;
1498     case PROP_HOVER_SELECTION:
1499       tree_view->priv->hover_selection = g_value_get_boolean (value);
1500       break;
1501     case PROP_HOVER_EXPAND:
1502       tree_view->priv->hover_expand = g_value_get_boolean (value);
1503       break;
1504     case PROP_SHOW_EXPANDERS:
1505       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1506       break;
1507     case PROP_LEVEL_INDENTATION:
1508       tree_view->priv->level_indentation = g_value_get_int (value);
1509       break;
1510     case PROP_RUBBER_BANDING:
1511       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1512       break;
1513     case PROP_ENABLE_GRID_LINES:
1514       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1515       break;
1516     case PROP_ENABLE_TREE_LINES:
1517       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1518       break;
1519     case PROP_TOOLTIP_COLUMN:
1520       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1521       break;
1522     default:
1523       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1524       break;
1525     }
1526 }
1527
1528 static void
1529 gtk_tree_view_get_property (GObject    *object,
1530                             guint       prop_id,
1531                             GValue     *value,
1532                             GParamSpec *pspec)
1533 {
1534   GtkTreeView *tree_view;
1535
1536   tree_view = GTK_TREE_VIEW (object);
1537
1538   switch (prop_id)
1539     {
1540     case PROP_MODEL:
1541       g_value_set_object (value, tree_view->priv->model);
1542       break;
1543     case PROP_HADJUSTMENT:
1544       g_value_set_object (value, tree_view->priv->hadjustment);
1545       break;
1546     case PROP_VADJUSTMENT:
1547       g_value_set_object (value, tree_view->priv->vadjustment);
1548       break;
1549     case PROP_HSCROLL_POLICY:
1550       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1551       break;
1552     case PROP_VSCROLL_POLICY:
1553       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1554       break;
1555     case PROP_HEADERS_VISIBLE:
1556       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1557       break;
1558     case PROP_HEADERS_CLICKABLE:
1559       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1560       break;
1561     case PROP_EXPANDER_COLUMN:
1562       g_value_set_object (value, tree_view->priv->expander_column);
1563       break;
1564     case PROP_REORDERABLE:
1565       g_value_set_boolean (value, tree_view->priv->reorderable);
1566       break;
1567     case PROP_RULES_HINT:
1568       g_value_set_boolean (value, tree_view->priv->has_rules);
1569       break;
1570     case PROP_ENABLE_SEARCH:
1571       g_value_set_boolean (value, tree_view->priv->enable_search);
1572       break;
1573     case PROP_SEARCH_COLUMN:
1574       g_value_set_int (value, tree_view->priv->search_column);
1575       break;
1576     case PROP_FIXED_HEIGHT_MODE:
1577       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1578       break;
1579     case PROP_HOVER_SELECTION:
1580       g_value_set_boolean (value, tree_view->priv->hover_selection);
1581       break;
1582     case PROP_HOVER_EXPAND:
1583       g_value_set_boolean (value, tree_view->priv->hover_expand);
1584       break;
1585     case PROP_SHOW_EXPANDERS:
1586       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1587       break;
1588     case PROP_LEVEL_INDENTATION:
1589       g_value_set_int (value, tree_view->priv->level_indentation);
1590       break;
1591     case PROP_RUBBER_BANDING:
1592       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1593       break;
1594     case PROP_ENABLE_GRID_LINES:
1595       g_value_set_enum (value, tree_view->priv->grid_lines);
1596       break;
1597     case PROP_ENABLE_TREE_LINES:
1598       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1599       break;
1600     case PROP_TOOLTIP_COLUMN:
1601       g_value_set_int (value, tree_view->priv->tooltip_column);
1602       break;
1603     default:
1604       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1605       break;
1606     }
1607 }
1608
1609 static void
1610 gtk_tree_view_finalize (GObject *object)
1611 {
1612   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1613 }
1614
1615
1616 static GtkBuildableIface *parent_buildable_iface;
1617
1618 static void
1619 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1620 {
1621   parent_buildable_iface = g_type_interface_peek_parent (iface);
1622   iface->add_child = gtk_tree_view_buildable_add_child;
1623   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1624 }
1625
1626 static void
1627 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1628                                    GtkBuilder  *builder,
1629                                    GObject     *child,
1630                                    const gchar *type)
1631 {
1632   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1633 }
1634
1635 static GObject *
1636 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1637                                             GtkBuilder        *builder,
1638                                             const gchar       *childname)
1639 {
1640     if (strcmp (childname, "selection") == 0)
1641       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1642     
1643     return parent_buildable_iface->get_internal_child (buildable,
1644                                                        builder,
1645                                                        childname);
1646 }
1647
1648 /* GtkWidget Methods
1649  */
1650
1651 static void
1652 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1653 {
1654   _gtk_rbtree_free (tree_view->priv->tree);
1655   
1656   tree_view->priv->tree = NULL;
1657   tree_view->priv->button_pressed_node = NULL;
1658   tree_view->priv->button_pressed_tree = NULL;
1659   tree_view->priv->prelight_tree = NULL;
1660   tree_view->priv->prelight_node = NULL;
1661   tree_view->priv->expanded_collapsed_node = NULL;
1662   tree_view->priv->expanded_collapsed_tree = NULL;
1663 }
1664
1665 static void
1666 gtk_tree_view_destroy (GtkWidget *widget)
1667 {
1668   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1669   GList *list;
1670
1671   gtk_tree_view_stop_editing (tree_view, TRUE);
1672
1673   if (tree_view->priv->columns != NULL)
1674     {
1675       list = tree_view->priv->columns;
1676       while (list)
1677         {
1678           GtkTreeViewColumn *column;
1679           column = GTK_TREE_VIEW_COLUMN (list->data);
1680           list = list->next;
1681           gtk_tree_view_remove_column (tree_view, column);
1682         }
1683       tree_view->priv->columns = NULL;
1684     }
1685
1686   if (tree_view->priv->tree != NULL)
1687     {
1688       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1689
1690       gtk_tree_view_free_rbtree (tree_view);
1691     }
1692
1693   if (tree_view->priv->selection != NULL)
1694     {
1695       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1696       g_object_unref (tree_view->priv->selection);
1697       tree_view->priv->selection = NULL;
1698     }
1699
1700   if (tree_view->priv->scroll_to_path != NULL)
1701     {
1702       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1703       tree_view->priv->scroll_to_path = NULL;
1704     }
1705
1706   if (tree_view->priv->drag_dest_row != NULL)
1707     {
1708       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1709       tree_view->priv->drag_dest_row = NULL;
1710     }
1711
1712   if (tree_view->priv->top_row != NULL)
1713     {
1714       gtk_tree_row_reference_free (tree_view->priv->top_row);
1715       tree_view->priv->top_row = NULL;
1716     }
1717
1718   if (tree_view->priv->column_drop_func_data &&
1719       tree_view->priv->column_drop_func_data_destroy)
1720     {
1721       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1722       tree_view->priv->column_drop_func_data = NULL;
1723     }
1724
1725   if (tree_view->priv->destroy_count_destroy &&
1726       tree_view->priv->destroy_count_data)
1727     {
1728       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1729       tree_view->priv->destroy_count_data = NULL;
1730     }
1731
1732   gtk_tree_row_reference_free (tree_view->priv->cursor);
1733   tree_view->priv->cursor = NULL;
1734
1735   gtk_tree_row_reference_free (tree_view->priv->anchor);
1736   tree_view->priv->anchor = NULL;
1737
1738   /* destroy interactive search dialog */
1739   if (tree_view->priv->search_window)
1740     {
1741       gtk_widget_destroy (tree_view->priv->search_window);
1742       tree_view->priv->search_window = NULL;
1743       tree_view->priv->search_entry = NULL;
1744       if (tree_view->priv->typeselect_flush_timeout)
1745         {
1746           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1747           tree_view->priv->typeselect_flush_timeout = 0;
1748         }
1749     }
1750
1751   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1752     {
1753       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1754       tree_view->priv->search_user_data = NULL;
1755     }
1756
1757   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1758     {
1759       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1760       tree_view->priv->search_position_user_data = NULL;
1761     }
1762
1763   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1764     {
1765       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1766       tree_view->priv->row_separator_data = NULL;
1767     }
1768   
1769   gtk_tree_view_set_model (tree_view, NULL);
1770
1771   if (tree_view->priv->hadjustment)
1772     {
1773       g_object_unref (tree_view->priv->hadjustment);
1774       tree_view->priv->hadjustment = NULL;
1775     }
1776   if (tree_view->priv->vadjustment)
1777     {
1778       g_object_unref (tree_view->priv->vadjustment);
1779       tree_view->priv->vadjustment = NULL;
1780     }
1781
1782   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
1783 }
1784
1785 /* GtkWidget::map helper */
1786 static void
1787 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1788 {
1789   GList *list;
1790
1791   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
1792
1793   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1794     {
1795       GtkTreeViewColumn *column;
1796
1797       for (list = tree_view->priv->columns; list; list = list->next)
1798         {
1799           column = list->data;
1800           if (gtk_widget_get_visible (column->button) &&
1801               !gtk_widget_get_mapped (column->button))
1802             gtk_widget_map (column->button);
1803         }
1804       for (list = tree_view->priv->columns; list; list = list->next)
1805         {
1806           column = list->data;
1807           if (gtk_tree_view_column_get_visible (column) == FALSE)
1808             continue;
1809           if (gtk_tree_view_column_get_resizable (column))
1810             {
1811               gdk_window_raise (column->window);
1812               gdk_window_show (column->window);
1813             }
1814           else
1815             gdk_window_hide (column->window);
1816         }
1817       gdk_window_show (tree_view->priv->header_window);
1818     }
1819 }
1820
1821 static void
1822 gtk_tree_view_map (GtkWidget *widget)
1823 {
1824   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1825   GList *tmp_list;
1826
1827   gtk_widget_set_mapped (widget, TRUE);
1828
1829   tmp_list = tree_view->priv->children;
1830   while (tmp_list)
1831     {
1832       GtkTreeViewChild *child = tmp_list->data;
1833       tmp_list = tmp_list->next;
1834
1835       if (gtk_widget_get_visible (child->widget))
1836         {
1837           if (!gtk_widget_get_mapped (child->widget))
1838             gtk_widget_map (child->widget);
1839         }
1840     }
1841   gdk_window_show (tree_view->priv->bin_window);
1842
1843   gtk_tree_view_map_buttons (tree_view);
1844
1845   gdk_window_show (gtk_widget_get_window (widget));
1846 }
1847
1848 static void
1849 gtk_tree_view_realize (GtkWidget *widget)
1850 {
1851   GtkAllocation allocation;
1852   GtkStyle *style;
1853   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1854   GdkWindow *window;
1855   GdkWindowAttr attributes;
1856   GList *tmp_list;
1857   gint attributes_mask;
1858
1859   gtk_widget_set_realized (widget, TRUE);
1860
1861   gtk_widget_get_allocation (widget, &allocation);
1862
1863   /* Make the main, clipping window */
1864   attributes.window_type = GDK_WINDOW_CHILD;
1865   attributes.x = allocation.x;
1866   attributes.y = allocation.y;
1867   attributes.width = allocation.width;
1868   attributes.height = allocation.height;
1869   attributes.wclass = GDK_INPUT_OUTPUT;
1870   attributes.visual = gtk_widget_get_visual (widget);
1871   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1872
1873   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1874
1875   window = gdk_window_new (gtk_widget_get_parent_window (widget),
1876                            &attributes, attributes_mask);
1877   gtk_widget_set_window (widget, window);
1878   gdk_window_set_user_data (window, widget);
1879
1880   gtk_widget_get_allocation (widget, &allocation);
1881
1882   /* Make the window for the tree */
1883   attributes.x = 0;
1884   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1885   attributes.width = MAX (tree_view->priv->width, allocation.width);
1886   attributes.height = allocation.height;
1887   attributes.event_mask = (GDK_EXPOSURE_MASK |
1888                            GDK_SCROLL_MASK |
1889                            GDK_POINTER_MOTION_MASK |
1890                            GDK_ENTER_NOTIFY_MASK |
1891                            GDK_LEAVE_NOTIFY_MASK |
1892                            GDK_BUTTON_PRESS_MASK |
1893                            GDK_BUTTON_RELEASE_MASK |
1894                            gtk_widget_get_events (widget));
1895
1896   tree_view->priv->bin_window = gdk_window_new (window,
1897                                                 &attributes, attributes_mask);
1898   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1899
1900   gtk_widget_get_allocation (widget, &allocation);
1901
1902   /* Make the column header window */
1903   attributes.x = 0;
1904   attributes.y = 0;
1905   attributes.width = MAX (tree_view->priv->width, allocation.width);
1906   attributes.height = tree_view->priv->header_height;
1907   attributes.event_mask = (GDK_EXPOSURE_MASK |
1908                            GDK_SCROLL_MASK |
1909                            GDK_ENTER_NOTIFY_MASK |
1910                            GDK_LEAVE_NOTIFY_MASK |
1911                            GDK_BUTTON_PRESS_MASK |
1912                            GDK_BUTTON_RELEASE_MASK |
1913                            GDK_KEY_PRESS_MASK |
1914                            GDK_KEY_RELEASE_MASK |
1915                            gtk_widget_get_events (widget));
1916
1917   tree_view->priv->header_window = gdk_window_new (window,
1918                                                    &attributes, attributes_mask);
1919   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1920
1921   /* Add them all up. */
1922   gtk_widget_style_attach (widget);
1923   style = gtk_widget_get_style (widget);
1924   gdk_window_set_background (tree_view->priv->bin_window,
1925                              &style->base[gtk_widget_get_state (widget)]);
1926   gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1927
1928   tmp_list = tree_view->priv->children;
1929   while (tmp_list)
1930     {
1931       GtkTreeViewChild *child = tmp_list->data;
1932       tmp_list = tmp_list->next;
1933
1934       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1935     }
1936
1937   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1938     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1939
1940   /* Need to call those here, since they create GCs */
1941   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1942   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1943
1944   install_presize_handler (tree_view); 
1945 }
1946
1947 static void
1948 gtk_tree_view_unrealize (GtkWidget *widget)
1949 {
1950   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1951   GtkTreeViewPrivate *priv = tree_view->priv;
1952   GList *list;
1953
1954   if (priv->scroll_timeout != 0)
1955     {
1956       g_source_remove (priv->scroll_timeout);
1957       priv->scroll_timeout = 0;
1958     }
1959
1960   if (priv->auto_expand_timeout != 0)
1961     {
1962       g_source_remove (priv->auto_expand_timeout);
1963       priv->auto_expand_timeout = 0;
1964     }
1965
1966   if (priv->open_dest_timeout != 0)
1967     {
1968       g_source_remove (priv->open_dest_timeout);
1969       priv->open_dest_timeout = 0;
1970     }
1971
1972   remove_expand_collapse_timeout (tree_view);
1973   
1974   if (priv->presize_handler_timer != 0)
1975     {
1976       g_source_remove (priv->presize_handler_timer);
1977       priv->presize_handler_timer = 0;
1978     }
1979
1980   if (priv->validate_rows_timer != 0)
1981     {
1982       g_source_remove (priv->validate_rows_timer);
1983       priv->validate_rows_timer = 0;
1984     }
1985
1986   if (priv->scroll_sync_timer != 0)
1987     {
1988       g_source_remove (priv->scroll_sync_timer);
1989       priv->scroll_sync_timer = 0;
1990     }
1991
1992   if (priv->typeselect_flush_timeout)
1993     {
1994       g_source_remove (priv->typeselect_flush_timeout);
1995       priv->typeselect_flush_timeout = 0;
1996     }
1997   
1998   for (list = priv->columns; list; list = list->next)
1999     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2000
2001   gdk_window_set_user_data (priv->bin_window, NULL);
2002   gdk_window_destroy (priv->bin_window);
2003   priv->bin_window = NULL;
2004
2005   gdk_window_set_user_data (priv->header_window, NULL);
2006   gdk_window_destroy (priv->header_window);
2007   priv->header_window = NULL;
2008
2009   if (priv->drag_window)
2010     {
2011       gdk_window_set_user_data (priv->drag_window, NULL);
2012       gdk_window_destroy (priv->drag_window);
2013       priv->drag_window = NULL;
2014     }
2015
2016   if (priv->drag_highlight_window)
2017     {
2018       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2019       gdk_window_destroy (priv->drag_highlight_window);
2020       priv->drag_highlight_window = NULL;
2021     }
2022
2023   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2024 }
2025
2026 /* GtkWidget::size_request helper */
2027 static void
2028 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2029 {
2030   GList *list;
2031
2032   tree_view->priv->header_height = 0;
2033
2034   if (tree_view->priv->model)
2035     {
2036       for (list = tree_view->priv->columns; list; list = list->next)
2037         {
2038           GtkRequisition requisition;
2039           GtkTreeViewColumn *column = list->data;
2040
2041           if (column->button == NULL)
2042             continue;
2043
2044           column = list->data;
2045
2046           gtk_widget_get_preferred_size (column->button, &requisition, NULL);
2047           column->button_request = requisition.width;
2048           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2049         }
2050     }
2051 }
2052
2053
2054 /* Called only by ::size_request */
2055 static void
2056 gtk_tree_view_update_size (GtkTreeView *tree_view)
2057 {
2058   GList *list;
2059   GtkTreeViewColumn *column;
2060   gint i;
2061
2062   if (tree_view->priv->model == NULL)
2063     {
2064       tree_view->priv->width = 0;
2065       tree_view->priv->prev_width = 0;                   
2066       tree_view->priv->height = 0;
2067       return;
2068     }
2069
2070   tree_view->priv->prev_width = tree_view->priv->width;  
2071   tree_view->priv->width = 0;
2072
2073   /* keep this in sync with size_allocate below */
2074   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2075     {
2076       gint max_width, min_width;
2077       gint real_requested_width = 0;
2078
2079       column = list->data;
2080       if (!gtk_tree_view_column_get_visible (column))
2081         continue;
2082
2083       if (column->use_resized_width)
2084         {
2085           real_requested_width = column->resized_width;
2086         }
2087       else if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_FIXED)
2088         {
2089           real_requested_width = gtk_tree_view_column_get_fixed_width (column);
2090         }
2091       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2092         {
2093           real_requested_width = MAX (column->requested_width, column->button_request);
2094         }
2095       else
2096         {
2097           real_requested_width = column->requested_width;
2098         }
2099
2100       min_width = gtk_tree_view_column_get_min_width (column);
2101       if (min_width != -1)
2102         real_requested_width = MAX (real_requested_width, min_width);
2103
2104       max_width = gtk_tree_view_column_get_max_width (column);
2105       if (max_width != -1)
2106         real_requested_width = MIN (real_requested_width, max_width);
2107
2108       tree_view->priv->width += real_requested_width;
2109     }
2110
2111   if (tree_view->priv->tree == NULL)
2112     tree_view->priv->height = 0;
2113   else
2114     tree_view->priv->height = tree_view->priv->tree->root->offset;
2115 }
2116
2117 static void
2118 gtk_tree_view_size_request (GtkWidget      *widget,
2119                             GtkRequisition *requisition)
2120 {
2121   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2122   GList *tmp_list;
2123
2124   /* we validate some rows initially just to make sure we have some size. 
2125    * In practice, with a lot of static lists, this should get a good width.
2126    */
2127   do_validate_rows (tree_view, FALSE);
2128   gtk_tree_view_size_request_columns (tree_view);
2129   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2130
2131   requisition->width = tree_view->priv->width;
2132   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2133
2134   tmp_list = tree_view->priv->children;
2135 }
2136
2137 static void
2138 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2139                                    gint      *minimum,
2140                                    gint      *natural)
2141 {
2142   GtkRequisition requisition;
2143
2144   gtk_tree_view_size_request (widget, &requisition);
2145
2146   *minimum = *natural = requisition.width;
2147 }
2148
2149 static void
2150 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2151                                     gint      *minimum,
2152                                     gint      *natural)
2153 {
2154   GtkRequisition requisition;
2155
2156   gtk_tree_view_size_request (widget, &requisition);
2157
2158   *minimum = *natural = requisition.height;
2159 }
2160
2161 static int
2162 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2163 {
2164   int width = 0;
2165   GList *list;
2166   gboolean rtl;
2167
2168   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2169   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2170        list->data != tree_view->priv->expander_column;
2171        list = (rtl ? list->prev : list->next))
2172     {
2173       GtkTreeViewColumn *column = list->data;
2174
2175       width += gtk_tree_view_column_get_width (column);
2176     }
2177
2178   return width;
2179 }
2180
2181 static void
2182 invalidate_column (GtkTreeView       *tree_view,
2183                    GtkTreeViewColumn *column)
2184 {
2185   gint column_offset = 0;
2186   GList *list;
2187   GtkWidget *widget = GTK_WIDGET (tree_view);
2188   gboolean rtl;
2189
2190   if (!gtk_widget_get_realized (widget))
2191     return;
2192
2193   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2194   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2195        list;
2196        list = (rtl ? list->prev : list->next))
2197     {
2198       GtkTreeViewColumn *tmpcolumn = list->data;
2199       if (tmpcolumn == column)
2200         {
2201           GtkAllocation allocation;
2202           GdkRectangle invalid_rect;
2203
2204           gtk_widget_get_allocation (widget, &allocation);
2205           invalid_rect.x = column_offset;
2206           invalid_rect.y = 0;
2207           invalid_rect.width = gtk_tree_view_column_get_width (column);
2208           invalid_rect.height = allocation.height;
2209
2210           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2211           break;
2212         }
2213
2214       column_offset += gtk_tree_view_column_get_width (tmpcolumn);
2215     }
2216 }
2217
2218 static void
2219 invalidate_last_column (GtkTreeView *tree_view)
2220 {
2221   GList *last_column;
2222   gboolean rtl;
2223
2224   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2225
2226   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2227        last_column;
2228        last_column = (rtl ? last_column->next : last_column->prev))
2229     {
2230       if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)))
2231         {
2232           invalidate_column (tree_view, last_column->data);
2233           return;
2234         }
2235     }
2236 }
2237
2238 static gint
2239 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2240                                                     GtkTreeViewColumn *column)
2241 {
2242   gint max_width, min_width;
2243   gint real_requested_width;
2244
2245   if (column->use_resized_width)
2246     {
2247       real_requested_width = column->resized_width;
2248     }
2249   else if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_FIXED)
2250     {
2251       real_requested_width = gtk_tree_view_column_get_fixed_width (column);
2252     }
2253   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2254     {
2255       real_requested_width = MAX (column->requested_width, column->button_request);
2256     }
2257   else
2258     {
2259       real_requested_width = column->requested_width;
2260       if (real_requested_width < 0)
2261         real_requested_width = 0;
2262     }
2263
2264   min_width = gtk_tree_view_column_get_min_width (column);
2265   if (min_width != -1)
2266     real_requested_width = MAX (real_requested_width, min_width);
2267
2268   max_width = gtk_tree_view_column_get_max_width (column);
2269   if (max_width != -1)
2270     real_requested_width = MIN (real_requested_width, max_width);
2271
2272   return real_requested_width;
2273 }
2274
2275 /* GtkWidget::size_allocate helper */
2276 static void
2277 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2278                                      gboolean  *width_changed)
2279 {
2280   GtkTreeView *tree_view;
2281   GList *list, *first_column, *last_column;
2282   GtkTreeViewColumn *column;
2283   GtkAllocation allocation;
2284   GtkAllocation widget_allocation;
2285   gint width = 0;
2286   gint extra, extra_per_column, extra_for_last;
2287   gint full_requested_width = 0;
2288   gint number_of_expand_columns = 0;
2289   gboolean column_changed = FALSE;
2290   gboolean rtl;
2291   gboolean update_expand;
2292   
2293   tree_view = GTK_TREE_VIEW (widget);
2294
2295   for (last_column = g_list_last (tree_view->priv->columns);
2296        last_column &&
2297        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2298        last_column = last_column->prev)
2299     ;
2300   if (last_column == NULL)
2301     return;
2302
2303   for (first_column = g_list_first (tree_view->priv->columns);
2304        first_column &&
2305        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2306        first_column = first_column->next)
2307     ;
2308
2309   allocation.y = 0;
2310   allocation.height = tree_view->priv->header_height;
2311
2312   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2313
2314   /* find out how many extra space and expandable columns we have */
2315   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2316     {
2317       column = (GtkTreeViewColumn *)list->data;
2318
2319       if (!gtk_tree_view_column_get_visible (column))
2320         continue;
2321
2322       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2323
2324       if (gtk_tree_view_column_get_expand (column))
2325         number_of_expand_columns++;
2326     }
2327
2328   /* Only update the expand value if the width of the widget has changed,
2329    * or the number of expand columns has changed, or if there are no expand
2330    * columns, or if we didn't have an size-allocation yet after the
2331    * last validated node.
2332    */
2333   update_expand = (width_changed && *width_changed == TRUE)
2334       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2335       || number_of_expand_columns == 0
2336       || tree_view->priv->post_validation_flag == TRUE;
2337
2338   tree_view->priv->post_validation_flag = FALSE;
2339
2340   gtk_widget_get_allocation (widget, &widget_allocation);
2341   if (!update_expand)
2342     {
2343       extra = tree_view->priv->last_extra_space;
2344       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2345     }
2346   else
2347     {
2348       extra = MAX (widget_allocation.width - full_requested_width, 0);
2349       extra_for_last = 0;
2350
2351       tree_view->priv->last_extra_space = extra;
2352     }
2353
2354   if (number_of_expand_columns > 0)
2355     extra_per_column = extra/number_of_expand_columns;
2356   else
2357     extra_per_column = 0;
2358
2359   if (update_expand)
2360     {
2361       tree_view->priv->last_extra_space_per_column = extra_per_column;
2362       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2363     }
2364
2365   for (list = (rtl ? last_column : first_column); 
2366        list != (rtl ? first_column->prev : last_column->next);
2367        list = (rtl ? list->prev : list->next)) 
2368     {
2369       gint real_requested_width = 0;
2370       gint old_width, column_width;
2371
2372       column = list->data;
2373       old_width = gtk_tree_view_column_get_width (column);
2374
2375       if (!gtk_tree_view_column_get_visible (column))
2376         continue;
2377
2378       /* We need to handle the dragged button specially.
2379        */
2380       if (column == tree_view->priv->drag_column)
2381         {
2382           GtkAllocation drag_allocation;
2383
2384           drag_allocation.x = 0;
2385           drag_allocation.y = 0;
2386           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2387           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2388           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2389                                     &drag_allocation);
2390           width += drag_allocation.width;
2391           continue;
2392         }
2393
2394       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2395
2396       allocation.x = width;
2397       column->width = real_requested_width;
2398
2399       if (gtk_tree_view_column_get_expand (column))
2400         {
2401           if (number_of_expand_columns == 1)
2402             {
2403               /* We add the remander to the last column as
2404                * */
2405               column->width += extra;
2406             }
2407           else
2408             {
2409               column->width += extra_per_column;
2410               extra -= extra_per_column;
2411               number_of_expand_columns --;
2412             }
2413         }
2414       else if (number_of_expand_columns == 0 &&
2415                list == last_column)
2416         {
2417           column->width += extra;
2418         }
2419
2420       /* In addition to expand, the last column can get even more
2421        * extra space so all available space is filled up.
2422        */
2423       if (extra_for_last > 0 && list == last_column)
2424         column->width += extra_for_last;
2425
2426       g_object_notify (G_OBJECT (column), "width");
2427
2428       column_width = gtk_tree_view_column_get_width (column);
2429       allocation.width = column_width;
2430       width += column_width;
2431
2432       if (column_width > old_width)
2433         column_changed = TRUE;
2434
2435       gtk_widget_size_allocate (column->button, &allocation);
2436
2437       if (column->window)
2438         gdk_window_move_resize (column->window,
2439                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2440                                 allocation.y,
2441                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2442     }
2443
2444   /* We change the width here.  The user might have been resizing columns,
2445    * so the total width of the tree view changes.
2446    */
2447   tree_view->priv->width = width;
2448   if (width_changed)
2449     *width_changed = TRUE;
2450
2451   if (column_changed)
2452     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2453 }
2454
2455
2456 static void
2457 gtk_tree_view_size_allocate (GtkWidget     *widget,
2458                              GtkAllocation *allocation)
2459 {
2460   GtkAllocation widget_allocation;
2461   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2462   GList *tmp_list;
2463   gboolean width_changed = FALSE;
2464   gint old_width;
2465
2466   gtk_widget_get_allocation (widget, &widget_allocation);
2467   old_width = widget_allocation.width;
2468   if (allocation->width != widget_allocation.width)
2469     width_changed = TRUE;
2470
2471   gtk_widget_set_allocation (widget, allocation);
2472
2473   tmp_list = tree_view->priv->children;
2474
2475   while (tmp_list)
2476     {
2477       GtkAllocation allocation;
2478
2479       GtkTreeViewChild *child = tmp_list->data;
2480       tmp_list = tmp_list->next;
2481
2482       /* totally ignore our child's requisition */
2483       allocation.x = child->x;
2484       allocation.y = child->y;
2485       allocation.width = child->width;
2486       allocation.height = child->height;
2487       gtk_widget_size_allocate (child->widget, &allocation);
2488     }
2489
2490   /* We size-allocate the columns first because the width of the
2491    * tree view (used in updating the adjustments below) might change.
2492    */
2493   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2494
2495   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2496   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2497                                 allocation->width);
2498   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2499                                      allocation->width * 0.9);
2500   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2501                                      allocation->width * 0.1);
2502   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2503   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2504                             MAX (tree_view->priv->hadjustment->page_size,
2505                                  tree_view->priv->width));
2506   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2507
2508   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2509     {
2510       if (allocation->width < tree_view->priv->width)
2511         {
2512           if (tree_view->priv->init_hadjust_value)
2513             {
2514               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2515                                         MAX (tree_view->priv->width -
2516                                              allocation->width, 0));
2517               tree_view->priv->init_hadjust_value = FALSE;
2518             }
2519           else if (allocation->width != old_width)
2520             {
2521               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2522                                         CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width,
2523                                                0,
2524                                                tree_view->priv->width - allocation->width));
2525             }
2526           else
2527             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2528                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value),
2529                                              0,
2530                                              tree_view->priv->width - allocation->width));
2531         }
2532       else
2533         {
2534           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2535           tree_view->priv->init_hadjust_value = TRUE;
2536         }
2537     }
2538   else
2539     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2540       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2541                                 MAX (tree_view->priv->width -
2542                                      allocation->width, 0));
2543
2544   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2545   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2546                                 allocation->height -
2547                                 TREE_VIEW_HEADER_HEIGHT (tree_view));
2548   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2549                                      tree_view->priv->vadjustment->page_size * 0.1);
2550   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2551                                      tree_view->priv->vadjustment->page_size * 0.9);
2552   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2553   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2554                             MAX (tree_view->priv->vadjustment->page_size,
2555                                  tree_view->priv->height));
2556   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2557
2558   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2559   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2560     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2561   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2562     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2563                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2564   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2565     gtk_tree_view_top_row_to_dy (tree_view);
2566   else
2567     gtk_tree_view_dy_to_top_row (tree_view);
2568   
2569   if (gtk_widget_get_realized (widget))
2570     {
2571       gdk_window_move_resize (gtk_widget_get_window (widget),
2572                               allocation->x, allocation->y,
2573                               allocation->width, allocation->height);
2574       gdk_window_move_resize (tree_view->priv->header_window,
2575                               - (gint) tree_view->priv->hadjustment->value,
2576                               0,
2577                               MAX (tree_view->priv->width, allocation->width),
2578                               tree_view->priv->header_height);
2579       gdk_window_move_resize (tree_view->priv->bin_window,
2580                               - (gint) tree_view->priv->hadjustment->value,
2581                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2582                               MAX (tree_view->priv->width, allocation->width),
2583                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2584     }
2585
2586   if (tree_view->priv->tree == NULL)
2587     invalidate_empty_focus (tree_view);
2588
2589   if (gtk_widget_get_realized (widget))
2590     {
2591       gboolean has_expand_column = FALSE;
2592       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2593         {
2594           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2595             {
2596               has_expand_column = TRUE;
2597               break;
2598             }
2599         }
2600
2601       if (width_changed && tree_view->priv->expander_column)
2602         {
2603           /* Might seem awkward, but is the best heuristic I could come up
2604            * with.  Only if the width of the columns before the expander
2605            * changes, we will update the prelight status.  It is this
2606            * width that makes the expander move vertically.  Always updating
2607            * prelight status causes trouble with hover selections.
2608            */
2609           gint width_before_expander;
2610
2611           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2612
2613           if (tree_view->priv->prev_width_before_expander
2614               != width_before_expander)
2615               update_prelight (tree_view,
2616                                tree_view->priv->event_last_x,
2617                                tree_view->priv->event_last_y);
2618
2619           tree_view->priv->prev_width_before_expander = width_before_expander;
2620         }
2621
2622       /* This little hack only works if we have an LTR locale, and no column has the  */
2623       if (width_changed)
2624         {
2625           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2626               ! has_expand_column)
2627             invalidate_last_column (tree_view);
2628           else
2629             gtk_widget_queue_draw (widget);
2630         }
2631     }
2632 }
2633
2634 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2635 static void
2636 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2637 {
2638   GtkWidget *widget = GTK_WIDGET (tree_view);
2639
2640   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2641     gtk_widget_grab_focus (widget);
2642   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2643 }
2644
2645 static inline gboolean
2646 row_is_separator (GtkTreeView *tree_view,
2647                   GtkTreeIter *iter,
2648                   GtkTreePath *path)
2649 {
2650   gboolean is_separator = FALSE;
2651
2652   if (tree_view->priv->row_separator_func)
2653     {
2654       GtkTreeIter tmpiter;
2655
2656       if (iter)
2657         tmpiter = *iter;
2658       else
2659         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2660
2661       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2662                                                           &tmpiter,
2663                                                           tree_view->priv->row_separator_data);
2664     }
2665
2666   return is_separator;
2667 }
2668
2669 static gboolean
2670 gtk_tree_view_button_press (GtkWidget      *widget,
2671                             GdkEventButton *event)
2672 {
2673   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2674   GList *list;
2675   GtkTreeViewColumn *column = NULL;
2676   gint i;
2677   GdkRectangle background_area;
2678   GdkRectangle cell_area;
2679   gint vertical_separator;
2680   gint horizontal_separator;
2681   gboolean path_is_selectable;
2682   gboolean rtl;
2683
2684   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2685   gtk_tree_view_stop_editing (tree_view, FALSE);
2686   gtk_widget_style_get (widget,
2687                         "vertical-separator", &vertical_separator,
2688                         "horizontal-separator", &horizontal_separator,
2689                         NULL);
2690
2691
2692   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2693    * we're done handling the button press.
2694    */
2695
2696   if (event->window == tree_view->priv->bin_window)
2697     {
2698       GtkRBNode *node;
2699       GtkRBTree *tree;
2700       GtkTreePath *path;
2701       gchar *path_string;
2702       gint depth;
2703       gint new_y;
2704       gint y_offset;
2705       gint dval;
2706       gint pre_val, aft_val;
2707       GtkTreeViewColumn *column = NULL;
2708       GtkCellRenderer *focus_cell = NULL;
2709       gint column_handled_click = FALSE;
2710       gboolean row_double_click = FALSE;
2711       gboolean rtl;
2712       gboolean node_selected;
2713
2714       /* Empty tree? */
2715       if (tree_view->priv->tree == NULL)
2716         {
2717           grab_focus_and_unset_draw_keyfocus (tree_view);
2718           return TRUE;
2719         }
2720
2721       /* are we in an arrow? */
2722       if (tree_view->priv->prelight_node &&
2723           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2724           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2725         {
2726           if (event->button == 1)
2727             {
2728               gtk_grab_add (widget);
2729               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2730               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2731               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2732                                               tree_view->priv->prelight_tree,
2733                                               tree_view->priv->prelight_node);
2734             }
2735
2736           grab_focus_and_unset_draw_keyfocus (tree_view);
2737           return TRUE;
2738         }
2739
2740       /* find the node that was clicked */
2741       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2742       if (new_y < 0)
2743         new_y = 0;
2744       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2745
2746       if (node == NULL)
2747         {
2748           /* We clicked in dead space */
2749           grab_focus_and_unset_draw_keyfocus (tree_view);
2750           return TRUE;
2751         }
2752
2753       /* Get the path and the node */
2754       path = _gtk_tree_view_find_path (tree_view, tree, node);
2755       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2756
2757       if (!path_is_selectable)
2758         {
2759           gtk_tree_path_free (path);
2760           grab_focus_and_unset_draw_keyfocus (tree_view);
2761           return TRUE;
2762         }
2763
2764       depth = gtk_tree_path_get_depth (path);
2765       background_area.y = y_offset + event->y;
2766       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2767       background_area.x = 0;
2768
2769
2770       /* Let the column have a chance at selecting it. */
2771       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2772       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2773            list; list = (rtl ? list->prev : list->next))
2774         {
2775           GtkTreeViewColumn *candidate = list->data;
2776
2777           if (!gtk_tree_view_column_get_visible (candidate))
2778             continue;
2779
2780           background_area.width = candidate->width;
2781           if ((background_area.x > (gint) event->x) ||
2782               (background_area.x + background_area.width <= (gint) event->x))
2783             {
2784               background_area.x += background_area.width;
2785               continue;
2786             }
2787
2788           /* we found the focus column */
2789           column = candidate;
2790           cell_area = background_area;
2791           cell_area.width -= horizontal_separator;
2792           cell_area.height -= vertical_separator;
2793           cell_area.x += horizontal_separator/2;
2794           cell_area.y += vertical_separator/2;
2795           if (gtk_tree_view_is_expander_column (tree_view, column))
2796             {
2797               if (!rtl)
2798                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2799               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2800
2801               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2802                 {
2803                   if (!rtl)
2804                     cell_area.x += depth * tree_view->priv->expander_size;
2805                   cell_area.width -= depth * tree_view->priv->expander_size;
2806                 }
2807             }
2808           break;
2809         }
2810
2811       if (column == NULL)
2812         {
2813           gtk_tree_path_free (path);
2814           grab_focus_and_unset_draw_keyfocus (tree_view);
2815           return FALSE;
2816         }
2817
2818       tree_view->priv->focus_column = column;
2819
2820       /* decide if we edit */
2821       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2822           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2823         {
2824           GtkTreePath *anchor;
2825           GtkTreeIter iter;
2826
2827           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2828           gtk_tree_view_column_cell_set_cell_data (column,
2829                                                    tree_view->priv->model,
2830                                                    &iter,
2831                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2832                                                    node->children?TRUE:FALSE);
2833
2834           if (tree_view->priv->anchor)
2835             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2836           else
2837             anchor = NULL;
2838
2839           if ((anchor && !gtk_tree_path_compare (anchor, path))
2840               || !_gtk_tree_view_column_has_editable_cell (column))
2841             {
2842               GtkCellEditable *cell_editable = NULL;
2843
2844               /* FIXME: get the right flags */
2845               guint flags = 0;
2846
2847               path_string = gtk_tree_path_to_string (path);
2848
2849               if (_gtk_tree_view_column_cell_event (column,
2850                                                     &cell_editable,
2851                                                     (GdkEvent *)event,
2852                                                     path_string,
2853                                                     &background_area,
2854                                                     &cell_area, flags))
2855                 {
2856                   if (cell_editable != NULL)
2857                     {
2858                       gint left, right;
2859                       GdkRectangle area;
2860
2861                       area = cell_area;
2862                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2863
2864                       area.x += left;
2865                       area.width -= right + left;
2866
2867                       gtk_tree_view_real_start_editing (tree_view,
2868                                                         column,
2869                                                         path,
2870                                                         cell_editable,
2871                                                         &area,
2872                                                         (GdkEvent *)event,
2873                                                         flags);
2874                       g_free (path_string);
2875                       gtk_tree_path_free (path);
2876                       gtk_tree_path_free (anchor);
2877                       return TRUE;
2878                     }
2879                   column_handled_click = TRUE;
2880                 }
2881               g_free (path_string);
2882             }
2883           if (anchor)
2884             gtk_tree_path_free (anchor);
2885         }
2886
2887       /* select */
2888       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2889       pre_val = tree_view->priv->vadjustment->value;
2890
2891       /* we only handle selection modifications on the first button press
2892        */
2893       if (event->type == GDK_BUTTON_PRESS)
2894         {
2895           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2896             tree_view->priv->ctrl_pressed = TRUE;
2897           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2898             tree_view->priv->shift_pressed = TRUE;
2899
2900           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2901           if (focus_cell)
2902             gtk_tree_view_column_focus_cell (column, focus_cell);
2903
2904           if (event->state & GDK_CONTROL_MASK)
2905             {
2906               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2907               gtk_tree_view_real_toggle_cursor_row (tree_view);
2908             }
2909           else if (event->state & GDK_SHIFT_MASK)
2910             {
2911               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2912               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2913             }
2914           else
2915             {
2916               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2917             }
2918
2919           tree_view->priv->ctrl_pressed = FALSE;
2920           tree_view->priv->shift_pressed = FALSE;
2921         }
2922
2923       /* the treeview may have been scrolled because of _set_cursor,
2924        * correct here
2925        */
2926
2927       aft_val = tree_view->priv->vadjustment->value;
2928       dval = pre_val - aft_val;
2929
2930       cell_area.y += dval;
2931       background_area.y += dval;
2932
2933       /* Save press to possibly begin a drag
2934        */
2935       if (!column_handled_click &&
2936           !tree_view->priv->in_grab &&
2937           tree_view->priv->pressed_button < 0)
2938         {
2939           tree_view->priv->pressed_button = event->button;
2940           tree_view->priv->press_start_x = event->x;
2941           tree_view->priv->press_start_y = event->y;
2942
2943           if (tree_view->priv->rubber_banding_enable
2944               && !node_selected
2945               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2946             {
2947               tree_view->priv->press_start_y += tree_view->priv->dy;
2948               tree_view->priv->rubber_band_x = event->x;
2949               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2950               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2951
2952               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2953                 tree_view->priv->rubber_band_ctrl = TRUE;
2954               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2955                 tree_view->priv->rubber_band_shift = TRUE;
2956             }
2957         }
2958
2959       /* Test if a double click happened on the same row. */
2960       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2961         {
2962           int double_click_time, double_click_distance;
2963
2964           g_object_get (gtk_settings_get_default (),
2965                         "gtk-double-click-time", &double_click_time,
2966                         "gtk-double-click-distance", &double_click_distance,
2967                         NULL);
2968
2969           /* Same conditions as _gdk_event_button_generate */
2970           if (tree_view->priv->last_button_x != -1 &&
2971               (event->time < tree_view->priv->last_button_time + double_click_time) &&
2972               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2973               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2974             {
2975               /* We do no longer compare paths of this row and the
2976                * row clicked previously.  We use the double click
2977                * distance to decide whether this is a valid click,
2978                * allowing the mouse to slightly move over another row.
2979                */
2980               row_double_click = TRUE;
2981
2982               tree_view->priv->last_button_time = 0;
2983               tree_view->priv->last_button_x = -1;
2984               tree_view->priv->last_button_y = -1;
2985             }
2986           else
2987             {
2988               tree_view->priv->last_button_time = event->time;
2989               tree_view->priv->last_button_x = event->x;
2990               tree_view->priv->last_button_y = event->y;
2991             }
2992         }
2993
2994       if (row_double_click)
2995         {
2996           gtk_grab_remove (widget);
2997           gtk_tree_view_row_activated (tree_view, path, column);
2998
2999           if (tree_view->priv->pressed_button == event->button)
3000             tree_view->priv->pressed_button = -1;
3001         }
3002
3003       gtk_tree_path_free (path);
3004
3005       /* If we activated the row through a double click we don't want to grab
3006        * focus back, as moving focus to another widget is pretty common.
3007        */
3008       if (!row_double_click)
3009         grab_focus_and_unset_draw_keyfocus (tree_view);
3010
3011       return TRUE;
3012     }
3013
3014   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3015    */
3016   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3017     {
3018       column = list->data;
3019       if (event->window == column->window &&
3020           gtk_tree_view_column_get_resizable (column) &&
3021           column->window)
3022         {
3023           GtkAllocation button_allocation;
3024           gpointer drag_data;
3025
3026           if (event->type == GDK_2BUTTON_PRESS &&
3027               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3028             {
3029               column->use_resized_width = FALSE;
3030               _gtk_tree_view_column_autosize (tree_view, column);
3031               return TRUE;
3032             }
3033
3034           if (gdk_pointer_grab (column->window, FALSE,
3035                                 GDK_POINTER_MOTION_HINT_MASK |
3036                                 GDK_BUTTON1_MOTION_MASK |
3037                                 GDK_BUTTON_RELEASE_MASK,
3038                                 NULL, NULL, event->time))
3039             return FALSE;
3040
3041           gtk_grab_add (widget);
3042           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3043           column->resized_width = gtk_tree_view_column_get_width (column) -
3044                                   tree_view->priv->last_extra_space_per_column;
3045
3046           /* block attached dnd signal handler */
3047           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3048           if (drag_data)
3049             g_signal_handlers_block_matched (widget,
3050                                              G_SIGNAL_MATCH_DATA,
3051                                              0, 0, NULL, NULL,
3052                                              drag_data);
3053
3054           gtk_widget_get_allocation (column->button, &button_allocation);
3055           tree_view->priv->drag_pos = i;
3056           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
3057
3058           if (!gtk_widget_has_focus (widget))
3059             gtk_widget_grab_focus (widget);
3060
3061           return TRUE;
3062         }
3063     }
3064   return FALSE;
3065 }
3066
3067 /* GtkWidget::button_release_event helper */
3068 static gboolean
3069 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3070                                           GdkEventButton *event)
3071 {
3072   GtkTreeView *tree_view;
3073   GList *l;
3074   gboolean rtl;
3075
3076   tree_view = GTK_TREE_VIEW (widget);
3077
3078   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3079   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
3080   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
3081
3082   /* Move the button back */
3083   g_object_ref (tree_view->priv->drag_column->button);
3084   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
3085   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
3086   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
3087   g_object_unref (tree_view->priv->drag_column->button);
3088   gtk_widget_queue_resize (widget);
3089   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3090     {
3091       gdk_window_raise (tree_view->priv->drag_column->window);
3092       gdk_window_show (tree_view->priv->drag_column->window);
3093     }
3094   else
3095     gdk_window_hide (tree_view->priv->drag_column->window);
3096
3097   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
3098
3099   if (rtl)
3100     {
3101       if (tree_view->priv->cur_reorder &&
3102           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3103         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3104                                          tree_view->priv->cur_reorder->right_column);
3105     }
3106   else
3107     {
3108       if (tree_view->priv->cur_reorder &&
3109           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3110         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3111                                          tree_view->priv->cur_reorder->left_column);
3112     }
3113   tree_view->priv->drag_column = NULL;
3114   gdk_window_hide (tree_view->priv->drag_window);
3115
3116   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3117     g_slice_free (GtkTreeViewColumnReorder, l->data);
3118   g_list_free (tree_view->priv->column_drag_info);
3119   tree_view->priv->column_drag_info = NULL;
3120   tree_view->priv->cur_reorder = NULL;
3121
3122   if (tree_view->priv->drag_highlight_window)
3123     gdk_window_hide (tree_view->priv->drag_highlight_window);
3124
3125   /* Reset our flags */
3126   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3127   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
3128
3129   return TRUE;
3130 }
3131
3132 /* GtkWidget::button_release_event helper */
3133 static gboolean
3134 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3135                                             GdkEventButton *event)
3136 {
3137   GtkTreeView *tree_view;
3138   gpointer drag_data;
3139
3140   tree_view = GTK_TREE_VIEW (widget);
3141
3142   tree_view->priv->drag_pos = -1;
3143
3144   /* unblock attached dnd signal handler */
3145   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3146   if (drag_data)
3147     g_signal_handlers_unblock_matched (widget,
3148                                        G_SIGNAL_MATCH_DATA,
3149                                        0, 0, NULL, NULL,
3150                                        drag_data);
3151
3152   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3153   gtk_grab_remove (widget);
3154   gdk_display_pointer_ungrab (gdk_window_get_display (event->window),
3155                               event->time);
3156   return TRUE;
3157 }
3158
3159 static gboolean
3160 gtk_tree_view_button_release (GtkWidget      *widget,
3161                               GdkEventButton *event)
3162 {
3163   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3164
3165   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3166     return gtk_tree_view_button_release_drag_column (widget, event);
3167
3168   if (tree_view->priv->rubber_band_status)
3169     gtk_tree_view_stop_rubber_band (tree_view);
3170
3171   if (tree_view->priv->pressed_button == event->button)
3172     tree_view->priv->pressed_button = -1;
3173
3174   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3175     return gtk_tree_view_button_release_column_resize (widget, event);
3176
3177   if (tree_view->priv->button_pressed_node == NULL)
3178     return FALSE;
3179
3180   if (event->button == 1)
3181     {
3182       gtk_grab_remove (widget);
3183       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3184           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3185         {
3186           GtkTreePath *path = NULL;
3187
3188           path = _gtk_tree_view_find_path (tree_view,
3189                                            tree_view->priv->button_pressed_tree,
3190                                            tree_view->priv->button_pressed_node);
3191           /* Actually activate the node */
3192           if (tree_view->priv->button_pressed_node->children == NULL)
3193             gtk_tree_view_real_expand_row (tree_view, path,
3194                                            tree_view->priv->button_pressed_tree,
3195                                            tree_view->priv->button_pressed_node,
3196                                            FALSE, TRUE);
3197           else
3198             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3199                                              tree_view->priv->button_pressed_tree,
3200                                              tree_view->priv->button_pressed_node, TRUE);
3201           gtk_tree_path_free (path);
3202         }
3203
3204       tree_view->priv->button_pressed_tree = NULL;
3205       tree_view->priv->button_pressed_node = NULL;
3206     }
3207
3208   return TRUE;
3209 }
3210
3211 static gboolean
3212 gtk_tree_view_grab_broken (GtkWidget          *widget,
3213                            GdkEventGrabBroken *event)
3214 {
3215   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3216
3217   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3218     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3219
3220   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3221     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3222
3223   return TRUE;
3224 }
3225
3226 #if 0
3227 static gboolean
3228 gtk_tree_view_configure (GtkWidget *widget,
3229                          GdkEventConfigure *event)
3230 {
3231   GtkTreeView *tree_view;
3232
3233   tree_view = GTK_TREE_VIEW (widget);
3234   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3235
3236   return FALSE;
3237 }
3238 #endif
3239
3240 /* GtkWidget::motion_event function set.
3241  */
3242
3243 static gboolean
3244 coords_are_over_arrow (GtkTreeView *tree_view,
3245                        GtkRBTree   *tree,
3246                        GtkRBNode   *node,
3247                        /* these are in bin window coords */
3248                        gint         x,
3249                        gint         y)
3250 {
3251   GdkRectangle arrow;
3252   gint x2;
3253
3254   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3255     return FALSE;
3256
3257   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3258     return FALSE;
3259
3260   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3261
3262   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3263
3264   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3265
3266   arrow.width = x2 - arrow.x;
3267
3268   return (x >= arrow.x &&
3269           x < (arrow.x + arrow.width) &&
3270           y >= arrow.y &&
3271           y < (arrow.y + arrow.height));
3272 }
3273
3274 static gboolean
3275 auto_expand_timeout (gpointer data)
3276 {
3277   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3278   GtkTreePath *path;
3279
3280   if (tree_view->priv->prelight_node)
3281     {
3282       path = _gtk_tree_view_find_path (tree_view,
3283                                        tree_view->priv->prelight_tree,
3284                                        tree_view->priv->prelight_node);   
3285
3286       if (tree_view->priv->prelight_node->children)
3287         gtk_tree_view_collapse_row (tree_view, path);
3288       else
3289         gtk_tree_view_expand_row (tree_view, path, FALSE);
3290
3291       gtk_tree_path_free (path);
3292     }
3293
3294   tree_view->priv->auto_expand_timeout = 0;
3295
3296   return FALSE;
3297 }
3298
3299 static void
3300 remove_auto_expand_timeout (GtkTreeView *tree_view)
3301 {
3302   if (tree_view->priv->auto_expand_timeout != 0)
3303     {
3304       g_source_remove (tree_view->priv->auto_expand_timeout);
3305       tree_view->priv->auto_expand_timeout = 0;
3306     }
3307 }
3308
3309 static void
3310 do_prelight (GtkTreeView *tree_view,
3311              GtkRBTree   *tree,
3312              GtkRBNode   *node,
3313              /* these are in bin_window coords */
3314              gint         x,
3315              gint         y)
3316 {
3317   if (tree_view->priv->prelight_tree == tree &&
3318       tree_view->priv->prelight_node == node)
3319     {
3320       /*  We are still on the same node,
3321           but we might need to take care of the arrow  */
3322
3323       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3324         {
3325           gboolean over_arrow;
3326           gboolean flag_set;
3327
3328           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3329           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3330                                              GTK_TREE_VIEW_ARROW_PRELIT);
3331
3332           if (over_arrow != flag_set)
3333             {
3334               if (over_arrow)
3335                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3336                                         GTK_TREE_VIEW_ARROW_PRELIT);
3337               else
3338                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3339                                           GTK_TREE_VIEW_ARROW_PRELIT);
3340
3341               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3342             }
3343         }
3344
3345       return;
3346     }
3347
3348   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3349     {
3350       /*  Unprelight the old node and arrow  */
3351
3352       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3353                              GTK_RBNODE_IS_PRELIT);
3354
3355       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3356           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3357         {
3358           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3359           
3360           gtk_tree_view_queue_draw_arrow (tree_view,
3361                                           tree_view->priv->prelight_tree,
3362                                           tree_view->priv->prelight_node);
3363         }
3364
3365       _gtk_tree_view_queue_draw_node (tree_view,
3366                                       tree_view->priv->prelight_tree,
3367                                       tree_view->priv->prelight_node,
3368                                       NULL);
3369     }
3370
3371
3372   if (tree_view->priv->hover_expand)
3373     remove_auto_expand_timeout (tree_view);
3374
3375   /*  Set the new prelight values  */
3376   tree_view->priv->prelight_node = node;
3377   tree_view->priv->prelight_tree = tree;
3378
3379   if (!node || !tree)
3380     return;
3381
3382   /*  Prelight the new node and arrow  */
3383
3384   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3385       && coords_are_over_arrow (tree_view, tree, node, x, y))
3386     {
3387       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3388
3389       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3390     }
3391
3392   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3393
3394   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3395
3396   if (tree_view->priv->hover_expand)
3397     {
3398       tree_view->priv->auto_expand_timeout = 
3399         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3400     }
3401 }
3402
3403 static void
3404 prelight_or_select (GtkTreeView *tree_view,
3405                     GtkRBTree   *tree,
3406                     GtkRBNode   *node,
3407                     /* these are in bin_window coords */
3408                     gint         x,
3409                     gint         y)
3410 {
3411   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3412   
3413   if (tree_view->priv->hover_selection &&
3414       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3415       !(tree_view->priv->edited_column &&
3416         tree_view->priv->edited_column->editable_widget))
3417     {
3418       if (node)
3419         {
3420           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3421             {
3422               GtkTreePath *path;
3423               
3424               path = _gtk_tree_view_find_path (tree_view, tree, node);
3425               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3426               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3427                 {
3428                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3429                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3430                 }
3431               gtk_tree_path_free (path);
3432             }
3433         }
3434
3435       else if (mode == GTK_SELECTION_SINGLE)
3436         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3437     }
3438
3439     do_prelight (tree_view, tree, node, x, y);
3440 }
3441
3442 static void
3443 ensure_unprelighted (GtkTreeView *tree_view)
3444 {
3445   do_prelight (tree_view,
3446                NULL, NULL,
3447                -1000, -1000); /* coords not possibly over an arrow */
3448
3449   g_assert (tree_view->priv->prelight_node == NULL);
3450 }
3451
3452 static void
3453 update_prelight (GtkTreeView *tree_view,
3454                  gint         x,
3455                  gint         y)
3456 {
3457   int new_y;
3458   GtkRBTree *tree;
3459   GtkRBNode *node;
3460
3461   if (tree_view->priv->tree == NULL)
3462     return;
3463
3464   if (x == -10000)
3465     {
3466       ensure_unprelighted (tree_view);
3467       return;
3468     }
3469
3470   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3471   if (new_y < 0)
3472     new_y = 0;
3473
3474   _gtk_rbtree_find_offset (tree_view->priv->tree,
3475                            new_y, &tree, &node);
3476
3477   if (node)
3478     prelight_or_select (tree_view, tree, node, x, y);
3479 }
3480
3481
3482
3483
3484 /* Our motion arrow is either a box (in the case of the original spot)
3485  * or an arrow.  It is expander_size wide.
3486  */
3487 /*
3488  * 11111111111111
3489  * 01111111111110
3490  * 00111111111100
3491  * 00011111111000
3492  * 00001111110000
3493  * 00000111100000
3494  * 00000111100000
3495  * 00000111100000
3496  * ~ ~ ~ ~ ~ ~ ~
3497  * 00000111100000
3498  * 00000111100000
3499  * 00000111100000
3500  * 00001111110000
3501  * 00011111111000
3502  * 00111111111100
3503  * 01111111111110
3504  * 11111111111111
3505  */
3506
3507 static void
3508 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3509 {
3510   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3511   GtkWidget *widget = GTK_WIDGET (tree_view);
3512   cairo_surface_t *mask_image;
3513   cairo_region_t *mask_region;
3514   gint x;
3515   gint y;
3516   gint width;
3517   gint height;
3518   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3519   GdkWindowAttr attributes;
3520   guint attributes_mask;
3521   cairo_t *cr;
3522
3523   if (!reorder ||
3524       reorder->left_column == tree_view->priv->drag_column ||
3525       reorder->right_column == tree_view->priv->drag_column)
3526     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3527   else if (reorder->left_column || reorder->right_column)
3528     {
3529       GtkAllocation left_allocation, right_allocation;
3530       GdkRectangle visible_rect;
3531
3532       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3533       if (reorder->left_column)
3534         {
3535           gtk_widget_get_allocation (reorder->left_column->button, &left_allocation);
3536           x = left_allocation.x + left_allocation.width;
3537         }
3538       else
3539         {
3540           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
3541           x = right_allocation.x;
3542         }
3543
3544       if (x < visible_rect.x)
3545         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3546       else if (x > visible_rect.x + visible_rect.width)
3547         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3548       else
3549         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3550     }
3551
3552   /* We want to draw the rectangle over the initial location. */
3553   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3554     {
3555       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3556         {
3557           GtkAllocation drag_allocation;
3558
3559           if (tree_view->priv->drag_highlight_window)
3560             {
3561               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3562                                         NULL);
3563               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3564             }
3565
3566           attributes.window_type = GDK_WINDOW_CHILD;
3567           attributes.wclass = GDK_INPUT_OUTPUT;
3568           attributes.x = tree_view->priv->drag_column_x;
3569           attributes.y = 0;
3570           gtk_widget_get_allocation (tree_view->priv->drag_column->button, &drag_allocation);
3571           width = attributes.width = drag_allocation.width;
3572           height = attributes.height = drag_allocation.height;
3573           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3574           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3575           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3576           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3577           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3578
3579           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3580           cr = cairo_create (mask_image);
3581
3582           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3583           cairo_stroke (cr);
3584           cairo_destroy (cr);
3585
3586           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3587           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3588                                            mask_region, 0, 0);
3589
3590           cairo_region_destroy (mask_region);
3591           cairo_surface_destroy (mask_image);
3592
3593           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3594         }
3595     }
3596   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3597     {
3598       GtkAllocation button_allocation;
3599
3600       width = tree_view->priv->expander_size;
3601
3602       /* Get x, y, width, height of arrow */
3603       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3604       if (reorder->left_column)
3605         {
3606           gtk_widget_get_allocation (reorder->left_column->button, &button_allocation);
3607           x += button_allocation.x + button_allocation.width - width/2;
3608           height = button_allocation.height;
3609         }
3610       else
3611         {
3612           gtk_widget_get_allocation (reorder->right_column->button, &button_allocation);
3613           x += button_allocation.x - width/2;
3614           height = button_allocation.height;
3615         }
3616       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3617       height += tree_view->priv->expander_size;
3618
3619       /* Create the new window */
3620       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3621         {
3622           if (tree_view->priv->drag_highlight_window)
3623             {
3624               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3625                                         NULL);
3626               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3627             }
3628
3629           attributes.window_type = GDK_WINDOW_TEMP;
3630           attributes.wclass = GDK_INPUT_OUTPUT;
3631           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3632           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3633           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3634           attributes.x = x;
3635           attributes.y = y;
3636           attributes.width = width;
3637           attributes.height = height;
3638           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3639                                                                    &attributes, attributes_mask);
3640           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3641
3642           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3643
3644           cr = cairo_create (mask_image);
3645           cairo_move_to (cr, 0, 0);
3646           cairo_line_to (cr, width, 0);
3647           cairo_line_to (cr, width / 2., width / 2);
3648           cairo_move_to (cr, 0, height);
3649           cairo_line_to (cr, width, height);
3650           cairo_line_to (cr, width / 2., height - width / 2.);
3651           cairo_fill (cr);
3652           cairo_destroy (cr);
3653
3654           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3655           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3656                                            mask_region, 0, 0);
3657
3658           cairo_region_destroy (mask_region);
3659           cairo_surface_destroy (mask_image);
3660         }
3661
3662       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3663       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3664     }
3665   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3666            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3667     {
3668       GtkAllocation allocation;
3669
3670       width = tree_view->priv->expander_size;
3671
3672       /* Get x, y, width, height of arrow */
3673       width = width/2; /* remember, the arrow only takes half the available width */
3674       gdk_window_get_origin (gtk_widget_get_window (widget),
3675                              &x, &y);
3676       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3677         {
3678           gtk_widget_get_allocation (widget, &allocation);
3679           x += allocation.width - width;
3680         }
3681
3682       if (reorder->left_column)
3683         {
3684           gtk_widget_get_allocation (reorder->left_column->button, &allocation);
3685           height = allocation.height;
3686         }
3687       else
3688         {
3689           gtk_widget_get_allocation (reorder->right_column->button, &allocation);
3690           height = allocation.height;
3691         }
3692
3693       y -= tree_view->priv->expander_size;
3694       height += 2*tree_view->priv->expander_size;
3695
3696       /* Create the new window */
3697       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3698           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3699         {
3700           if (tree_view->priv->drag_highlight_window)
3701             {
3702               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3703                                         NULL);
3704               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3705             }
3706
3707           attributes.window_type = GDK_WINDOW_TEMP;
3708           attributes.wclass = GDK_INPUT_OUTPUT;
3709           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3710           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3711           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3712           attributes.x = x;
3713           attributes.y = y;
3714           attributes.width = width;
3715           attributes.height = height;
3716           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3717           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3718
3719           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3720
3721           cr = cairo_create (mask_image);
3722           /* mirror if we're on the left */
3723           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3724             {
3725               cairo_translate (cr, width, 0);
3726               cairo_scale (cr, -1, 1);
3727             }
3728           cairo_move_to (cr, 0, 0);
3729           cairo_line_to (cr, width, width);
3730           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3731           cairo_move_to (cr, 0, height);
3732           cairo_line_to (cr, width, height - width);
3733           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3734           cairo_fill (cr);
3735           cairo_destroy (cr);
3736
3737           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3738           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3739                                            mask_region, 0, 0);
3740
3741           cairo_region_destroy (mask_region);
3742           cairo_surface_destroy (mask_image);
3743         }
3744
3745       tree_view->priv->drag_column_window_state = arrow_type;
3746       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3747    }
3748   else
3749     {
3750       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3751       gdk_window_hide (tree_view->priv->drag_highlight_window);
3752       return;
3753     }
3754
3755   gdk_window_show (tree_view->priv->drag_highlight_window);
3756   gdk_window_raise (tree_view->priv->drag_highlight_window);
3757 }
3758
3759 static gboolean
3760 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3761                                     GdkEventMotion *event)
3762 {
3763   gint x;
3764   gint new_width;
3765   GtkTreeViewColumn *column;
3766   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3767
3768   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3769
3770   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3771     gtk_widget_get_pointer (widget, &x, NULL);
3772   else
3773     x = event->x;
3774
3775   if (tree_view->priv->hadjustment)
3776     x += tree_view->priv->hadjustment->value;
3777
3778   new_width = gtk_tree_view_new_column_width (tree_view,
3779                                               tree_view->priv->drag_pos, &x);
3780   if (x != tree_view->priv->x_drag &&
3781       (new_width != gtk_tree_view_column_get_fixed_width (column)))
3782     {
3783       column->use_resized_width = TRUE;
3784       column->resized_width = new_width;
3785       if (gtk_tree_view_column_get_expand (column))
3786         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3787       gtk_widget_queue_resize (widget);
3788     }
3789
3790   return FALSE;
3791 }
3792
3793
3794 static void
3795 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3796 {
3797   GtkTreeViewColumnReorder *reorder = NULL;
3798   GList *list;
3799   gint mouse_x;
3800
3801   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3802   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3803     {
3804       reorder = (GtkTreeViewColumnReorder *) list->data;
3805       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3806         break;
3807       reorder = NULL;
3808     }
3809
3810   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3811       return;*/
3812
3813   tree_view->priv->cur_reorder = reorder;
3814   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3815 }
3816
3817 static void
3818 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3819 {
3820   GdkRectangle visible_rect;
3821   gint y;
3822   gint offset;
3823
3824   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3825   y += tree_view->priv->dy;
3826
3827   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3828
3829   /* see if we are near the edge. */
3830   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3831   if (offset > 0)
3832     {
3833       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3834       if (offset < 0)
3835         return;
3836     }
3837
3838   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3839                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3840 }
3841
3842 static gboolean
3843 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3844 {
3845   GdkRectangle visible_rect;
3846   gint x;
3847   gint offset;
3848
3849   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3850
3851   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3852
3853   /* See if we are near the edge. */
3854   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3855   if (offset > 0)
3856     {
3857       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3858       if (offset < 0)
3859         return TRUE;
3860     }
3861   offset = offset/3;
3862
3863   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3864                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3865
3866   return TRUE;
3867
3868 }
3869
3870 static gboolean
3871 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3872                                   GdkEventMotion *event)
3873 {
3874   GtkAllocation allocation, button_allocation;
3875   GtkTreeView *tree_view = (GtkTreeView *) widget;
3876   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3877   gint x, y;
3878
3879   /* Sanity Check */
3880   if ((column == NULL) ||
3881       (event->window != tree_view->priv->drag_window))
3882     return FALSE;
3883
3884   /* Handle moving the header */
3885   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3886   gtk_widget_get_allocation (widget, &allocation);
3887   gtk_widget_get_allocation (column->button, &button_allocation);
3888   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3889              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
3890   gdk_window_move (tree_view->priv->drag_window, x, y);
3891   
3892   /* autoscroll, if needed */
3893   gtk_tree_view_horizontal_autoscroll (tree_view);
3894   /* Update the current reorder position and arrow; */
3895   gtk_tree_view_update_current_reorder (tree_view);
3896
3897   return TRUE;
3898 }
3899
3900 static void
3901 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3902 {
3903   remove_scroll_timeout (tree_view);
3904   gtk_grab_remove (GTK_WIDGET (tree_view));
3905
3906   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3907     {
3908       GtkTreePath *tmp_path;
3909
3910       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3911
3912       /* The anchor path should be set to the start path */
3913       tmp_path = _gtk_tree_view_find_path (tree_view,
3914                                            tree_view->priv->rubber_band_start_tree,
3915                                            tree_view->priv->rubber_band_start_node);
3916
3917       if (tree_view->priv->anchor)
3918         gtk_tree_row_reference_free (tree_view->priv->anchor);
3919
3920       tree_view->priv->anchor =
3921         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3922                                           tree_view->priv->model,
3923                                           tmp_path);
3924
3925       gtk_tree_path_free (tmp_path);
3926
3927       /* ... and the cursor to the end path */
3928       tmp_path = _gtk_tree_view_find_path (tree_view,
3929                                            tree_view->priv->rubber_band_end_tree,
3930                                            tree_view->priv->rubber_band_end_node);
3931       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3932       gtk_tree_path_free (tmp_path);
3933
3934       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3935     }
3936
3937   /* Clear status variables */
3938   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3939   tree_view->priv->rubber_band_shift = 0;
3940   tree_view->priv->rubber_band_ctrl = 0;
3941
3942   tree_view->priv->rubber_band_start_node = NULL;
3943   tree_view->priv->rubber_band_start_tree = NULL;
3944   tree_view->priv->rubber_band_end_node = NULL;
3945   tree_view->priv->rubber_band_end_tree = NULL;
3946 }
3947
3948 static void
3949 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3950                                                  GtkRBTree   *start_tree,
3951                                                  GtkRBNode   *start_node,
3952                                                  GtkRBTree   *end_tree,
3953                                                  GtkRBNode   *end_node,
3954                                                  gboolean     select,
3955                                                  gboolean     skip_start,
3956                                                  gboolean     skip_end)
3957 {
3958   if (start_node == end_node)
3959     return;
3960
3961   /* We skip the first node and jump inside the loop */
3962   if (skip_start)
3963     goto skip_first;
3964
3965   do
3966     {
3967       /* Small optimization by assuming insensitive nodes are never
3968        * selected.
3969        */
3970       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3971         {
3972           GtkTreePath *path;
3973           gboolean selectable;
3974
3975           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3976           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3977           gtk_tree_path_free (path);
3978
3979           if (!selectable)
3980             goto node_not_selectable;
3981         }
3982
3983       if (select)
3984         {
3985           if (tree_view->priv->rubber_band_shift)
3986             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3987           else if (tree_view->priv->rubber_band_ctrl)
3988             {
3989               /* Toggle the selection state */
3990               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3991                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3992               else
3993                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3994             }
3995           else
3996             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3997         }
3998       else
3999         {
4000           /* Mirror the above */
4001           if (tree_view->priv->rubber_band_shift)
4002             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4003           else if (tree_view->priv->rubber_band_ctrl)
4004             {
4005               /* Toggle the selection state */
4006               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4007                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4008               else
4009                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4010             }
4011           else
4012             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4013         }
4014
4015       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4016
4017 node_not_selectable:
4018       if (start_node == end_node)
4019         break;
4020
4021 skip_first:
4022
4023       if (start_node->children)
4024         {
4025           start_tree = start_node->children;
4026           start_node = start_tree->root;
4027           while (start_node->left != start_tree->nil)
4028             start_node = start_node->left;
4029         }
4030       else
4031         {
4032           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4033
4034           if (!start_tree)
4035             /* Ran out of tree */
4036             break;
4037         }
4038
4039       if (skip_end && start_node == end_node)
4040         break;
4041     }
4042   while (TRUE);
4043 }
4044
4045 static void
4046 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4047 {
4048   GtkRBTree *start_tree, *end_tree;
4049   GtkRBNode *start_node, *end_node;
4050
4051   _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);
4052   _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);
4053
4054   /* Handle the start area first */
4055   if (!tree_view->priv->rubber_band_start_node)
4056     {
4057       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4058                                                        start_tree,
4059                                                        start_node,
4060                                                        end_tree,
4061                                                        end_node,
4062                                                        TRUE,
4063                                                        FALSE,
4064                                                        FALSE);
4065     }
4066   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4067            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4068     {
4069       /* New node is above the old one; selection became bigger */
4070       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4071                                                        start_tree,
4072                                                        start_node,
4073                                                        tree_view->priv->rubber_band_start_tree,
4074                                                        tree_view->priv->rubber_band_start_node,
4075                                                        TRUE,
4076                                                        FALSE,
4077                                                        TRUE);
4078     }
4079   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4080            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4081     {
4082       /* New node is below the old one; selection became smaller */
4083       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4084                                                        tree_view->priv->rubber_band_start_tree,
4085                                                        tree_view->priv->rubber_band_start_node,
4086                                                        start_tree,
4087                                                        start_node,
4088                                                        FALSE,
4089                                                        FALSE,
4090                                                        TRUE);
4091     }
4092
4093   tree_view->priv->rubber_band_start_tree = start_tree;
4094   tree_view->priv->rubber_band_start_node = start_node;
4095
4096   /* Next, handle the end area */
4097   if (!tree_view->priv->rubber_band_end_node)
4098     {
4099       /* In the event this happens, start_node was also NULL; this case is
4100        * handled above.
4101        */
4102     }
4103   else if (!end_node)
4104     {
4105       /* Find the last node in the tree */
4106       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4107                                &end_tree, &end_node);
4108
4109       /* Selection reached end of the tree */
4110       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4111                                                        tree_view->priv->rubber_band_end_tree,
4112                                                        tree_view->priv->rubber_band_end_node,
4113                                                        end_tree,
4114                                                        end_node,
4115                                                        TRUE,
4116                                                        TRUE,
4117                                                        FALSE);
4118     }
4119   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4120            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4121     {
4122       /* New node is below the old one; selection became bigger */
4123       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4124                                                        tree_view->priv->rubber_band_end_tree,
4125                                                        tree_view->priv->rubber_band_end_node,
4126                                                        end_tree,
4127                                                        end_node,
4128                                                        TRUE,
4129                                                        TRUE,
4130                                                        FALSE);
4131     }
4132   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4133            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4134     {
4135       /* New node is above the old one; selection became smaller */
4136       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4137                                                        end_tree,
4138                                                        end_node,
4139                                                        tree_view->priv->rubber_band_end_tree,
4140                                                        tree_view->priv->rubber_band_end_node,
4141                                                        FALSE,
4142                                                        TRUE,
4143                                                        FALSE);
4144     }
4145
4146   tree_view->priv->rubber_band_end_tree = end_tree;
4147   tree_view->priv->rubber_band_end_node = end_node;
4148 }
4149
4150 static void
4151 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4152 {
4153   gint x, y;
4154   GdkRectangle old_area;
4155   GdkRectangle new_area;
4156   GdkRectangle common;
4157   cairo_region_t *invalid_region;
4158
4159   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4160   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4161   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4162   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4163
4164   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4165
4166   x = MAX (x, 0);
4167   y = MAX (y, 0) + tree_view->priv->dy;
4168
4169   new_area.x = MIN (tree_view->priv->press_start_x, x);
4170   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4171   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4172   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4173
4174   invalid_region = cairo_region_create_rectangle (&old_area);
4175   cairo_region_union_rectangle (invalid_region, &new_area);
4176
4177   gdk_rectangle_intersect (&old_area, &new_area, &common);
4178   if (common.width > 2 && common.height > 2)
4179     {
4180       cairo_region_t *common_region;
4181
4182       /* make sure the border is invalidated */
4183       common.x += 1;
4184       common.y += 1;
4185       common.width -= 2;
4186       common.height -= 2;
4187
4188       common_region = cairo_region_create_rectangle (&common);
4189
4190       cairo_region_subtract (invalid_region, common_region);
4191       cairo_region_destroy (common_region);
4192     }
4193
4194   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4195
4196   cairo_region_destroy (invalid_region);
4197
4198   tree_view->priv->rubber_band_x = x;
4199   tree_view->priv->rubber_band_y = y;
4200
4201   gtk_tree_view_update_rubber_band_selection (tree_view);
4202 }
4203
4204 static void
4205 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4206                                  cairo_t      *cr)
4207 {
4208   GdkRectangle rect;
4209   GtkStyle *style;
4210
4211   cairo_save (cr);
4212
4213   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4214   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4215   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4216   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4217
4218   cairo_set_line_width (cr, 1.0);
4219
4220   style = gtk_widget_get_style (GTK_WIDGET (tree_view));
4221
4222   gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
4223
4224   gdk_cairo_rectangle (cr, &rect);
4225   cairo_clip (cr);
4226   cairo_paint_with_alpha (cr, 0.25);
4227
4228   cairo_rectangle (cr,
4229                    rect.x + 0.5, rect.y + 0.5,
4230                    rect.width - 1, rect.height - 1);
4231   cairo_stroke (cr);
4232
4233   cairo_restore (cr);
4234 }
4235
4236 static gboolean
4237 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4238                                  GdkEventMotion *event)
4239 {
4240   GtkTreeView *tree_view;
4241   GtkRBTree *tree;
4242   GtkRBNode *node;
4243   gint new_y;
4244
4245   tree_view = (GtkTreeView *) widget;
4246
4247   if (tree_view->priv->tree == NULL)
4248     return FALSE;
4249
4250   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4251     {
4252       gtk_grab_add (GTK_WIDGET (tree_view));
4253       gtk_tree_view_update_rubber_band (tree_view);
4254
4255       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4256     }
4257   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4258     {
4259       gtk_tree_view_update_rubber_band (tree_view);
4260
4261       add_scroll_timeout (tree_view);
4262     }
4263
4264   /* only check for an initiated drag when a button is pressed */
4265   if (tree_view->priv->pressed_button >= 0
4266       && !tree_view->priv->rubber_band_status)
4267     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4268
4269   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4270   if (new_y < 0)
4271     new_y = 0;
4272
4273   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4274
4275   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4276   if ((tree_view->priv->button_pressed_node != NULL) &&
4277       (tree_view->priv->button_pressed_node != node))
4278     node = NULL;
4279
4280   tree_view->priv->event_last_x = event->x;
4281   tree_view->priv->event_last_y = event->y;
4282
4283   prelight_or_select (tree_view, tree, node, event->x, event->y);
4284
4285   return TRUE;
4286 }
4287
4288 static gboolean
4289 gtk_tree_view_motion (GtkWidget      *widget,
4290                       GdkEventMotion *event)
4291 {
4292   GtkTreeView *tree_view;
4293
4294   tree_view = (GtkTreeView *) widget;
4295
4296   /* Resizing a column */
4297   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4298     return gtk_tree_view_motion_resize_column (widget, event);
4299
4300   /* Drag column */
4301   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4302     return gtk_tree_view_motion_drag_column (widget, event);
4303
4304   /* Sanity check it */
4305   if (event->window == tree_view->priv->bin_window)
4306     return gtk_tree_view_motion_bin_window (widget, event);
4307
4308   return FALSE;
4309 }
4310
4311 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4312  * the tree is empty.
4313  */
4314 static void
4315 invalidate_empty_focus (GtkTreeView *tree_view)
4316 {
4317   GdkRectangle area;
4318
4319   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4320     return;
4321
4322   area.x = 0;
4323   area.y = 0;
4324   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4325   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4326   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4327 }
4328
4329 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4330  * is empty.
4331  */
4332 static void
4333 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4334 {
4335   GtkWidget *widget = GTK_WIDGET (tree_view);
4336   gint w, h;
4337
4338   if (!gtk_widget_has_focus (widget))
4339     return;
4340
4341   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4342   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4343
4344   if (w > 0 && h > 0)
4345     gtk_paint_focus (gtk_widget_get_style (widget),
4346                      cr,
4347                      gtk_widget_get_state (widget),
4348                      widget,
4349                      NULL,
4350                      1, 1, w, h);
4351 }
4352
4353 typedef enum {
4354   GTK_TREE_VIEW_GRID_LINE,
4355   GTK_TREE_VIEW_TREE_LINE,
4356   GTK_TREE_VIEW_FOREGROUND_LINE
4357 } GtkTreeViewLineType;
4358
4359 static void
4360 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4361                          cairo_t             *cr,
4362                          GtkTreeViewLineType  type,
4363                          int                  x1,
4364                          int                  y1,
4365                          int                  x2,
4366                          int                  y2)
4367 {
4368   cairo_save (cr);
4369
4370   switch (type)
4371     {
4372     case GTK_TREE_VIEW_TREE_LINE:
4373       cairo_set_source_rgb (cr, 0, 0, 0);
4374       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4375       if (tree_view->priv->tree_line_dashes[0])
4376         cairo_set_dash (cr, 
4377                         tree_view->priv->tree_line_dashes,
4378                         2, 0.5);
4379       break;
4380     case GTK_TREE_VIEW_GRID_LINE:
4381       cairo_set_source_rgb (cr, 0, 0, 0);
4382       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4383       if (tree_view->priv->grid_line_dashes[0])
4384         cairo_set_dash (cr, 
4385                         tree_view->priv->grid_line_dashes,
4386                         2, 0.5);
4387       break;
4388     default:
4389       g_assert_not_reached ();
4390       /* fall through */
4391     case GTK_TREE_VIEW_FOREGROUND_LINE:
4392       cairo_set_line_width (cr, 1.0);
4393       gdk_cairo_set_source_color (cr,
4394                                   &gtk_widget_get_style (GTK_WIDGET (tree_view))->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4395       break;
4396     }
4397
4398   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4399   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4400   cairo_stroke (cr);
4401
4402   cairo_restore (cr);
4403 }
4404                          
4405 static void
4406 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4407                                cairo_t        *cr,
4408                                gint            n_visible_columns)
4409 {
4410   GList *list = tree_view->priv->columns;
4411   gint i = 0;
4412   gint current_x = 0;
4413
4414   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4415       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4416     return;
4417
4418   /* Only draw the lines for visible rows and columns */
4419   for (list = tree_view->priv->columns; list; list = list->next, i++)
4420     {
4421       GtkTreeViewColumn *column = list->data;
4422
4423       /* We don't want a line for the last column */
4424       if (i == n_visible_columns - 1)
4425         break;
4426
4427       if (!gtk_tree_view_column_get_visible (column))
4428         continue;
4429
4430       current_x += gtk_tree_view_column_get_width (column);
4431
4432       gtk_tree_view_draw_line (tree_view, cr,
4433                                GTK_TREE_VIEW_GRID_LINE,
4434                                current_x - 1, 0,
4435                                current_x - 1, tree_view->priv->height);
4436     }
4437 }
4438
4439 /* Warning: Very scary function.
4440  * Modify at your own risk
4441  *
4442  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4443  * FIXME: It's not...
4444  */
4445 static gboolean
4446 gtk_tree_view_bin_draw (GtkWidget      *widget,
4447                         cairo_t        *cr)
4448 {
4449   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4450   GtkTreePath *path;
4451   GtkStyle *style;
4452   GtkRBTree *tree;
4453   GList *list;
4454   GtkRBNode *node;
4455   GtkRBNode *cursor = NULL;
4456   GtkRBTree *cursor_tree = NULL;
4457   GtkRBNode *drag_highlight = NULL;
4458   GtkRBTree *drag_highlight_tree = NULL;
4459   GtkTreeIter iter;
4460   gint new_y;
4461   gint y_offset, cell_offset;
4462   gint max_height;
4463   gint depth;
4464   GdkRectangle background_area;
4465   GdkRectangle cell_area;
4466   GdkRectangle clip;
4467   guint flags;
4468   gint highlight_x;
4469   gint expander_cell_width;
4470   gint bin_window_width;
4471   gint bin_window_height;
4472   GtkTreePath *cursor_path;
4473   GtkTreePath *drag_dest_path;
4474   GList *first_column, *last_column;
4475   gint vertical_separator;
4476   gint horizontal_separator;
4477   gint focus_line_width;
4478   gboolean allow_rules;
4479   gboolean has_special_cell;
4480   gboolean rtl;
4481   gint n_visible_columns;
4482   gint pointer_x, pointer_y;
4483   gint grid_line_width;
4484   gboolean got_pointer = FALSE;
4485   gboolean draw_vgrid_lines, draw_hgrid_lines;
4486
4487   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4488
4489   gtk_widget_style_get (widget,
4490                         "horizontal-separator", &horizontal_separator,
4491                         "vertical-separator", &vertical_separator,
4492                         "allow-rules", &allow_rules,
4493                         "focus-line-width", &focus_line_width,
4494                         NULL);
4495
4496   if (tree_view->priv->tree == NULL)
4497     {
4498       draw_empty_focus (tree_view, cr);
4499       return TRUE;
4500     }
4501
4502   style = gtk_widget_get_style (widget);
4503
4504   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4505   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4506   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4507   cairo_clip (cr);
4508   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4509     return TRUE;
4510
4511   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4512
4513   if (new_y < 0)
4514     new_y = 0;
4515   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4516
4517   if (tree_view->priv->height < bin_window_height)
4518     {
4519       gtk_paint_flat_box (style,
4520                           cr,
4521                           gtk_widget_get_state (widget),
4522                           GTK_SHADOW_NONE,
4523                           widget,
4524                           "cell_even",
4525                           0, tree_view->priv->height,
4526                           bin_window_width,
4527                           bin_window_height - tree_view->priv->height);
4528     }
4529
4530   if (node == NULL)
4531     return TRUE;
4532
4533   /* find the path for the node */
4534   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4535                                    tree,
4536                                    node);
4537   gtk_tree_model_get_iter (tree_view->priv->model,
4538                            &iter,
4539                            path);
4540   depth = gtk_tree_path_get_depth (path);
4541   gtk_tree_path_free (path);
4542   
4543   cursor_path = NULL;
4544   drag_dest_path = NULL;
4545
4546   if (tree_view->priv->cursor)
4547     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4548
4549   if (cursor_path)
4550     _gtk_tree_view_find_node (tree_view, cursor_path,
4551                               &cursor_tree, &cursor);
4552
4553   if (tree_view->priv->drag_dest_row)
4554     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4555
4556   if (drag_dest_path)
4557     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4558                               &drag_highlight_tree, &drag_highlight);
4559
4560   draw_vgrid_lines =
4561     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4562     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4563   draw_hgrid_lines =
4564     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4565     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4566
4567   if (draw_vgrid_lines || draw_hgrid_lines)
4568     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4569   
4570   n_visible_columns = 0;
4571   for (list = tree_view->priv->columns; list; list = list->next)
4572     {
4573       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4574         continue;
4575       n_visible_columns ++;
4576     }
4577
4578   /* Find the last column */
4579   for (last_column = g_list_last (tree_view->priv->columns);
4580        last_column &&
4581        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4582        last_column = last_column->prev)
4583     ;
4584
4585   /* and the first */
4586   for (first_column = g_list_first (tree_view->priv->columns);
4587        first_column &&
4588        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4589        first_column = first_column->next)
4590     ;
4591
4592   /* Actually process the expose event.  To do this, we want to
4593    * start at the first node of the event, and walk the tree in
4594    * order, drawing each successive node.
4595    */
4596
4597   do
4598     {
4599       gboolean parity;
4600       gboolean is_separator = FALSE;
4601       gboolean is_first = FALSE;
4602       gboolean is_last = FALSE;
4603       
4604       is_separator = row_is_separator (tree_view, &iter, NULL);
4605
4606       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4607
4608       cell_offset = 0;
4609       highlight_x = 0; /* should match x coord of first cell */
4610       expander_cell_width = 0;
4611
4612       background_area.y = y_offset + clip.y;
4613       background_area.height = max_height;
4614
4615       flags = 0;
4616
4617       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4618         flags |= GTK_CELL_RENDERER_PRELIT;
4619
4620       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4621         flags |= GTK_CELL_RENDERER_SELECTED;
4622
4623       parity = _gtk_rbtree_node_find_parity (tree, node);
4624
4625       /* we *need* to set cell data on all cells before the call
4626        * to _has_special_cell, else _has_special_cell() does not
4627        * return a correct value.
4628        */
4629       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4630            list;
4631            list = (rtl ? list->prev : list->next))
4632         {
4633           GtkTreeViewColumn *column = list->data;
4634           gtk_tree_view_column_cell_set_cell_data (column,
4635                                                    tree_view->priv->model,
4636                                                    &iter,
4637                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4638                                                    node->children?TRUE:FALSE);
4639         }
4640
4641       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4642
4643       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4644            list;
4645            list = (rtl ? list->prev : list->next))
4646         {
4647           GtkTreeViewColumn *column = list->data;
4648           const gchar *detail = NULL;
4649           gchar new_detail[128];
4650           gint width;
4651           GtkStateType state;
4652
4653           if (!gtk_tree_view_column_get_visible (column))
4654             continue;
4655
4656           width = gtk_tree_view_column_get_width (column);
4657
4658           if (cell_offset > clip.x + clip.width ||
4659               cell_offset + width < clip.x)
4660             {
4661               cell_offset += width;
4662               continue;
4663             }
4664
4665           if (gtk_tree_view_column_get_sort_indicator (column))
4666             flags |= GTK_CELL_RENDERER_SORTED;
4667           else
4668             flags &= ~GTK_CELL_RENDERER_SORTED;
4669
4670           if (cursor == node)
4671             flags |= GTK_CELL_RENDERER_FOCUSED;
4672           else
4673             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4674
4675           background_area.x = cell_offset;
4676           background_area.width = width;
4677
4678           cell_area = background_area;
4679           cell_area.y += vertical_separator / 2;
4680           cell_area.x += horizontal_separator / 2;
4681           cell_area.height -= vertical_separator;
4682           cell_area.width -= horizontal_separator;
4683
4684           if (draw_vgrid_lines)
4685             {
4686               if (list == first_column)
4687                 {
4688                   cell_area.width -= grid_line_width / 2;
4689                 }
4690               else if (list == last_column)
4691                 {
4692                   cell_area.x += grid_line_width / 2;
4693                   cell_area.width -= grid_line_width / 2;
4694                 }
4695               else
4696                 {
4697                   cell_area.x += grid_line_width / 2;
4698                   cell_area.width -= grid_line_width;
4699                 }
4700             }
4701
4702           if (draw_hgrid_lines)
4703             {
4704               cell_area.y += grid_line_width / 2;
4705               cell_area.height -= grid_line_width;
4706             }
4707
4708           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4709             {
4710               cell_offset += gtk_tree_view_column_get_width (column);
4711               continue;
4712             }
4713
4714           gtk_tree_view_column_cell_set_cell_data (column,
4715                                                    tree_view->priv->model,
4716                                                    &iter,
4717                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4718                                                    node->children?TRUE:FALSE);
4719
4720           /* Select the detail for drawing the cell.  relevant
4721            * factors are parity, sortedness, and whether to
4722            * display rules.
4723            */
4724           if (allow_rules && tree_view->priv->has_rules)
4725             {
4726               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4727                   n_visible_columns >= 3)
4728                 {
4729                   if (parity)
4730                     detail = "cell_odd_ruled_sorted";
4731                   else
4732                     detail = "cell_even_ruled_sorted";
4733                 }
4734               else
4735                 {
4736                   if (parity)
4737                     detail = "cell_odd_ruled";
4738                   else
4739                     detail = "cell_even_ruled";
4740                 }
4741             }
4742           else
4743             {
4744               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4745                   n_visible_columns >= 3)
4746                 {
4747                   if (parity)
4748                     detail = "cell_odd_sorted";
4749                   else
4750                     detail = "cell_even_sorted";
4751                 }
4752               else
4753                 {
4754                   if (parity)
4755                     detail = "cell_odd";
4756                   else
4757                     detail = "cell_even";
4758                 }
4759             }
4760
4761           g_assert (detail);
4762
4763           if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
4764             state = GTK_STATE_INSENSITIVE;          
4765           else if (flags & GTK_CELL_RENDERER_SELECTED)
4766             state = GTK_STATE_SELECTED;
4767           else
4768             state = GTK_STATE_NORMAL;
4769
4770           /* Draw background */
4771           is_first = (rtl ? !list->next : !list->prev);
4772           is_last = (rtl ? !list->prev : !list->next);
4773
4774           /* (I don't like the snprintfs either, but couldn't find a
4775            * less messy way).
4776            */
4777           if (is_first && is_last)
4778             g_snprintf (new_detail, 127, "%s", detail);
4779           else if (is_first)
4780             g_snprintf (new_detail, 127, "%s_start", detail);
4781           else if (is_last)
4782             g_snprintf (new_detail, 127, "%s_end", detail);
4783           else
4784             g_snprintf (new_detail, 127, "%s_middle", detail);
4785
4786           gtk_paint_flat_box (style,
4787                               cr,
4788                               state,
4789                               GTK_SHADOW_NONE,
4790                               widget,
4791                               new_detail,
4792                               background_area.x,
4793                               background_area.y,
4794                               background_area.width,
4795                               background_area.height);
4796
4797           if (gtk_tree_view_is_expander_column (tree_view, column))
4798             {
4799               if (!rtl)
4800                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4801               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4802
4803               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4804                 {
4805                   if (!rtl)
4806                     cell_area.x += depth * tree_view->priv->expander_size;
4807                   cell_area.width -= depth * tree_view->priv->expander_size;
4808                 }
4809
4810               /* If we have an expander column, the highlight underline
4811                * starts with that column, so that it indicates which
4812                * level of the tree we're dropping at.
4813                */
4814               highlight_x = cell_area.x;
4815               expander_cell_width = cell_area.width;
4816
4817               if (is_separator)
4818                 gtk_paint_hline (style,
4819                                  cr,
4820                                  state,
4821                                  widget,
4822                                  NULL,
4823                                  cell_area.x,
4824                                  cell_area.x + cell_area.width,
4825                                  cell_area.y + cell_area.height / 2);
4826               else
4827                 _gtk_tree_view_column_cell_render (column,
4828                                                    cr,
4829                                                    &background_area,
4830                                                    &cell_area,
4831                                                    flags);
4832               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4833                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4834                 {
4835                   if (!got_pointer)
4836                     {
4837                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4838                                               &pointer_x, &pointer_y, NULL);
4839                       got_pointer = TRUE;
4840                     }
4841
4842                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4843                                             cr,
4844                                             tree,
4845                                             node,
4846                                             pointer_x, pointer_y);
4847                 }
4848             }
4849           else
4850             {
4851               if (is_separator)
4852                 gtk_paint_hline (style,
4853                                  cr,
4854                                  state,
4855                                  widget,
4856                                  NULL,
4857                                  cell_area.x,
4858                                  cell_area.x + cell_area.width,
4859                                  cell_area.y + cell_area.height / 2);
4860               else
4861                 _gtk_tree_view_column_cell_render (column,
4862                                                    cr,
4863                                                    &background_area,
4864                                                    &cell_area,
4865                                                    flags);
4866             }
4867
4868           if (draw_hgrid_lines)
4869             {
4870               if (background_area.y > 0)
4871                 gtk_tree_view_draw_line (tree_view, cr,
4872                                          GTK_TREE_VIEW_GRID_LINE,
4873                                          background_area.x, background_area.y,
4874                                          background_area.x + background_area.width,
4875                                          background_area.y);
4876
4877               if (y_offset + max_height >= clip.height)
4878                 gtk_tree_view_draw_line (tree_view, cr,
4879                                          GTK_TREE_VIEW_GRID_LINE,
4880                                          background_area.x, background_area.y + max_height,
4881                                          background_area.x + background_area.width,
4882                                          background_area.y + max_height);
4883             }
4884
4885           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4886               tree_view->priv->tree_lines_enabled)
4887             {
4888               gint x = background_area.x;
4889               gint mult = rtl ? -1 : 1;
4890               gint y0 = background_area.y;
4891               gint y1 = background_area.y + background_area.height/2;
4892               gint y2 = background_area.y + background_area.height;
4893
4894               if (rtl)
4895                 x += background_area.width - 1;
4896
4897               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4898                   && depth > 1)
4899                 {
4900                   gtk_tree_view_draw_line (tree_view, cr,
4901                                            GTK_TREE_VIEW_TREE_LINE,
4902                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4903                                            y1,
4904                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4905                                            y1);
4906                 }
4907               else if (depth > 1)
4908                 {
4909                   gtk_tree_view_draw_line (tree_view, cr,
4910                                            GTK_TREE_VIEW_TREE_LINE,
4911                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4912                                            y1,
4913                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4914                                            y1);
4915                 }
4916
4917               if (depth > 1)
4918                 {
4919                   gint i;
4920                   GtkRBNode *tmp_node;
4921                   GtkRBTree *tmp_tree;
4922
4923                   if (!_gtk_rbtree_next (tree, node))
4924                     gtk_tree_view_draw_line (tree_view, cr,
4925                                              GTK_TREE_VIEW_TREE_LINE,
4926                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4927                                              y0,
4928                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4929                                              y1);
4930                   else
4931                     gtk_tree_view_draw_line (tree_view, cr,
4932                                              GTK_TREE_VIEW_TREE_LINE,
4933                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4934                                              y0,
4935                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4936                                              y2);
4937
4938                   tmp_node = tree->parent_node;
4939                   tmp_tree = tree->parent_tree;
4940
4941                   for (i = depth - 2; i > 0; i--)
4942                     {
4943                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4944                         gtk_tree_view_draw_line (tree_view, cr,
4945                                                  GTK_TREE_VIEW_TREE_LINE,
4946                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4947                                                  y0,
4948                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4949                                                  y2);
4950
4951                       tmp_node = tmp_tree->parent_node;
4952                       tmp_tree = tmp_tree->parent_tree;
4953                     }
4954                 }
4955             }
4956
4957           if (node == cursor && has_special_cell &&
4958               ((column == tree_view->priv->focus_column &&
4959                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4960                 gtk_widget_has_focus (widget)) ||
4961                (column == tree_view->priv->edited_column)))
4962             {
4963               _gtk_tree_view_column_cell_draw_focus (column,
4964                                                      cr,
4965                                                      &background_area,
4966                                                      &cell_area,
4967                                                      flags);
4968             }
4969
4970           cell_offset += gtk_tree_view_column_get_width (column);
4971         }
4972
4973       if (node == drag_highlight)
4974         {
4975           /* Draw indicator for the drop
4976            */
4977           gint highlight_y = -1;
4978           GtkRBTree *tree = NULL;
4979           GtkRBNode *node = NULL;
4980
4981           switch (tree_view->priv->drag_dest_pos)
4982             {
4983             case GTK_TREE_VIEW_DROP_BEFORE:
4984               highlight_y = background_area.y - 1;
4985               if (highlight_y < 0)
4986                       highlight_y = 0;
4987               break;
4988
4989             case GTK_TREE_VIEW_DROP_AFTER:
4990               highlight_y = background_area.y + background_area.height - 1;
4991               break;
4992
4993             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4994             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4995               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4996
4997               if (tree == NULL)
4998                 break;
4999
5000               gtk_paint_focus (style,
5001                                cr,
5002                                gtk_widget_get_state (widget),
5003                                widget,
5004                                (is_first
5005                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
5006                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
5007                                 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
5008                                    - focus_line_width / 2,
5009                                 gdk_window_get_width (tree_view->priv->bin_window),
5010                                 ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
5011                                    - focus_line_width + 1);
5012               break;
5013             }
5014
5015           if (highlight_y >= 0)
5016             {
5017               gtk_tree_view_draw_line (tree_view, cr,
5018                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5019                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5020                                        highlight_y,
5021                                        rtl ? 0 : bin_window_width,
5022                                        highlight_y);
5023             }
5024         }
5025
5026       /* draw the big row-spanning focus rectangle, if needed */
5027       if (!has_special_cell && node == cursor &&
5028           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
5029           gtk_widget_has_focus (widget))
5030         {
5031           gint tmp_y, tmp_height;
5032           GtkStateType focus_rect_state;
5033
5034           focus_rect_state =
5035             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
5036             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
5037              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
5038               GTK_STATE_NORMAL));
5039
5040           if (draw_hgrid_lines)
5041             {
5042               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
5043               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
5044             }
5045           else
5046             {
5047               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
5048               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
5049             }
5050
5051           gtk_paint_focus (style,
5052                            cr,
5053                            focus_rect_state,
5054                            widget,
5055                            (is_first
5056                             ? (is_last ? "treeview" : "treeview-left" )
5057                             : (is_last ? "treeview-right" : "treeview-middle" )),
5058                            0, tmp_y,
5059                            gdk_window_get_width (tree_view->priv->bin_window),
5060                            tmp_height);
5061         }
5062
5063       y_offset += max_height;
5064       if (node->children)
5065         {
5066           GtkTreeIter parent = iter;
5067           gboolean has_child;
5068
5069           tree = node->children;
5070           node = tree->root;
5071
5072           g_assert (node != tree->nil);
5073
5074           while (node->left != tree->nil)
5075             node = node->left;
5076           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5077                                                     &iter,
5078                                                     &parent);
5079           depth++;
5080
5081           /* Sanity Check! */
5082           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5083         }
5084       else
5085         {
5086           gboolean done = FALSE;
5087
5088           do
5089             {
5090               node = _gtk_rbtree_next (tree, node);
5091               if (node != NULL)
5092                 {
5093                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5094                   done = TRUE;
5095
5096                   /* Sanity Check! */
5097                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5098                 }
5099               else
5100                 {
5101                   GtkTreeIter parent_iter = iter;
5102                   gboolean has_parent;
5103
5104                   node = tree->parent_node;
5105                   tree = tree->parent_tree;
5106                   if (tree == NULL)
5107                     /* we should go to done to free some memory */
5108                     goto done;
5109                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5110                                                            &iter,
5111                                                            &parent_iter);
5112                   depth--;
5113
5114                   /* Sanity check */
5115                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5116                 }
5117             }
5118           while (!done);
5119         }
5120     }
5121   while (y_offset < clip.height);
5122
5123 done:
5124   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5125
5126   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5127     gtk_tree_view_paint_rubber_band (tree_view, cr);
5128
5129   if (cursor_path)
5130     gtk_tree_path_free (cursor_path);
5131
5132   if (drag_dest_path)
5133     gtk_tree_path_free (drag_dest_path);
5134
5135   return FALSE;
5136 }
5137
5138 static gboolean
5139 gtk_tree_view_draw (GtkWidget *widget,
5140                     cairo_t   *cr)
5141 {
5142   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5143
5144   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5145     {
5146       GList *tmp_list;
5147
5148       cairo_save (cr);
5149
5150       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5151
5152       gtk_tree_view_bin_draw (widget, cr);
5153
5154       cairo_restore (cr);
5155
5156       /* We can't just chain up to Container::draw as it will try to send the
5157        * event to the headers, so we handle propagating it to our children
5158        * (eg. widgets being edited) ourselves.
5159        */
5160       tmp_list = tree_view->priv->children;
5161       while (tmp_list)
5162         {
5163           GtkTreeViewChild *child = tmp_list->data;
5164           tmp_list = tmp_list->next;
5165
5166           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5167         }
5168     }
5169
5170   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5171     {
5172       GList *list;
5173       
5174       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5175         {
5176           GtkTreeViewColumn *column = list->data;
5177
5178           if (column == tree_view->priv->drag_column)
5179             continue;
5180
5181           if (gtk_tree_view_column_get_visible (column))
5182             gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5183                                           column->button,
5184                                           cr);
5185         }
5186     }
5187   
5188   if (tree_view->priv->drag_window &&
5189       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5190     {
5191       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5192                                     tree_view->priv->drag_column->button,
5193                                     cr);
5194     }
5195
5196   return TRUE;
5197 }
5198
5199 enum
5200 {
5201   DROP_HOME,
5202   DROP_RIGHT,
5203   DROP_LEFT,
5204   DROP_END
5205 };
5206
5207 /* returns 0x1 when no column has been found -- yes it's hackish */
5208 static GtkTreeViewColumn *
5209 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5210                                GtkTreeViewColumn *column,
5211                                gint               drop_position)
5212 {
5213   GtkTreeViewColumn *left_column = NULL;
5214   GtkTreeViewColumn *cur_column = NULL;
5215   GList *tmp_list;
5216
5217   if (!gtk_tree_view_column_get_reorderable (column))
5218     return (GtkTreeViewColumn *)0x1;
5219
5220   switch (drop_position)
5221     {
5222       case DROP_HOME:
5223         /* find first column where we can drop */
5224         tmp_list = tree_view->priv->columns;
5225         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5226           return (GtkTreeViewColumn *)0x1;
5227
5228         while (tmp_list)
5229           {
5230             g_assert (tmp_list);
5231
5232             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5233             tmp_list = tmp_list->next;
5234
5235             if (left_column &&
5236                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5237               continue;
5238
5239             if (!tree_view->priv->column_drop_func)
5240               return left_column;
5241
5242             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5243               {
5244                 left_column = cur_column;
5245                 continue;
5246               }
5247
5248             return left_column;
5249           }
5250
5251         if (!tree_view->priv->column_drop_func)
5252           return left_column;
5253
5254         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5255           return left_column;
5256         else
5257           return (GtkTreeViewColumn *)0x1;
5258         break;
5259
5260       case DROP_RIGHT:
5261         /* find first column after column where we can drop */
5262         tmp_list = tree_view->priv->columns;
5263
5264         for (; tmp_list; tmp_list = tmp_list->next)
5265           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5266             break;
5267
5268         if (!tmp_list || !tmp_list->next)
5269           return (GtkTreeViewColumn *)0x1;
5270
5271         tmp_list = tmp_list->next;
5272         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5273         tmp_list = tmp_list->next;
5274
5275         while (tmp_list)
5276           {
5277             g_assert (tmp_list);
5278
5279             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5280             tmp_list = tmp_list->next;
5281
5282             if (left_column &&
5283                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5284               {
5285                 left_column = cur_column;
5286                 if (tmp_list)
5287                   tmp_list = tmp_list->next;
5288                 continue;
5289               }
5290
5291             if (!tree_view->priv->column_drop_func)
5292               return left_column;
5293
5294             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5295               {
5296                 left_column = cur_column;
5297                 continue;
5298               }
5299
5300             return left_column;
5301           }
5302
5303         if (!tree_view->priv->column_drop_func)
5304           return left_column;
5305
5306         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5307           return left_column;
5308         else
5309           return (GtkTreeViewColumn *)0x1;
5310         break;
5311
5312       case DROP_LEFT:
5313         /* find first column before column where we can drop */
5314         tmp_list = tree_view->priv->columns;
5315
5316         for (; tmp_list; tmp_list = tmp_list->next)
5317           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5318             break;
5319
5320         if (!tmp_list || !tmp_list->prev)
5321           return (GtkTreeViewColumn *)0x1;
5322
5323         tmp_list = tmp_list->prev;
5324         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5325         tmp_list = tmp_list->prev;
5326
5327         while (tmp_list)
5328           {
5329             g_assert (tmp_list);
5330
5331             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5332
5333             if (left_column &&
5334                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5335               {
5336                 /*if (!tmp_list->prev)
5337                   return (GtkTreeViewColumn *)0x1;
5338                   */
5339 /*
5340                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5341                 tmp_list = tmp_list->prev->prev;
5342                 continue;*/
5343
5344                 cur_column = left_column;
5345                 if (tmp_list)
5346                   tmp_list = tmp_list->prev;
5347                 continue;
5348               }
5349
5350             if (!tree_view->priv->column_drop_func)
5351               return left_column;
5352
5353             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5354               return left_column;
5355
5356             cur_column = left_column;
5357             tmp_list = tmp_list->prev;
5358           }
5359
5360         if (!tree_view->priv->column_drop_func)
5361           return NULL;
5362
5363         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5364           return NULL;
5365         else
5366           return (GtkTreeViewColumn *)0x1;
5367         break;
5368
5369       case DROP_END:
5370         /* same as DROP_HOME case, but doing it backwards */
5371         tmp_list = g_list_last (tree_view->priv->columns);
5372         cur_column = NULL;
5373
5374         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5375           return (GtkTreeViewColumn *)0x1;
5376
5377         while (tmp_list)
5378           {
5379             g_assert (tmp_list);
5380
5381             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5382
5383             if (left_column &&
5384                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5385               {
5386                 cur_column = left_column;
5387                 tmp_list = tmp_list->prev;
5388               }
5389
5390             if (!tree_view->priv->column_drop_func)
5391               return left_column;
5392
5393             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5394               return left_column;
5395
5396             cur_column = left_column;
5397             tmp_list = tmp_list->prev;
5398           }
5399
5400         if (!tree_view->priv->column_drop_func)
5401           return NULL;
5402
5403         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5404           return NULL;
5405         else
5406           return (GtkTreeViewColumn *)0x1;
5407         break;
5408     }
5409
5410   return (GtkTreeViewColumn *)0x1;
5411 }
5412
5413 static gboolean
5414 gtk_tree_view_key_press (GtkWidget   *widget,
5415                          GdkEventKey *event)
5416 {
5417   GtkTreeView *tree_view = (GtkTreeView *) widget;
5418
5419   if (tree_view->priv->rubber_band_status)
5420     {
5421       if (event->keyval == GDK_KEY_Escape)
5422         gtk_tree_view_stop_rubber_band (tree_view);
5423
5424       return TRUE;
5425     }
5426
5427   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5428     {
5429       if (event->keyval == GDK_KEY_Escape)
5430         {
5431           tree_view->priv->cur_reorder = NULL;
5432           gtk_tree_view_button_release_drag_column (widget, NULL);
5433         }
5434       return TRUE;
5435     }
5436
5437   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5438     {
5439       GList *focus_column;
5440       gboolean rtl;
5441
5442       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5443
5444       for (focus_column = tree_view->priv->columns;
5445            focus_column;
5446            focus_column = focus_column->next)
5447         {
5448           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5449
5450           if (gtk_widget_has_focus (column->button))
5451             break;
5452         }
5453
5454       if (focus_column &&
5455           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5456           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5457            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5458         {
5459           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5460           gint max_width, min_width;
5461
5462           if (!gtk_tree_view_column_get_resizable (column))
5463             {
5464               gtk_widget_error_bell (widget);
5465               return TRUE;
5466             }
5467
5468           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5469               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5470             {
5471               GtkRequisition button_req;
5472               gint old_width = column->resized_width;
5473
5474               gtk_widget_get_preferred_size (column->button, &button_req, NULL);
5475
5476               column->resized_width = MAX (column->resized_width,
5477                                            gtk_tree_view_column_get_width (column));
5478               column->resized_width -= 2;
5479               if (column->resized_width < 0)
5480                 column->resized_width = 0;
5481
5482               min_width = gtk_tree_view_column_get_min_width (column);
5483               if (min_width == -1)
5484                 column->resized_width = MAX (button_req.width,
5485                                              column->resized_width);
5486               else
5487                 {
5488                   column->resized_width = MAX (min_width,
5489                                                column->resized_width);
5490                 }
5491
5492               max_width = gtk_tree_view_column_get_max_width (column);
5493               if (max_width != -1)
5494                 column->resized_width = MIN (column->resized_width, max_width);
5495
5496               column->use_resized_width = TRUE;
5497
5498               if (column->resized_width != old_width)
5499                 gtk_widget_queue_resize (widget);
5500               else
5501                 gtk_widget_error_bell (widget);
5502             }
5503           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5504                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5505             {
5506               gint old_width = column->resized_width;
5507
5508               column->resized_width = MAX (column->resized_width,
5509                                            gtk_tree_view_column_get_width (column));
5510               column->resized_width += 2;
5511
5512               max_width = gtk_tree_view_column_get_max_width (column);
5513               if (max_width != -1)
5514                 column->resized_width = MIN (column->resized_width, max_width);
5515
5516               column->use_resized_width = TRUE;
5517
5518               if (column->resized_width != old_width)
5519                 gtk_widget_queue_resize (widget);
5520               else
5521                 gtk_widget_error_bell (widget);
5522             }
5523
5524           return TRUE;
5525         }
5526
5527       if (focus_column &&
5528           (event->state & GDK_MOD1_MASK) &&
5529           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5530            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5531            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5532            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5533         {
5534           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5535
5536           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5537               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5538             {
5539               GtkTreeViewColumn *col;
5540               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5541               if (col != (GtkTreeViewColumn *)0x1)
5542                 gtk_tree_view_move_column_after (tree_view, column, col);
5543               else
5544                 gtk_widget_error_bell (widget);
5545             }
5546           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5547                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5548             {
5549               GtkTreeViewColumn *col;
5550               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5551               if (col != (GtkTreeViewColumn *)0x1)
5552                 gtk_tree_view_move_column_after (tree_view, column, col);
5553               else
5554                 gtk_widget_error_bell (widget);
5555             }
5556           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5557             {
5558               GtkTreeViewColumn *col;
5559               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5560               if (col != (GtkTreeViewColumn *)0x1)
5561                 gtk_tree_view_move_column_after (tree_view, column, col);
5562               else
5563                 gtk_widget_error_bell (widget);
5564             }
5565           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5566             {
5567               GtkTreeViewColumn *col;
5568               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5569               if (col != (GtkTreeViewColumn *)0x1)
5570                 gtk_tree_view_move_column_after (tree_view, column, col);
5571               else
5572                 gtk_widget_error_bell (widget);
5573             }
5574
5575           return TRUE;
5576         }
5577     }
5578
5579   /* Chain up to the parent class.  It handles the keybindings. */
5580   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5581     return TRUE;
5582
5583   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5584     {
5585       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5586       return FALSE;
5587     }
5588
5589   /* We pass the event to the search_entry.  If its text changes, then we start
5590    * the typeahead find capabilities. */
5591   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5592       && tree_view->priv->enable_search
5593       && !tree_view->priv->search_custom_entry_set)
5594     {
5595       GdkEvent *new_event;
5596       char *old_text;
5597       const char *new_text;
5598       gboolean retval;
5599       GdkScreen *screen;
5600       gboolean text_modified;
5601       gulong popup_menu_id;
5602
5603       gtk_tree_view_ensure_interactive_directory (tree_view);
5604
5605       /* Make a copy of the current text */
5606       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5607       new_event = gdk_event_copy ((GdkEvent *) event);
5608       g_object_unref (((GdkEventKey *) new_event)->window);
5609       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5610       gtk_widget_realize (tree_view->priv->search_window);
5611
5612       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5613                                         "popup-menu", G_CALLBACK (gtk_true),
5614                                         NULL);
5615
5616       /* Move the entry off screen */
5617       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5618       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5619                        gdk_screen_get_width (screen) + 1,
5620                        gdk_screen_get_height (screen) + 1);
5621       gtk_widget_show (tree_view->priv->search_window);
5622
5623       /* Send the event to the window.  If the preedit_changed signal is emitted
5624        * during this event, we will set priv->imcontext_changed  */
5625       tree_view->priv->imcontext_changed = FALSE;
5626       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5627       gdk_event_free (new_event);
5628       gtk_widget_hide (tree_view->priv->search_window);
5629
5630       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5631                                    popup_menu_id);
5632
5633       /* We check to make sure that the entry tried to handle the text, and that
5634        * the text has changed.
5635        */
5636       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5637       text_modified = strcmp (old_text, new_text) != 0;
5638       g_free (old_text);
5639       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5640           (retval && text_modified))               /* ...or the text was modified */
5641         {
5642           if (gtk_tree_view_real_start_interactive_search (tree_view,
5643                                                            gdk_event_get_device ((GdkEvent *) event),
5644                                                            FALSE))
5645             {
5646               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5647               return TRUE;
5648             }
5649           else
5650             {
5651               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5652               return FALSE;
5653             }
5654         }
5655     }
5656
5657   return FALSE;
5658 }
5659
5660 static gboolean
5661 gtk_tree_view_key_release (GtkWidget   *widget,
5662                            GdkEventKey *event)
5663 {
5664   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5665
5666   if (tree_view->priv->rubber_band_status)
5667     return TRUE;
5668
5669   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5670 }
5671
5672 /* FIXME Is this function necessary? Can I get an enter_notify event
5673  * w/o either an expose event or a mouse motion event?
5674  */
5675 static gboolean
5676 gtk_tree_view_enter_notify (GtkWidget        *widget,
5677                             GdkEventCrossing *event)
5678 {
5679   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5680   GtkRBTree *tree;
5681   GtkRBNode *node;
5682   gint new_y;
5683
5684   /* Sanity check it */
5685   if (event->window != tree_view->priv->bin_window)
5686     return FALSE;
5687
5688   if (tree_view->priv->tree == NULL)
5689     return FALSE;
5690
5691   if (event->mode == GDK_CROSSING_GRAB ||
5692       event->mode == GDK_CROSSING_GTK_GRAB ||
5693       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5694       event->mode == GDK_CROSSING_STATE_CHANGED)
5695     return TRUE;
5696
5697   /* find the node internally */
5698   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5699   if (new_y < 0)
5700     new_y = 0;
5701   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5702
5703   tree_view->priv->event_last_x = event->x;
5704   tree_view->priv->event_last_y = event->y;
5705
5706   if ((tree_view->priv->button_pressed_node == NULL) ||
5707       (tree_view->priv->button_pressed_node == node))
5708     prelight_or_select (tree_view, tree, node, event->x, event->y);
5709
5710   return TRUE;
5711 }
5712
5713 static gboolean
5714 gtk_tree_view_leave_notify (GtkWidget        *widget,
5715                             GdkEventCrossing *event)
5716 {
5717   GtkTreeView *tree_view;
5718
5719   if (event->mode == GDK_CROSSING_GRAB)
5720     return TRUE;
5721
5722   tree_view = GTK_TREE_VIEW (widget);
5723
5724   if (tree_view->priv->prelight_node)
5725     _gtk_tree_view_queue_draw_node (tree_view,
5726                                    tree_view->priv->prelight_tree,
5727                                    tree_view->priv->prelight_node,
5728                                    NULL);
5729
5730   tree_view->priv->event_last_x = -10000;
5731   tree_view->priv->event_last_y = -10000;
5732
5733   prelight_or_select (tree_view,
5734                       NULL, NULL,
5735                       -1000, -1000); /* coords not possibly over an arrow */
5736
5737   return TRUE;
5738 }
5739
5740
5741 static gint
5742 gtk_tree_view_focus_out (GtkWidget     *widget,
5743                          GdkEventFocus *event)
5744 {
5745   GtkTreeView *tree_view;
5746
5747   tree_view = GTK_TREE_VIEW (widget);
5748
5749   gtk_widget_queue_draw (widget);
5750
5751   /* destroy interactive search dialog */
5752   if (tree_view->priv->search_window)
5753     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5754                                       gdk_event_get_device ((GdkEvent *) event));
5755
5756   return FALSE;
5757 }
5758
5759
5760 /* Incremental Reflow
5761  */
5762
5763 static void
5764 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5765                                  GtkRBTree   *tree,
5766                                  GtkRBNode   *node)
5767 {
5768   GtkAllocation allocation;
5769   gint y;
5770
5771   y = _gtk_rbtree_node_find_offset (tree, node)
5772     - tree_view->priv->vadjustment->value
5773     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5774
5775   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5776   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5777                               0, y,
5778                               allocation.width,
5779                               GTK_RBNODE_GET_HEIGHT (node));
5780 }
5781
5782 static gboolean
5783 node_is_visible (GtkTreeView *tree_view,
5784                  GtkRBTree   *tree,
5785                  GtkRBNode   *node)
5786 {
5787   int y;
5788   int height;
5789
5790   y = _gtk_rbtree_node_find_offset (tree, node);
5791   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5792
5793   if (y >= tree_view->priv->vadjustment->value &&
5794       y + height <= (tree_view->priv->vadjustment->value
5795                      + tree_view->priv->vadjustment->page_size))
5796     return TRUE;
5797
5798   return FALSE;
5799 }
5800
5801 /* Returns TRUE if it updated the size
5802  */
5803 static gboolean
5804 validate_row (GtkTreeView *tree_view,
5805               GtkRBTree   *tree,
5806               GtkRBNode   *node,
5807               GtkTreeIter *iter,
5808               GtkTreePath *path)
5809 {
5810   GtkTreeViewColumn *column;
5811   GList *list, *first_column, *last_column;
5812   gint height = 0;
5813   gint horizontal_separator;
5814   gint vertical_separator;
5815   gint focus_line_width;
5816   gint depth = gtk_tree_path_get_depth (path);
5817   gboolean retval = FALSE;
5818   gboolean is_separator = FALSE;
5819   gboolean draw_vgrid_lines, draw_hgrid_lines;
5820   gint focus_pad;
5821   gint grid_line_width;
5822   gboolean wide_separators;
5823   gint separator_height;
5824
5825   /* double check the row needs validating */
5826   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5827       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5828     return FALSE;
5829
5830   is_separator = row_is_separator (tree_view, iter, NULL);
5831
5832   gtk_widget_style_get (GTK_WIDGET (tree_view),
5833                         "focus-padding", &focus_pad,
5834                         "focus-line-width", &focus_line_width,
5835                         "horizontal-separator", &horizontal_separator,
5836                         "vertical-separator", &vertical_separator,
5837                         "grid-line-width", &grid_line_width,
5838                         "wide-separators",  &wide_separators,
5839                         "separator-height", &separator_height,
5840                         NULL);
5841   
5842   draw_vgrid_lines =
5843     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5844     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5845   draw_hgrid_lines =
5846     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5847     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5848
5849   for (last_column = g_list_last (tree_view->priv->columns);
5850        last_column &&
5851        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
5852        last_column = last_column->prev)
5853     ;
5854
5855   for (first_column = g_list_first (tree_view->priv->columns);
5856        first_column &&
5857        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
5858        first_column = first_column->next)
5859     ;
5860
5861   for (list = tree_view->priv->columns; list; list = list->next)
5862     {
5863       gint tmp_width;
5864       gint tmp_height;
5865
5866       column = list->data;
5867
5868       if (!gtk_tree_view_column_get_visible (column))
5869         continue;
5870
5871       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5872         continue;
5873
5874       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5875                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5876                                                node->children?TRUE:FALSE);
5877       gtk_tree_view_column_cell_get_size (column,
5878                                           NULL, NULL, NULL,
5879                                           &tmp_width, &tmp_height);
5880
5881       if (!is_separator)
5882         {
5883           tmp_height += vertical_separator;
5884           height = MAX (height, tmp_height);
5885           height = MAX (height, tree_view->priv->expander_size);
5886         }
5887       else
5888         {
5889           if (wide_separators)
5890             height = separator_height + 2 * focus_pad;
5891           else
5892             height = 2 + 2 * focus_pad;
5893         }
5894
5895       if (gtk_tree_view_is_expander_column (tree_view, column))
5896         {
5897           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5898
5899           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5900             tmp_width += depth * tree_view->priv->expander_size;
5901         }
5902       else
5903         tmp_width = tmp_width + horizontal_separator;
5904
5905       if (draw_vgrid_lines)
5906         {
5907           if (list->data == first_column || list->data == last_column)
5908             tmp_width += grid_line_width / 2.0;
5909           else
5910             tmp_width += grid_line_width;
5911         }
5912
5913       if (tmp_width > column->requested_width)
5914         {
5915           retval = TRUE;
5916           column->requested_width = tmp_width;
5917         }
5918     }
5919
5920   if (draw_hgrid_lines)
5921     height += grid_line_width;
5922
5923   if (height != GTK_RBNODE_GET_HEIGHT (node))
5924     {
5925       retval = TRUE;
5926       _gtk_rbtree_node_set_height (tree, node, height);
5927     }
5928   _gtk_rbtree_node_mark_valid (tree, node);
5929   tree_view->priv->post_validation_flag = TRUE;
5930
5931   return retval;
5932 }
5933
5934
5935 static void
5936 validate_visible_area (GtkTreeView *tree_view)
5937 {
5938   GtkAllocation allocation;
5939   GtkTreePath *path = NULL;
5940   GtkTreePath *above_path = NULL;
5941   GtkTreeIter iter;
5942   GtkRBTree *tree = NULL;
5943   GtkRBNode *node = NULL;
5944   gboolean need_redraw = FALSE;
5945   gboolean size_changed = FALSE;
5946   gint total_height;
5947   gint area_above = 0;
5948   gint area_below = 0;
5949
5950   if (tree_view->priv->tree == NULL)
5951     return;
5952
5953   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5954       tree_view->priv->scroll_to_path == NULL)
5955     return;
5956
5957   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5958   total_height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5959
5960   if (total_height == 0)
5961     return;
5962
5963   /* First, we check to see if we need to scroll anywhere
5964    */
5965   if (tree_view->priv->scroll_to_path)
5966     {
5967       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5968       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5969         {
5970           /* we are going to scroll, and will update dy */
5971           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5972           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5973               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5974             {
5975               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5976               if (validate_row (tree_view, tree, node, &iter, path))
5977                 size_changed = TRUE;
5978             }
5979
5980           if (tree_view->priv->scroll_to_use_align)
5981             {
5982               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5983               area_above = (total_height - height) *
5984                 tree_view->priv->scroll_to_row_align;
5985               area_below = total_height - area_above - height;
5986               area_above = MAX (area_above, 0);
5987               area_below = MAX (area_below, 0);
5988             }
5989           else
5990             {
5991               /* two cases:
5992                * 1) row not visible
5993                * 2) row visible
5994                */
5995               gint dy;
5996               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5997
5998               dy = _gtk_rbtree_node_find_offset (tree, node);
5999
6000               if (dy >= tree_view->priv->vadjustment->value &&
6001                   dy + height <= (tree_view->priv->vadjustment->value
6002                                   + tree_view->priv->vadjustment->page_size))
6003                 {
6004                   /* row visible: keep the row at the same position */
6005                   area_above = dy - tree_view->priv->vadjustment->value;
6006                   area_below = (tree_view->priv->vadjustment->value +
6007                                 tree_view->priv->vadjustment->page_size)
6008                                - dy - height;
6009                 }
6010               else
6011                 {
6012                   /* row not visible */
6013                   if (dy >= 0
6014                       && dy + height <= tree_view->priv->vadjustment->page_size)
6015                     {
6016                       /* row at the beginning -- fixed */
6017                       area_above = dy;
6018                       area_below = tree_view->priv->vadjustment->page_size
6019                                    - area_above - height;
6020                     }
6021                   else if (dy >= (tree_view->priv->vadjustment->upper -
6022                                   tree_view->priv->vadjustment->page_size))
6023                     {
6024                       /* row at the end -- fixed */
6025                       area_above = dy - (tree_view->priv->vadjustment->upper -
6026                                    tree_view->priv->vadjustment->page_size);
6027                       area_below = tree_view->priv->vadjustment->page_size -
6028                                    area_above - height;
6029
6030                       if (area_below < 0)
6031                         {
6032                           area_above = tree_view->priv->vadjustment->page_size - height;
6033                           area_below = 0;
6034                         }
6035                     }
6036                   else
6037                     {
6038                       /* row somewhere in the middle, bring it to the top
6039                        * of the view
6040                        */
6041                       area_above = 0;
6042                       area_below = total_height - height;
6043                     }
6044                 }
6045             }
6046         }
6047       else
6048         /* the scroll to isn't valid; ignore it.
6049          */
6050         {
6051           if (tree_view->priv->scroll_to_path && !path)
6052             {
6053               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6054               tree_view->priv->scroll_to_path = NULL;
6055             }
6056           if (path)
6057             gtk_tree_path_free (path);
6058           path = NULL;
6059         }      
6060     }
6061
6062   /* We didn't have a scroll_to set, so we just handle things normally
6063    */
6064   if (path == NULL)
6065     {
6066       gint offset;
6067
6068       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6069                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6070                                         &tree, &node);
6071       if (node == NULL)
6072         {
6073           /* In this case, nothing has been validated */
6074           path = gtk_tree_path_new_first ();
6075           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6076         }
6077       else
6078         {
6079           path = _gtk_tree_view_find_path (tree_view, tree, node);
6080           total_height += offset;
6081         }
6082
6083       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6084
6085       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6086           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6087         {
6088           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6089           if (validate_row (tree_view, tree, node, &iter, path))
6090             size_changed = TRUE;
6091         }
6092       area_above = 0;
6093       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6094     }
6095
6096   above_path = gtk_tree_path_copy (path);
6097
6098   /* if we do not validate any row above the new top_row, we will make sure
6099    * that the row immediately above top_row has been validated. (if we do not
6100    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6101    * when invalidated that row's height will be zero. and this will mess up
6102    * scrolling).
6103    */
6104   if (area_above == 0)
6105     {
6106       GtkRBTree *tmptree;
6107       GtkRBNode *tmpnode;
6108
6109       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6110       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6111
6112       if (tmpnode)
6113         {
6114           GtkTreePath *tmppath;
6115           GtkTreeIter tmpiter;
6116
6117           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6118           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6119
6120           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6121               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6122             {
6123               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6124               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6125                 size_changed = TRUE;
6126             }
6127
6128           gtk_tree_path_free (tmppath);
6129         }
6130     }
6131
6132   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6133    * backwards is much slower then forward, as there is no iter_prev function.
6134    * We go forwards first in case we run out of tree.  Then we go backwards to
6135    * fill out the top.
6136    */
6137   while (node && area_below > 0)
6138     {
6139       if (node->children)
6140         {
6141           GtkTreeIter parent = iter;
6142           gboolean has_child;
6143
6144           tree = node->children;
6145           node = tree->root;
6146
6147           g_assert (node != tree->nil);
6148
6149           while (node->left != tree->nil)
6150             node = node->left;
6151           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6152                                                     &iter,
6153                                                     &parent);
6154           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6155           gtk_tree_path_down (path);
6156         }
6157       else
6158         {
6159           gboolean done = FALSE;
6160           do
6161             {
6162               node = _gtk_rbtree_next (tree, node);
6163               if (node != NULL)
6164                 {
6165                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6166                   done = TRUE;
6167                   gtk_tree_path_next (path);
6168
6169                   /* Sanity Check! */
6170                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6171                 }
6172               else
6173                 {
6174                   GtkTreeIter parent_iter = iter;
6175                   gboolean has_parent;
6176
6177                   node = tree->parent_node;
6178                   tree = tree->parent_tree;
6179                   if (tree == NULL)
6180                     break;
6181                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6182                                                            &iter,
6183                                                            &parent_iter);
6184                   gtk_tree_path_up (path);
6185
6186                   /* Sanity check */
6187                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6188                 }
6189             }
6190           while (!done);
6191         }
6192
6193       if (!node)
6194         break;
6195
6196       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6197           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6198         {
6199           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6200           if (validate_row (tree_view, tree, node, &iter, path))
6201               size_changed = TRUE;
6202         }
6203
6204       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6205     }
6206   gtk_tree_path_free (path);
6207
6208   /* If we ran out of tree, and have extra area_below left, we need to add it
6209    * to area_above */
6210   if (area_below > 0)
6211     area_above += area_below;
6212
6213   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6214
6215   /* We walk backwards */
6216   while (area_above > 0)
6217     {
6218       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6219
6220       /* Always find the new path in the tree.  We cannot just assume
6221        * a gtk_tree_path_prev() is enough here, as there might be children
6222        * in between this node and the previous sibling node.  If this
6223        * appears to be a performance hotspot in profiles, we can look into
6224        * intrigate logic for keeping path, node and iter in sync like
6225        * we do for forward walks.  (Which will be hard because of the lacking
6226        * iter_prev).
6227        */
6228
6229       if (node == NULL)
6230         break;
6231
6232       gtk_tree_path_free (above_path);
6233       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6234
6235       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6236
6237       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6238           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6239         {
6240           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6241           if (validate_row (tree_view, tree, node, &iter, above_path))
6242             size_changed = TRUE;
6243         }
6244       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6245     }
6246
6247   /* if we scrolled to a path, we need to set the dy here,
6248    * and sync the top row accordingly
6249    */
6250   if (tree_view->priv->scroll_to_path)
6251     {
6252       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6253       gtk_tree_view_top_row_to_dy (tree_view);
6254
6255       need_redraw = TRUE;
6256     }
6257   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6258     {
6259       /* when we are not scrolling, we should never set dy to something
6260        * else than zero. we update top_row to be in sync with dy = 0.
6261        */
6262       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6263       gtk_tree_view_dy_to_top_row (tree_view);
6264     }
6265   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6266     {
6267       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6268       gtk_tree_view_dy_to_top_row (tree_view);
6269     }
6270   else
6271     gtk_tree_view_top_row_to_dy (tree_view);
6272
6273   /* update width/height and queue a resize */
6274   if (size_changed)
6275     {
6276       GtkRequisition requisition;
6277
6278       /* We temporarily guess a size, under the assumption that it will be the
6279        * same when we get our next size_allocate.  If we don't do this, we'll be
6280        * in an inconsistent state if we call top_row_to_dy. */
6281
6282       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6283                                      &requisition, NULL);
6284       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6285       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6286       gtk_adjustment_changed (tree_view->priv->hadjustment);
6287       gtk_adjustment_changed (tree_view->priv->vadjustment);
6288       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6289     }
6290
6291   if (tree_view->priv->scroll_to_path)
6292     {
6293       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6294       tree_view->priv->scroll_to_path = NULL;
6295     }
6296
6297   if (above_path)
6298     gtk_tree_path_free (above_path);
6299
6300   if (tree_view->priv->scroll_to_column)
6301     {
6302       tree_view->priv->scroll_to_column = NULL;
6303     }
6304   if (need_redraw)
6305     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6306 }
6307
6308 static void
6309 initialize_fixed_height_mode (GtkTreeView *tree_view)
6310 {
6311   if (!tree_view->priv->tree)
6312     return;
6313
6314   if (tree_view->priv->fixed_height < 0)
6315     {
6316       GtkTreeIter iter;
6317       GtkTreePath *path;
6318
6319       GtkRBTree *tree = NULL;
6320       GtkRBNode *node = NULL;
6321
6322       tree = tree_view->priv->tree;
6323       node = tree->root;
6324
6325       path = _gtk_tree_view_find_path (tree_view, tree, node);
6326       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6327
6328       validate_row (tree_view, tree, node, &iter, path);
6329
6330       gtk_tree_path_free (path);
6331
6332       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6333     }
6334
6335    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6336                                  tree_view->priv->fixed_height, TRUE);
6337 }
6338
6339 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6340  * the left-most uninvalidated node.  We then try walking right, validating
6341  * nodes.  Once we find a valid node, we repeat the previous process of finding
6342  * the first invalid node.
6343  */
6344
6345 static gboolean
6346 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6347 {
6348   GtkRBTree *tree = NULL;
6349   GtkRBNode *node = NULL;
6350   gboolean validated_area = FALSE;
6351   gint retval = TRUE;
6352   GtkTreePath *path = NULL;
6353   GtkTreeIter iter;
6354   GTimer *timer;
6355   gint i = 0;
6356
6357   gint prev_height = -1;
6358   gboolean fixed_height = TRUE;
6359
6360   g_assert (tree_view);
6361
6362   if (tree_view->priv->tree == NULL)
6363       return FALSE;
6364
6365   if (tree_view->priv->fixed_height_mode)
6366     {
6367       if (tree_view->priv->fixed_height < 0)
6368         initialize_fixed_height_mode (tree_view);
6369
6370       return FALSE;
6371     }
6372
6373   timer = g_timer_new ();
6374   g_timer_start (timer);
6375
6376   do
6377     {
6378       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6379         {
6380           retval = FALSE;
6381           goto done;
6382         }
6383
6384       if (path != NULL)
6385         {
6386           node = _gtk_rbtree_next (tree, node);
6387           if (node != NULL)
6388             {
6389               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6390               gtk_tree_path_next (path);
6391             }
6392           else
6393             {
6394               gtk_tree_path_free (path);
6395               path = NULL;
6396             }
6397         }
6398
6399       if (path == NULL)
6400         {
6401           tree = tree_view->priv->tree;
6402           node = tree_view->priv->tree->root;
6403
6404           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6405
6406           do
6407             {
6408               if (node->left != tree->nil &&
6409                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6410                 {
6411                   node = node->left;
6412                 }
6413               else if (node->right != tree->nil &&
6414                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6415                 {
6416                   node = node->right;
6417                 }
6418               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6419                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6420                 {
6421                   break;
6422                 }
6423               else if (node->children != NULL)
6424                 {
6425                   tree = node->children;
6426                   node = tree->root;
6427                 }
6428               else
6429                 /* RBTree corruption!  All bad */
6430                 g_assert_not_reached ();
6431             }
6432           while (TRUE);
6433           path = _gtk_tree_view_find_path (tree_view, tree, node);
6434           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6435         }
6436
6437       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6438                        validated_area;
6439
6440       if (!tree_view->priv->fixed_height_check)
6441         {
6442           gint height;
6443
6444           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6445           if (prev_height < 0)
6446             prev_height = height;
6447           else if (prev_height != height)
6448             fixed_height = FALSE;
6449         }
6450
6451       i++;
6452     }
6453   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6454
6455   if (!tree_view->priv->fixed_height_check)
6456    {
6457      if (fixed_height)
6458        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6459
6460      tree_view->priv->fixed_height_check = 1;
6461    }
6462   
6463  done:
6464   if (validated_area)
6465     {
6466       GtkRequisition requisition;
6467
6468       /* We temporarily guess a size, under the assumption that it will be the
6469        * same when we get our next size_allocate.  If we don't do this, we'll be
6470        * in an inconsistent state when we call top_row_to_dy. */
6471
6472       /* FIXME: This is called from size_request, for some reason it is not infinitely
6473        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6474        * not allowed (from inside ->get_preferred_width/height() implementations, one
6475        * should call the vfuncs directly). However what is desired here is the full
6476        * size including any margins and limited by any alignment (i.e. after 
6477        * GtkWidget:adjust_size_request() is called).
6478        *
6479        * Currently bypassing this but the real solution is to not update the scroll adjustments
6480        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6481        */
6482       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition);
6483
6484       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6485       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6486       gtk_adjustment_changed (tree_view->priv->hadjustment);
6487       gtk_adjustment_changed (tree_view->priv->vadjustment);
6488
6489       if (queue_resize)
6490         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6491     }
6492
6493   if (path) gtk_tree_path_free (path);
6494   g_timer_destroy (timer);
6495
6496   return retval;
6497 }
6498
6499 static gboolean
6500 validate_rows (GtkTreeView *tree_view)
6501 {
6502   gboolean retval;
6503   
6504   retval = do_validate_rows (tree_view, TRUE);
6505   
6506   if (! retval && tree_view->priv->validate_rows_timer)
6507     {
6508       g_source_remove (tree_view->priv->validate_rows_timer);
6509       tree_view->priv->validate_rows_timer = 0;
6510     }
6511
6512   return retval;
6513 }
6514
6515 static gboolean
6516 validate_rows_handler (GtkTreeView *tree_view)
6517 {
6518   gboolean retval;
6519
6520   retval = do_validate_rows (tree_view, TRUE);
6521   if (! retval && tree_view->priv->validate_rows_timer)
6522     {
6523       g_source_remove (tree_view->priv->validate_rows_timer);
6524       tree_view->priv->validate_rows_timer = 0;
6525     }
6526
6527   return retval;
6528 }
6529
6530 static gboolean
6531 do_presize_handler (GtkTreeView *tree_view)
6532 {
6533   if (tree_view->priv->mark_rows_col_dirty)
6534     {
6535       if (tree_view->priv->tree)
6536         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6537       tree_view->priv->mark_rows_col_dirty = FALSE;
6538     }
6539   validate_visible_area (tree_view);
6540   tree_view->priv->presize_handler_timer = 0;
6541
6542   if (tree_view->priv->fixed_height_mode)
6543     {
6544       GtkRequisition requisition;
6545
6546       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6547                                      &requisition, NULL);
6548
6549       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6550       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6551       gtk_adjustment_changed (tree_view->priv->hadjustment);
6552       gtk_adjustment_changed (tree_view->priv->vadjustment);
6553       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6554     }
6555                    
6556   return FALSE;
6557 }
6558
6559 static gboolean
6560 presize_handler_callback (gpointer data)
6561 {
6562   do_presize_handler (GTK_TREE_VIEW (data));
6563                    
6564   return FALSE;
6565 }
6566
6567 static void
6568 install_presize_handler (GtkTreeView *tree_view)
6569 {
6570   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6571     return;
6572
6573   if (! tree_view->priv->presize_handler_timer)
6574     {
6575       tree_view->priv->presize_handler_timer =
6576         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6577     }
6578   if (! tree_view->priv->validate_rows_timer)
6579     {
6580       tree_view->priv->validate_rows_timer =
6581         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6582     }
6583 }
6584
6585 static void
6586 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6587 {
6588   /* Prior to drawing, we make sure the visible area is validated. */
6589   if (tree_view->priv->presize_handler_timer)
6590     {
6591       g_source_remove (tree_view->priv->presize_handler_timer);
6592       tree_view->priv->presize_handler_timer = 0;
6593
6594       do_presize_handler (tree_view);
6595     }
6596
6597   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6598 }
6599
6600 static gboolean
6601 scroll_sync_handler (GtkTreeView *tree_view)
6602 {
6603   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6604     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6605   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6606     gtk_tree_view_top_row_to_dy (tree_view);
6607   else
6608     gtk_tree_view_dy_to_top_row (tree_view);
6609
6610   tree_view->priv->scroll_sync_timer = 0;
6611
6612   return FALSE;
6613 }
6614
6615 static void
6616 install_scroll_sync_handler (GtkTreeView *tree_view)
6617 {
6618   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6619     return;
6620
6621   if (!tree_view->priv->scroll_sync_timer)
6622     {
6623       tree_view->priv->scroll_sync_timer =
6624         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6625     }
6626 }
6627
6628 static void
6629 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6630                            GtkTreePath *path,
6631                            gint         offset)
6632 {
6633   gtk_tree_row_reference_free (tree_view->priv->top_row);
6634
6635   if (!path)
6636     {
6637       tree_view->priv->top_row = NULL;
6638       tree_view->priv->top_row_dy = 0;
6639     }
6640   else
6641     {
6642       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6643       tree_view->priv->top_row_dy = offset;
6644     }
6645 }
6646
6647 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6648  * it's set to be NULL, and top_row_dy is 0;
6649  */
6650 static void
6651 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6652 {
6653   gint offset;
6654   GtkTreePath *path;
6655   GtkRBTree *tree;
6656   GtkRBNode *node;
6657
6658   if (tree_view->priv->tree == NULL)
6659     {
6660       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6661     }
6662   else
6663     {
6664       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6665                                         tree_view->priv->dy,
6666                                         &tree, &node);
6667
6668       if (tree == NULL)
6669         {
6670           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6671         }
6672       else
6673         {
6674           path = _gtk_tree_view_find_path (tree_view, tree, node);
6675           gtk_tree_view_set_top_row (tree_view, path, offset);
6676           gtk_tree_path_free (path);
6677         }
6678     }
6679 }
6680
6681 static void
6682 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6683 {
6684   GtkTreePath *path;
6685   GtkRBTree *tree;
6686   GtkRBNode *node;
6687   int new_dy;
6688
6689   /* Avoid recursive calls */
6690   if (tree_view->priv->in_top_row_to_dy)
6691     return;
6692
6693   if (tree_view->priv->top_row)
6694     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6695   else
6696     path = NULL;
6697
6698   if (!path)
6699     tree = NULL;
6700   else
6701     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6702
6703   if (path)
6704     gtk_tree_path_free (path);
6705
6706   if (tree == NULL)
6707     {
6708       /* keep dy and set new toprow */
6709       gtk_tree_row_reference_free (tree_view->priv->top_row);
6710       tree_view->priv->top_row = NULL;
6711       tree_view->priv->top_row_dy = 0;
6712       /* DO NOT install the idle handler */
6713       gtk_tree_view_dy_to_top_row (tree_view);
6714       return;
6715     }
6716
6717   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6718       < tree_view->priv->top_row_dy)
6719     {
6720       /* new top row -- do NOT install the idle handler */
6721       gtk_tree_view_dy_to_top_row (tree_view);
6722       return;
6723     }
6724
6725   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6726   new_dy += tree_view->priv->top_row_dy;
6727
6728   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6729     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6730
6731   new_dy = MAX (0, new_dy);
6732
6733   tree_view->priv->in_top_row_to_dy = TRUE;
6734   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6735   tree_view->priv->in_top_row_to_dy = FALSE;
6736 }
6737
6738
6739 void
6740 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6741 {
6742   tree_view->priv->mark_rows_col_dirty = TRUE;
6743
6744   install_presize_handler (tree_view);
6745 }
6746
6747 /*
6748  * This function works synchronously (due to the while (validate_rows...)
6749  * loop).
6750  *
6751  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6752  * here. You now need to check that yourself.
6753  */
6754 void
6755 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6756                                 GtkTreeViewColumn *column)
6757 {
6758   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6759   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6760
6761   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6762
6763   do_presize_handler (tree_view);
6764   while (validate_rows (tree_view));
6765
6766   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6767 }
6768
6769 /* Drag-and-drop */
6770
6771 static void
6772 set_source_row (GdkDragContext *context,
6773                 GtkTreeModel   *model,
6774                 GtkTreePath    *source_row)
6775 {
6776   g_object_set_data_full (G_OBJECT (context),
6777                           I_("gtk-tree-view-source-row"),
6778                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6779                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6780 }
6781
6782 static GtkTreePath*
6783 get_source_row (GdkDragContext *context)
6784 {
6785   GtkTreeRowReference *ref =
6786     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6787
6788   if (ref)
6789     return gtk_tree_row_reference_get_path (ref);
6790   else
6791     return NULL;
6792 }
6793
6794 typedef struct
6795 {
6796   GtkTreeRowReference *dest_row;
6797   guint                path_down_mode   : 1;
6798   guint                empty_view_drop  : 1;
6799   guint                drop_append_mode : 1;
6800 }
6801 DestRow;
6802
6803 static void
6804 dest_row_free (gpointer data)
6805 {
6806   DestRow *dr = (DestRow *)data;
6807
6808   gtk_tree_row_reference_free (dr->dest_row);
6809   g_slice_free (DestRow, dr);
6810 }
6811
6812 static void
6813 set_dest_row (GdkDragContext *context,
6814               GtkTreeModel   *model,
6815               GtkTreePath    *dest_row,
6816               gboolean        path_down_mode,
6817               gboolean        empty_view_drop,
6818               gboolean        drop_append_mode)
6819 {
6820   DestRow *dr;
6821
6822   if (!dest_row)
6823     {
6824       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6825                               NULL, NULL);
6826       return;
6827     }
6828
6829   dr = g_slice_new (DestRow);
6830
6831   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6832   dr->path_down_mode = path_down_mode != FALSE;
6833   dr->empty_view_drop = empty_view_drop != FALSE;
6834   dr->drop_append_mode = drop_append_mode != FALSE;
6835
6836   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6837                           dr, (GDestroyNotify) dest_row_free);
6838 }
6839
6840 static GtkTreePath*
6841 get_dest_row (GdkDragContext *context,
6842               gboolean       *path_down_mode)
6843 {
6844   DestRow *dr =
6845     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6846
6847   if (dr)
6848     {
6849       GtkTreePath *path = NULL;
6850
6851       if (path_down_mode)
6852         *path_down_mode = dr->path_down_mode;
6853
6854       if (dr->dest_row)
6855         path = gtk_tree_row_reference_get_path (dr->dest_row);
6856       else if (dr->empty_view_drop)
6857         path = gtk_tree_path_new_from_indices (0, -1);
6858       else
6859         path = NULL;
6860
6861       if (path && dr->drop_append_mode)
6862         gtk_tree_path_next (path);
6863
6864       return path;
6865     }
6866   else
6867     return NULL;
6868 }
6869
6870 /* Get/set whether drag_motion requested the drag data and
6871  * drag_data_received should thus not actually insert the data,
6872  * since the data doesn't result from a drop.
6873  */
6874 static void
6875 set_status_pending (GdkDragContext *context,
6876                     GdkDragAction   suggested_action)
6877 {
6878   g_object_set_data (G_OBJECT (context),
6879                      I_("gtk-tree-view-status-pending"),
6880                      GINT_TO_POINTER (suggested_action));
6881 }
6882
6883 static GdkDragAction
6884 get_status_pending (GdkDragContext *context)
6885 {
6886   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6887                                              "gtk-tree-view-status-pending"));
6888 }
6889
6890 static TreeViewDragInfo*
6891 get_info (GtkTreeView *tree_view)
6892 {
6893   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6894 }
6895
6896 static void
6897 destroy_info (TreeViewDragInfo *di)
6898 {
6899   g_slice_free (TreeViewDragInfo, di);
6900 }
6901
6902 static TreeViewDragInfo*
6903 ensure_info (GtkTreeView *tree_view)
6904 {
6905   TreeViewDragInfo *di;
6906
6907   di = get_info (tree_view);
6908
6909   if (di == NULL)
6910     {
6911       di = g_slice_new0 (TreeViewDragInfo);
6912
6913       g_object_set_data_full (G_OBJECT (tree_view),
6914                               I_("gtk-tree-view-drag-info"),
6915                               di,
6916                               (GDestroyNotify) destroy_info);
6917     }
6918
6919   return di;
6920 }
6921
6922 static void
6923 remove_info (GtkTreeView *tree_view)
6924 {
6925   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6926 }
6927
6928 #if 0
6929 static gint
6930 drag_scan_timeout (gpointer data)
6931 {
6932   GtkTreeView *tree_view;
6933   gint x, y;
6934   GdkModifierType state;
6935   GtkTreePath *path = NULL;
6936   GtkTreeViewColumn *column = NULL;
6937   GdkRectangle visible_rect;
6938
6939   GDK_THREADS_ENTER ();
6940
6941   tree_view = GTK_TREE_VIEW (data);
6942
6943   gdk_window_get_pointer (tree_view->priv->bin_window,
6944                           &x, &y, &state);
6945
6946   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6947
6948   /* See if we are near the edge. */
6949   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6950       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6951       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6952       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6953     {
6954       gtk_tree_view_get_path_at_pos (tree_view,
6955                                      tree_view->priv->bin_window,
6956                                      x, y,
6957                                      &path,
6958                                      &column,
6959                                      NULL,
6960                                      NULL);
6961
6962       if (path != NULL)
6963         {
6964           gtk_tree_view_scroll_to_cell (tree_view,
6965                                         path,
6966                                         column,
6967                                         TRUE,
6968                                         0.5, 0.5);
6969
6970           gtk_tree_path_free (path);
6971         }
6972     }
6973
6974   GDK_THREADS_LEAVE ();
6975
6976   return TRUE;
6977 }
6978 #endif /* 0 */
6979
6980 static void
6981 add_scroll_timeout (GtkTreeView *tree_view)
6982 {
6983   if (tree_view->priv->scroll_timeout == 0)
6984     {
6985       tree_view->priv->scroll_timeout =
6986         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6987     }
6988 }
6989
6990 static void
6991 remove_scroll_timeout (GtkTreeView *tree_view)
6992 {
6993   if (tree_view->priv->scroll_timeout != 0)
6994     {
6995       g_source_remove (tree_view->priv->scroll_timeout);
6996       tree_view->priv->scroll_timeout = 0;
6997     }
6998 }
6999
7000 static gboolean
7001 check_model_dnd (GtkTreeModel *model,
7002                  GType         required_iface,
7003                  const gchar  *signal)
7004 {
7005   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7006     {
7007       g_warning ("You must override the default '%s' handler "
7008                  "on GtkTreeView when using models that don't support "
7009                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7010                  "is to connect to '%s' and call "
7011                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7012                  "the default handler from running. Look at the source code "
7013                  "for the default handler in gtktreeview.c to get an idea what "
7014                  "your handler should do. (gtktreeview.c is in the GTK source "
7015                  "code.) If you're using GTK from a language other than C, "
7016                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7017                  signal, g_type_name (required_iface), signal);
7018       return FALSE;
7019     }
7020   else
7021     return TRUE;
7022 }
7023
7024 static void
7025 remove_open_timeout (GtkTreeView *tree_view)
7026 {
7027   if (tree_view->priv->open_dest_timeout != 0)
7028     {
7029       g_source_remove (tree_view->priv->open_dest_timeout);
7030       tree_view->priv->open_dest_timeout = 0;
7031     }
7032 }
7033
7034
7035 static gint
7036 open_row_timeout (gpointer data)
7037 {
7038   GtkTreeView *tree_view = data;
7039   GtkTreePath *dest_path = NULL;
7040   GtkTreeViewDropPosition pos;
7041   gboolean result = FALSE;
7042
7043   gtk_tree_view_get_drag_dest_row (tree_view,
7044                                    &dest_path,
7045                                    &pos);
7046
7047   if (dest_path &&
7048       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7049        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7050     {
7051       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7052       tree_view->priv->open_dest_timeout = 0;
7053
7054       gtk_tree_path_free (dest_path);
7055     }
7056   else
7057     {
7058       if (dest_path)
7059         gtk_tree_path_free (dest_path);
7060
7061       result = TRUE;
7062     }
7063
7064   return result;
7065 }
7066
7067 static gboolean
7068 scroll_row_timeout (gpointer data)
7069 {
7070   GtkTreeView *tree_view = data;
7071
7072   gtk_tree_view_vertical_autoscroll (tree_view);
7073
7074   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7075     gtk_tree_view_update_rubber_band (tree_view);
7076
7077   return TRUE;
7078 }
7079
7080 /* Returns TRUE if event should not be propagated to parent widgets */
7081 static gboolean
7082 set_destination_row (GtkTreeView    *tree_view,
7083                      GdkDragContext *context,
7084                      /* coordinates relative to the widget */
7085                      gint            x,
7086                      gint            y,
7087                      GdkDragAction  *suggested_action,
7088                      GdkAtom        *target)
7089 {
7090   GtkTreePath *path = NULL;
7091   GtkTreeViewDropPosition pos;
7092   GtkTreeViewDropPosition old_pos;
7093   TreeViewDragInfo *di;
7094   GtkWidget *widget;
7095   GtkTreePath *old_dest_path = NULL;
7096   gboolean can_drop = FALSE;
7097
7098   *suggested_action = 0;
7099   *target = GDK_NONE;
7100
7101   widget = GTK_WIDGET (tree_view);
7102
7103   di = get_info (tree_view);
7104
7105   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
7106     {
7107       /* someone unset us as a drag dest, note that if
7108        * we return FALSE drag_leave isn't called
7109        */
7110
7111       gtk_tree_view_set_drag_dest_row (tree_view,
7112                                        NULL,
7113                                        GTK_TREE_VIEW_DROP_BEFORE);
7114
7115       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7116       remove_open_timeout (GTK_TREE_VIEW (widget));
7117
7118       return FALSE; /* no longer a drop site */
7119     }
7120
7121   *target = gtk_drag_dest_find_target (widget, context,
7122                                        gtk_drag_dest_get_target_list (widget));
7123   if (*target == GDK_NONE)
7124     {
7125       return FALSE;
7126     }
7127
7128   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7129                                           x, y,
7130                                           &path,
7131                                           &pos))
7132     {
7133       gint n_children;
7134       GtkTreeModel *model;
7135
7136       remove_open_timeout (tree_view);
7137
7138       /* the row got dropped on empty space, let's setup a special case
7139        */
7140
7141       if (path)
7142         gtk_tree_path_free (path);
7143
7144       model = gtk_tree_view_get_model (tree_view);
7145
7146       n_children = gtk_tree_model_iter_n_children (model, NULL);
7147       if (n_children)
7148         {
7149           pos = GTK_TREE_VIEW_DROP_AFTER;
7150           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7151         }
7152       else
7153         {
7154           pos = GTK_TREE_VIEW_DROP_BEFORE;
7155           path = gtk_tree_path_new_from_indices (0, -1);
7156         }
7157
7158       can_drop = TRUE;
7159
7160       goto out;
7161     }
7162
7163   g_assert (path);
7164
7165   /* If we left the current row's "open" zone, unset the timeout for
7166    * opening the row
7167    */
7168   gtk_tree_view_get_drag_dest_row (tree_view,
7169                                    &old_dest_path,
7170                                    &old_pos);
7171
7172   if (old_dest_path &&
7173       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7174        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7175          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7176     remove_open_timeout (tree_view);
7177
7178   if (old_dest_path)
7179     gtk_tree_path_free (old_dest_path);
7180
7181   if (TRUE /* FIXME if the location droppable predicate */)
7182     {
7183       can_drop = TRUE;
7184     }
7185
7186 out:
7187   if (can_drop)
7188     {
7189       GtkWidget *source_widget;
7190
7191       *suggested_action = gdk_drag_context_get_suggested_action (context);
7192       source_widget = gtk_drag_get_source_widget (context);
7193
7194       if (source_widget == widget)
7195         {
7196           /* Default to MOVE, unless the user has
7197            * pressed ctrl or shift to affect available actions
7198            */
7199           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7200             *suggested_action = GDK_ACTION_MOVE;
7201         }
7202
7203       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7204                                        path, pos);
7205     }
7206   else
7207     {
7208       /* can't drop here */
7209       remove_open_timeout (tree_view);
7210
7211       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7212                                        NULL,
7213                                        GTK_TREE_VIEW_DROP_BEFORE);
7214     }
7215
7216   if (path)
7217     gtk_tree_path_free (path);
7218
7219   return TRUE;
7220 }
7221
7222 static GtkTreePath*
7223 get_logical_dest_row (GtkTreeView *tree_view,
7224                       gboolean    *path_down_mode,
7225                       gboolean    *drop_append_mode)
7226 {
7227   /* adjust path to point to the row the drop goes in front of */
7228   GtkTreePath *path = NULL;
7229   GtkTreeViewDropPosition pos;
7230
7231   g_return_val_if_fail (path_down_mode != NULL, NULL);
7232   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7233
7234   *path_down_mode = FALSE;
7235   *drop_append_mode = 0;
7236
7237   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7238
7239   if (path == NULL)
7240     return NULL;
7241
7242   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7243     ; /* do nothing */
7244   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7245            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7246     *path_down_mode = TRUE;
7247   else
7248     {
7249       GtkTreeIter iter;
7250       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7251
7252       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7253
7254       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7255           !gtk_tree_model_iter_next (model, &iter))
7256         *drop_append_mode = 1;
7257       else
7258         {
7259           *drop_append_mode = 0;
7260           gtk_tree_path_next (path);
7261         }
7262     }
7263
7264   return path;
7265 }
7266
7267 static gboolean
7268 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7269                                         GdkEventMotion   *event)
7270 {
7271   GtkWidget *widget = GTK_WIDGET (tree_view);
7272   GdkDragContext *context;
7273   TreeViewDragInfo *di;
7274   GtkTreePath *path = NULL;
7275   gint button;
7276   gint cell_x, cell_y;
7277   GtkTreeModel *model;
7278   gboolean retval = FALSE;
7279
7280   di = get_info (tree_view);
7281
7282   if (di == NULL || !di->source_set)
7283     goto out;
7284
7285   if (tree_view->priv->pressed_button < 0)
7286     goto out;
7287
7288   if (!gtk_drag_check_threshold (widget,
7289                                  tree_view->priv->press_start_x,
7290                                  tree_view->priv->press_start_y,
7291                                  event->x, event->y))
7292     goto out;
7293
7294   model = gtk_tree_view_get_model (tree_view);
7295
7296   if (model == NULL)
7297     goto out;
7298
7299   button = tree_view->priv->pressed_button;
7300   tree_view->priv->pressed_button = -1;
7301
7302   gtk_tree_view_get_path_at_pos (tree_view,
7303                                  tree_view->priv->press_start_x,
7304                                  tree_view->priv->press_start_y,
7305                                  &path,
7306                                  NULL,
7307                                  &cell_x,
7308                                  &cell_y);
7309
7310   if (path == NULL)
7311     goto out;
7312
7313   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7314       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7315                                            path))
7316     goto out;
7317
7318   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7319     goto out;
7320
7321   /* Now we can begin the drag */
7322
7323   retval = TRUE;
7324
7325   context = gtk_drag_begin (widget,
7326                             gtk_drag_source_get_target_list (widget),
7327                             di->source_actions,
7328                             button,
7329                             (GdkEvent*)event);
7330
7331   set_source_row (context, model, path);
7332
7333  out:
7334   if (path)
7335     gtk_tree_path_free (path);
7336
7337   return retval;
7338 }
7339
7340
7341 static void
7342 gtk_tree_view_drag_begin (GtkWidget      *widget,
7343                           GdkDragContext *context)
7344 {
7345   GtkTreeView *tree_view;
7346   GtkTreePath *path = NULL;
7347   gint cell_x, cell_y;
7348   cairo_surface_t *row_pix;
7349   TreeViewDragInfo *di;
7350
7351   tree_view = GTK_TREE_VIEW (widget);
7352
7353   /* if the user uses a custom DND source impl, we don't set the icon here */
7354   di = get_info (tree_view);
7355
7356   if (di == NULL || !di->source_set)
7357     return;
7358
7359   gtk_tree_view_get_path_at_pos (tree_view,
7360                                  tree_view->priv->press_start_x,
7361                                  tree_view->priv->press_start_y,
7362                                  &path,
7363                                  NULL,
7364                                  &cell_x,
7365                                  &cell_y);
7366
7367   g_return_if_fail (path != NULL);
7368
7369   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7370                                                 path);
7371   cairo_surface_set_device_offset (row_pix,
7372                                    /* the + 1 is for the black border in the icon */
7373                                    - (tree_view->priv->press_start_x + 1),
7374                                    - (cell_y + 1));
7375
7376   gtk_drag_set_icon_surface (context, row_pix);
7377
7378   cairo_surface_destroy (row_pix);
7379   gtk_tree_path_free (path);
7380 }
7381
7382 static void
7383 gtk_tree_view_drag_end (GtkWidget      *widget,
7384                         GdkDragContext *context)
7385 {
7386   /* do nothing */
7387 }
7388
7389 /* Default signal implementations for the drag signals */
7390 static void
7391 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7392                              GdkDragContext   *context,
7393                              GtkSelectionData *selection_data,
7394                              guint             info,
7395                              guint             time)
7396 {
7397   GtkTreeView *tree_view;
7398   GtkTreeModel *model;
7399   TreeViewDragInfo *di;
7400   GtkTreePath *source_row;
7401
7402   tree_view = GTK_TREE_VIEW (widget);
7403
7404   model = gtk_tree_view_get_model (tree_view);
7405
7406   if (model == NULL)
7407     return;
7408
7409   di = get_info (GTK_TREE_VIEW (widget));
7410
7411   if (di == NULL)
7412     return;
7413
7414   source_row = get_source_row (context);
7415
7416   if (source_row == NULL)
7417     return;
7418
7419   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7420    * any model; for DragSource models there are some other targets
7421    * we also support.
7422    */
7423
7424   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7425       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7426                                           source_row,
7427                                           selection_data))
7428     goto done;
7429
7430   /* If drag_data_get does nothing, try providing row data. */
7431   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7432     {
7433       gtk_tree_set_row_drag_data (selection_data,
7434                                   model,
7435                                   source_row);
7436     }
7437
7438  done:
7439   gtk_tree_path_free (source_row);
7440 }
7441
7442
7443 static void
7444 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7445                                 GdkDragContext *context)
7446 {
7447   TreeViewDragInfo *di;
7448   GtkTreeModel *model;
7449   GtkTreeView *tree_view;
7450   GtkTreePath *source_row;
7451
7452   tree_view = GTK_TREE_VIEW (widget);
7453   model = gtk_tree_view_get_model (tree_view);
7454
7455   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7456     return;
7457
7458   di = get_info (tree_view);
7459
7460   if (di == NULL)
7461     return;
7462
7463   source_row = get_source_row (context);
7464
7465   if (source_row == NULL)
7466     return;
7467
7468   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7469                                          source_row);
7470
7471   gtk_tree_path_free (source_row);
7472
7473   set_source_row (context, NULL, NULL);
7474 }
7475
7476 static void
7477 gtk_tree_view_drag_leave (GtkWidget      *widget,
7478                           GdkDragContext *context,
7479                           guint             time)
7480 {
7481   /* unset any highlight row */
7482   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7483                                    NULL,
7484                                    GTK_TREE_VIEW_DROP_BEFORE);
7485
7486   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7487   remove_open_timeout (GTK_TREE_VIEW (widget));
7488 }
7489
7490
7491 static gboolean
7492 gtk_tree_view_drag_motion (GtkWidget        *widget,
7493                            GdkDragContext   *context,
7494                            /* coordinates relative to the widget */
7495                            gint              x,
7496                            gint              y,
7497                            guint             time)
7498 {
7499   gboolean empty;
7500   GtkTreePath *path = NULL;
7501   GtkTreeViewDropPosition pos;
7502   GtkTreeView *tree_view;
7503   GdkDragAction suggested_action = 0;
7504   GdkAtom target;
7505
7506   tree_view = GTK_TREE_VIEW (widget);
7507
7508   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7509     return FALSE;
7510
7511   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7512
7513   /* we only know this *after* set_desination_row */
7514   empty = tree_view->priv->empty_view_drop;
7515
7516   if (path == NULL && !empty)
7517     {
7518       /* Can't drop here. */
7519       gdk_drag_status (context, 0, time);
7520     }
7521   else
7522     {
7523       if (tree_view->priv->open_dest_timeout == 0 &&
7524           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7525            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7526         {
7527           tree_view->priv->open_dest_timeout =
7528             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7529         }
7530       else
7531         {
7532           add_scroll_timeout (tree_view);
7533         }
7534
7535       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7536         {
7537           /* Request data so we can use the source row when
7538            * determining whether to accept the drop
7539            */
7540           set_status_pending (context, suggested_action);
7541           gtk_drag_get_data (widget, context, target, time);
7542         }
7543       else
7544         {
7545           set_status_pending (context, 0);
7546           gdk_drag_status (context, suggested_action, time);
7547         }
7548     }
7549
7550   if (path)
7551     gtk_tree_path_free (path);
7552
7553   return TRUE;
7554 }
7555
7556
7557 static gboolean
7558 gtk_tree_view_drag_drop (GtkWidget        *widget,
7559                          GdkDragContext   *context,
7560                          /* coordinates relative to the widget */
7561                          gint              x,
7562                          gint              y,
7563                          guint             time)
7564 {
7565   GtkTreeView *tree_view;
7566   GtkTreePath *path;
7567   GdkDragAction suggested_action = 0;
7568   GdkAtom target = GDK_NONE;
7569   TreeViewDragInfo *di;
7570   GtkTreeModel *model;
7571   gboolean path_down_mode;
7572   gboolean drop_append_mode;
7573
7574   tree_view = GTK_TREE_VIEW (widget);
7575
7576   model = gtk_tree_view_get_model (tree_view);
7577
7578   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7579   remove_open_timeout (GTK_TREE_VIEW (widget));
7580
7581   di = get_info (tree_view);
7582
7583   if (di == NULL)
7584     return FALSE;
7585
7586   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7587     return FALSE;
7588
7589   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7590     return FALSE;
7591
7592   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7593
7594   if (target != GDK_NONE && path != NULL)
7595     {
7596       /* in case a motion had requested drag data, change things so we
7597        * treat drag data receives as a drop.
7598        */
7599       set_status_pending (context, 0);
7600       set_dest_row (context, model, path,
7601                     path_down_mode, tree_view->priv->empty_view_drop,
7602                     drop_append_mode);
7603     }
7604
7605   if (path)
7606     gtk_tree_path_free (path);
7607
7608   /* Unset this thing */
7609   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7610                                    NULL,
7611                                    GTK_TREE_VIEW_DROP_BEFORE);
7612
7613   if (target != GDK_NONE)
7614     {
7615       gtk_drag_get_data (widget, context, target, time);
7616       return TRUE;
7617     }
7618   else
7619     return FALSE;
7620 }
7621
7622 static void
7623 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7624                                   GdkDragContext   *context,
7625                                   /* coordinates relative to the widget */
7626                                   gint              x,
7627                                   gint              y,
7628                                   GtkSelectionData *selection_data,
7629                                   guint             info,
7630                                   guint             time)
7631 {
7632   GtkTreePath *path;
7633   TreeViewDragInfo *di;
7634   gboolean accepted = FALSE;
7635   GtkTreeModel *model;
7636   GtkTreeView *tree_view;
7637   GtkTreePath *dest_row;
7638   GdkDragAction suggested_action;
7639   gboolean path_down_mode;
7640   gboolean drop_append_mode;
7641
7642   tree_view = GTK_TREE_VIEW (widget);
7643
7644   model = gtk_tree_view_get_model (tree_view);
7645
7646   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7647     return;
7648
7649   di = get_info (tree_view);
7650
7651   if (di == NULL)
7652     return;
7653
7654   suggested_action = get_status_pending (context);
7655
7656   if (suggested_action)
7657     {
7658       /* We are getting this data due to a request in drag_motion,
7659        * rather than due to a request in drag_drop, so we are just
7660        * supposed to call drag_status, not actually paste in the
7661        * data.
7662        */
7663       path = get_logical_dest_row (tree_view, &path_down_mode,
7664                                    &drop_append_mode);
7665
7666       if (path == NULL)
7667         suggested_action = 0;
7668       else if (path_down_mode)
7669         gtk_tree_path_down (path);
7670
7671       if (suggested_action)
7672         {
7673           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7674                                                      path,
7675                                                      selection_data))
7676             {
7677               if (path_down_mode)
7678                 {
7679                   path_down_mode = FALSE;
7680                   gtk_tree_path_up (path);
7681
7682                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7683                                                              path,
7684                                                              selection_data))
7685                     suggested_action = 0;
7686                 }
7687               else
7688                 suggested_action = 0;
7689             }
7690         }
7691
7692       gdk_drag_status (context, suggested_action, time);
7693
7694       if (path)
7695         gtk_tree_path_free (path);
7696
7697       /* If you can't drop, remove user drop indicator until the next motion */
7698       if (suggested_action == 0)
7699         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7700                                          NULL,
7701                                          GTK_TREE_VIEW_DROP_BEFORE);
7702
7703       return;
7704     }
7705
7706   dest_row = get_dest_row (context, &path_down_mode);
7707
7708   if (dest_row == NULL)
7709     return;
7710
7711   if (selection_data->length >= 0)
7712     {
7713       if (path_down_mode)
7714         {
7715           gtk_tree_path_down (dest_row);
7716           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7717                                                      dest_row, selection_data))
7718             gtk_tree_path_up (dest_row);
7719         }
7720     }
7721
7722   if (selection_data->length >= 0)
7723     {
7724       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7725                                                  dest_row,
7726                                                  selection_data))
7727         accepted = TRUE;
7728     }
7729
7730   gtk_drag_finish (context,
7731                    accepted,
7732                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
7733                    time);
7734
7735   if (gtk_tree_path_get_depth (dest_row) == 1
7736       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7737     {
7738       /* special special case drag to "0", scroll to first item */
7739       if (!tree_view->priv->scroll_to_path)
7740         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7741     }
7742
7743   gtk_tree_path_free (dest_row);
7744
7745   /* drop dest_row */
7746   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7747 }
7748
7749
7750
7751 /* GtkContainer Methods
7752  */
7753
7754
7755 static void
7756 gtk_tree_view_remove (GtkContainer *container,
7757                       GtkWidget    *widget)
7758 {
7759   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7760   GtkTreeViewChild *child = NULL;
7761   GList *tmp_list;
7762
7763   tmp_list = tree_view->priv->children;
7764   while (tmp_list)
7765     {
7766       child = tmp_list->data;
7767       if (child->widget == widget)
7768         {
7769           gtk_widget_unparent (widget);
7770
7771           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7772           g_list_free_1 (tmp_list);
7773           g_slice_free (GtkTreeViewChild, child);
7774           return;
7775         }
7776
7777       tmp_list = tmp_list->next;
7778     }
7779
7780   tmp_list = tree_view->priv->columns;
7781
7782   while (tmp_list)
7783     {
7784       GtkTreeViewColumn *column;
7785       column = tmp_list->data;
7786       if (column->button == widget)
7787         {
7788           gtk_widget_unparent (widget);
7789           return;
7790         }
7791       tmp_list = tmp_list->next;
7792     }
7793 }
7794
7795 static void
7796 gtk_tree_view_forall (GtkContainer *container,
7797                       gboolean      include_internals,
7798                       GtkCallback   callback,
7799                       gpointer      callback_data)
7800 {
7801   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7802   GtkTreeViewChild *child = NULL;
7803   GtkTreeViewColumn *column;
7804   GList *tmp_list;
7805
7806   tmp_list = tree_view->priv->children;
7807   while (tmp_list)
7808     {
7809       child = tmp_list->data;
7810       tmp_list = tmp_list->next;
7811
7812       (* callback) (child->widget, callback_data);
7813     }
7814   if (include_internals == FALSE)
7815     return;
7816
7817   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7818     {
7819       column = tmp_list->data;
7820
7821       if (column->button)
7822         (* callback) (column->button, callback_data);
7823     }
7824 }
7825
7826 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7827  * cells. If so we draw one big row-spanning focus rectangle.
7828  */
7829 static gboolean
7830 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7831 {
7832   GList *list;
7833
7834   for (list = tree_view->priv->columns; list; list = list->next)
7835     {
7836       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
7837         continue;
7838       if (_gtk_tree_view_column_count_special_cells (list->data))
7839         return TRUE;
7840     }
7841
7842   return FALSE;
7843 }
7844
7845 static void
7846 column_sizing_notify (GObject    *object,
7847                       GParamSpec *pspec,
7848                       gpointer    data)
7849 {
7850   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7851
7852   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7853     /* disable fixed height mode */
7854     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7855 }
7856
7857 /**
7858  * gtk_tree_view_set_fixed_height_mode:
7859  * @tree_view: a #GtkTreeView 
7860  * @enable: %TRUE to enable fixed height mode
7861  * 
7862  * Enables or disables the fixed height mode of @tree_view. 
7863  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7864  * rows have the same height. 
7865  * Only enable this option if all rows are the same height and all
7866  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7867  *
7868  * Since: 2.6 
7869  **/
7870 void
7871 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7872                                      gboolean     enable)
7873 {
7874   GList *l;
7875   
7876   enable = enable != FALSE;
7877
7878   if (enable == tree_view->priv->fixed_height_mode)
7879     return;
7880
7881   if (!enable)
7882     {
7883       tree_view->priv->fixed_height_mode = 0;
7884       tree_view->priv->fixed_height = -1;
7885
7886       /* force a revalidation */
7887       install_presize_handler (tree_view);
7888     }
7889   else 
7890     {
7891       /* make sure all columns are of type FIXED */
7892       for (l = tree_view->priv->columns; l; l = l->next)
7893         {
7894           GtkTreeViewColumn *c = l->data;
7895           
7896           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7897         }
7898       
7899       /* yes, we really have to do this is in a separate loop */
7900       for (l = tree_view->priv->columns; l; l = l->next)
7901         g_signal_connect (l->data, "notify::sizing",
7902                           G_CALLBACK (column_sizing_notify), tree_view);
7903       
7904       tree_view->priv->fixed_height_mode = 1;
7905       tree_view->priv->fixed_height = -1;
7906       
7907       if (tree_view->priv->tree)
7908         initialize_fixed_height_mode (tree_view);
7909     }
7910
7911   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7912 }
7913
7914 /**
7915  * gtk_tree_view_get_fixed_height_mode:
7916  * @tree_view: a #GtkTreeView
7917  * 
7918  * Returns whether fixed height mode is turned on for @tree_view.
7919  * 
7920  * Return value: %TRUE if @tree_view is in fixed height mode
7921  * 
7922  * Since: 2.6
7923  **/
7924 gboolean
7925 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7926 {
7927   return tree_view->priv->fixed_height_mode;
7928 }
7929
7930 /* Returns TRUE if the focus is within the headers, after the focus operation is
7931  * done
7932  */
7933 static gboolean
7934 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7935                             GtkDirectionType  dir,
7936                             gboolean          clamp_column_visible)
7937 {
7938   GtkTreeViewColumn *column;
7939   GtkWidget *focus_child;
7940
7941   GList *last_column, *first_column;
7942   GList *tmp_list;
7943   gboolean rtl;
7944
7945   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7946     return FALSE;
7947
7948   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
7949
7950   first_column = tree_view->priv->columns;
7951   while (first_column)
7952     {
7953       column = GTK_TREE_VIEW_COLUMN (first_column->data);
7954
7955       if (gtk_widget_get_can_focus (column->button) &&
7956           gtk_tree_view_column_get_visible (column) &&
7957           (gtk_tree_view_column_get_clickable (column) ||
7958            gtk_tree_view_column_get_reorderable (column)))
7959         break;
7960       first_column = first_column->next;
7961     }
7962
7963   /* No headers are visible, or are focusable.  We can't focus in or out.
7964    */
7965   if (first_column == NULL)
7966     return FALSE;
7967
7968   last_column = g_list_last (tree_view->priv->columns);
7969   while (last_column)
7970     {
7971       column = GTK_TREE_VIEW_COLUMN (last_column->data);
7972
7973       if (gtk_widget_get_can_focus (column->button) &&
7974           gtk_tree_view_column_get_visible (column) &&
7975           (gtk_tree_view_column_get_clickable (column) ||
7976            gtk_tree_view_column_get_reorderable (column)))
7977         break;
7978       last_column = last_column->prev;
7979     }
7980
7981
7982   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7983
7984   switch (dir)
7985     {
7986     case GTK_DIR_TAB_BACKWARD:
7987     case GTK_DIR_TAB_FORWARD:
7988     case GTK_DIR_UP:
7989     case GTK_DIR_DOWN:
7990       if (focus_child == NULL)
7991         {
7992           if (tree_view->priv->focus_column != NULL &&
7993               gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
7994             focus_child = tree_view->priv->focus_column->button;
7995           else
7996             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7997           gtk_widget_grab_focus (focus_child);
7998           break;
7999         }
8000       return FALSE;
8001
8002     case GTK_DIR_LEFT:
8003     case GTK_DIR_RIGHT:
8004       if (focus_child == NULL)
8005         {
8006           if (tree_view->priv->focus_column != NULL)
8007             focus_child = tree_view->priv->focus_column->button;
8008           else if (dir == GTK_DIR_LEFT)
8009             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
8010           else
8011             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
8012           gtk_widget_grab_focus (focus_child);
8013           break;
8014         }
8015
8016       if (gtk_widget_child_focus (focus_child, dir))
8017         {
8018           /* The focus moves inside the button. */
8019           /* This is probably a great example of bad UI */
8020           break;
8021         }
8022
8023       /* We need to move the focus among the row of buttons. */
8024       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8025         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
8026           break;
8027
8028       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8029           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8030         {
8031           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8032           break;
8033         }
8034
8035       while (tmp_list)
8036         {
8037           GtkTreeViewColumn *column;
8038
8039           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8040             tmp_list = tmp_list->next;
8041           else
8042             tmp_list = tmp_list->prev;
8043
8044           if (tmp_list == NULL)
8045             {
8046               g_warning ("Internal button not found");
8047               break;
8048             }
8049           column = tmp_list->data;
8050           if (column->button &&
8051               gtk_tree_view_column_get_visible (column) &&
8052               gtk_widget_get_can_focus (column->button))
8053             {
8054               focus_child = column->button;
8055               gtk_widget_grab_focus (column->button);
8056               break;
8057             }
8058         }
8059       break;
8060     default:
8061       g_assert_not_reached ();
8062       break;
8063     }
8064
8065   /* if focus child is non-null, we assume it's been set to the current focus child
8066    */
8067   if (focus_child)
8068     {
8069       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8070         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
8071           {
8072             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8073             break;
8074           }
8075
8076       if (clamp_column_visible)
8077         {
8078           gtk_tree_view_clamp_column_visible (tree_view,
8079                                               tree_view->priv->focus_column,
8080                                               FALSE);
8081         }
8082     }
8083
8084   return (focus_child != NULL);
8085 }
8086
8087 /* This function returns in 'path' the first focusable path, if the given path
8088  * is already focusable, it's the returned one.
8089  */
8090 static gboolean
8091 search_first_focusable_path (GtkTreeView  *tree_view,
8092                              GtkTreePath **path,
8093                              gboolean      search_forward,
8094                              GtkRBTree   **new_tree,
8095                              GtkRBNode   **new_node)
8096 {
8097   GtkRBTree *tree = NULL;
8098   GtkRBNode *node = NULL;
8099
8100   if (!path || !*path)
8101     return FALSE;
8102
8103   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8104
8105   if (!tree || !node)
8106     return FALSE;
8107
8108   while (node && row_is_separator (tree_view, NULL, *path))
8109     {
8110       if (search_forward)
8111         _gtk_rbtree_next_full (tree, node, &tree, &node);
8112       else
8113         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8114
8115       if (*path)
8116         gtk_tree_path_free (*path);
8117
8118       if (node)
8119         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8120       else
8121         *path = NULL;
8122     }
8123
8124   if (new_tree)
8125     *new_tree = tree;
8126
8127   if (new_node)
8128     *new_node = node;
8129
8130   return (*path != NULL);
8131 }
8132
8133 static gint
8134 gtk_tree_view_focus (GtkWidget        *widget,
8135                      GtkDirectionType  direction)
8136 {
8137   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8138   GtkContainer *container = GTK_CONTAINER (widget);
8139   GtkWidget *focus_child;
8140
8141   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8142     return FALSE;
8143
8144   focus_child = gtk_container_get_focus_child (container);
8145
8146   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8147   /* Case 1.  Headers currently have focus. */
8148   if (focus_child)
8149     {
8150       switch (direction)
8151         {
8152         case GTK_DIR_LEFT:
8153         case GTK_DIR_RIGHT:
8154           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8155           return TRUE;
8156         case GTK_DIR_TAB_BACKWARD:
8157         case GTK_DIR_UP:
8158           return FALSE;
8159         case GTK_DIR_TAB_FORWARD:
8160         case GTK_DIR_DOWN:
8161           gtk_widget_grab_focus (widget);
8162           return TRUE;
8163         default:
8164           g_assert_not_reached ();
8165           return FALSE;
8166         }
8167     }
8168
8169   /* Case 2. We don't have focus at all. */
8170   if (!gtk_widget_has_focus (widget))
8171     {
8172       gtk_widget_grab_focus (widget);
8173       return TRUE;
8174     }
8175
8176   /* Case 3. We have focus already. */
8177   if (direction == GTK_DIR_TAB_BACKWARD)
8178     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8179   else if (direction == GTK_DIR_TAB_FORWARD)
8180     return FALSE;
8181
8182   /* Other directions caught by the keybindings */
8183   gtk_widget_grab_focus (widget);
8184   return TRUE;
8185 }
8186
8187 static void
8188 gtk_tree_view_grab_focus (GtkWidget *widget)
8189 {
8190   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8191
8192   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8193 }
8194
8195 static void
8196 gtk_tree_view_style_set (GtkWidget *widget,
8197                          GtkStyle *previous_style)
8198 {
8199   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8200   GtkStyle *style;
8201   GList *list;
8202   GtkTreeViewColumn *column;
8203
8204   if (gtk_widget_get_realized (widget))
8205     {
8206       style = gtk_widget_get_style (widget);
8207       gdk_window_set_background (tree_view->priv->bin_window,
8208                                  &style->base[gtk_widget_get_state (widget)]);
8209       gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8210
8211       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8212       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8213     }
8214
8215   gtk_widget_style_get (widget,
8216                         "expander-size", &tree_view->priv->expander_size,
8217                         NULL);
8218   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8219
8220   for (list = tree_view->priv->columns; list; list = list->next)
8221     {
8222       column = list->data;
8223       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8224     }
8225
8226   tree_view->priv->fixed_height = -1;
8227   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8228
8229   gtk_widget_queue_resize (widget);
8230 }
8231
8232
8233 static void
8234 gtk_tree_view_set_focus_child (GtkContainer *container,
8235                                GtkWidget    *child)
8236 {
8237   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8238   GList *list;
8239
8240   for (list = tree_view->priv->columns; list; list = list->next)
8241     {
8242       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8243         {
8244           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8245           break;
8246         }
8247     }
8248
8249   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8250 }
8251
8252 static gboolean
8253 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8254                                 GtkMovementStep    step,
8255                                 gint               count)
8256 {
8257   GdkModifierType state;
8258
8259   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8260   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8261                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8262                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8263                         step == GTK_MOVEMENT_PAGES ||
8264                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8265
8266   if (tree_view->priv->tree == NULL)
8267     return FALSE;
8268   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8269     return FALSE;
8270
8271   gtk_tree_view_stop_editing (tree_view, FALSE);
8272   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8273   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8274
8275   if (gtk_get_current_event_state (&state))
8276     {
8277       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8278         tree_view->priv->ctrl_pressed = TRUE;
8279       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8280         tree_view->priv->shift_pressed = TRUE;
8281     }
8282   /* else we assume not pressed */
8283
8284   switch (step)
8285     {
8286       /* currently we make no distinction.  When we go bi-di, we need to */
8287     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8288     case GTK_MOVEMENT_VISUAL_POSITIONS:
8289       gtk_tree_view_move_cursor_left_right (tree_view, count);
8290       break;
8291     case GTK_MOVEMENT_DISPLAY_LINES:
8292       gtk_tree_view_move_cursor_up_down (tree_view, count);
8293       break;
8294     case GTK_MOVEMENT_PAGES:
8295       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8296       break;
8297     case GTK_MOVEMENT_BUFFER_ENDS:
8298       gtk_tree_view_move_cursor_start_end (tree_view, count);
8299       break;
8300     default:
8301       g_assert_not_reached ();
8302     }
8303
8304   tree_view->priv->ctrl_pressed = FALSE;
8305   tree_view->priv->shift_pressed = FALSE;
8306
8307   return TRUE;
8308 }
8309
8310 static void
8311 gtk_tree_view_put (GtkTreeView *tree_view,
8312                    GtkWidget   *child_widget,
8313                    /* in bin_window coordinates */
8314                    gint         x,
8315                    gint         y,
8316                    gint         width,
8317                    gint         height)
8318 {
8319   GtkTreeViewChild *child;
8320   
8321   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8322   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8323
8324   child = g_slice_new (GtkTreeViewChild);
8325
8326   child->widget = child_widget;
8327   child->x = x;
8328   child->y = y;
8329   child->width = width;
8330   child->height = height;
8331
8332   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8333
8334   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8335     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8336   
8337   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8338 }
8339
8340 void
8341 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8342                                   GtkWidget   *widget,
8343                                   /* in tree coordinates */
8344                                   gint         x,
8345                                   gint         y,
8346                                   gint         width,
8347                                   gint         height)
8348 {
8349   GtkTreeViewChild *child = NULL;
8350   GList *list;
8351   GdkRectangle allocation;
8352
8353   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8354   g_return_if_fail (GTK_IS_WIDGET (widget));
8355
8356   for (list = tree_view->priv->children; list; list = list->next)
8357     {
8358       if (((GtkTreeViewChild *)list->data)->widget == widget)
8359         {
8360           child = list->data;
8361           break;
8362         }
8363     }
8364   if (child == NULL)
8365     return;
8366
8367   allocation.x = child->x = x;
8368   allocation.y = child->y = y;
8369   allocation.width = child->width = width;
8370   allocation.height = child->height = height;
8371
8372   if (gtk_widget_get_realized (widget))
8373     gtk_widget_size_allocate (widget, &allocation);
8374 }
8375
8376
8377 /* TreeModel Callbacks
8378  */
8379
8380 static void
8381 gtk_tree_view_row_changed (GtkTreeModel *model,
8382                            GtkTreePath  *path,
8383                            GtkTreeIter  *iter,
8384                            gpointer      data)
8385 {
8386   GtkTreeView *tree_view = (GtkTreeView *)data;
8387   GtkRBTree *tree;
8388   GtkRBNode *node;
8389   gboolean free_path = FALSE;
8390   GList *list;
8391   GtkTreePath *cursor_path;
8392
8393   g_return_if_fail (path != NULL || iter != NULL);
8394
8395   if (tree_view->priv->cursor != NULL)
8396     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8397   else
8398     cursor_path = NULL;
8399
8400   if (tree_view->priv->edited_column &&
8401       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8402     gtk_tree_view_stop_editing (tree_view, TRUE);
8403
8404   if (cursor_path != NULL)
8405     gtk_tree_path_free (cursor_path);
8406
8407   if (path == NULL)
8408     {
8409       path = gtk_tree_model_get_path (model, iter);
8410       free_path = TRUE;
8411     }
8412   else if (iter == NULL)
8413     gtk_tree_model_get_iter (model, iter, path);
8414
8415   if (_gtk_tree_view_find_node (tree_view,
8416                                 path,
8417                                 &tree,
8418                                 &node))
8419     /* We aren't actually showing the node */
8420     goto done;
8421
8422   if (tree == NULL)
8423     goto done;
8424
8425   if (tree_view->priv->fixed_height_mode
8426       && tree_view->priv->fixed_height >= 0)
8427     {
8428       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8429       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8430         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8431     }
8432   else
8433     {
8434       _gtk_rbtree_node_mark_invalid (tree, node);
8435       for (list = tree_view->priv->columns; list; list = list->next)
8436         {
8437           GtkTreeViewColumn *column;
8438
8439           column = list->data;
8440           if (!gtk_tree_view_column_get_visible (column))
8441             continue;
8442
8443           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8444             {
8445               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8446             }
8447         }
8448     }
8449
8450  done:
8451   if (!tree_view->priv->fixed_height_mode &&
8452       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8453     install_presize_handler (tree_view);
8454   if (free_path)
8455     gtk_tree_path_free (path);
8456 }
8457
8458 static void
8459 gtk_tree_view_row_inserted (GtkTreeModel *model,
8460                             GtkTreePath  *path,
8461                             GtkTreeIter  *iter,
8462                             gpointer      data)
8463 {
8464   GtkTreeView *tree_view = (GtkTreeView *) data;
8465   gint *indices;
8466   GtkRBTree *tmptree, *tree;
8467   GtkRBNode *tmpnode = NULL;
8468   gint depth;
8469   gint i = 0;
8470   gint height;
8471   gboolean free_path = FALSE;
8472   gboolean node_visible = TRUE;
8473
8474   g_return_if_fail (path != NULL || iter != NULL);
8475
8476   if (tree_view->priv->fixed_height_mode
8477       && tree_view->priv->fixed_height >= 0)
8478     height = tree_view->priv->fixed_height;
8479   else
8480     height = 0;
8481
8482   if (path == NULL)
8483     {
8484       path = gtk_tree_model_get_path (model, iter);
8485       free_path = TRUE;
8486     }
8487   else if (iter == NULL)
8488     gtk_tree_model_get_iter (model, iter, path);
8489
8490   if (tree_view->priv->tree == NULL)
8491     tree_view->priv->tree = _gtk_rbtree_new ();
8492
8493   tmptree = tree = tree_view->priv->tree;
8494
8495   /* Update all row-references */
8496   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8497   depth = gtk_tree_path_get_depth (path);
8498   indices = gtk_tree_path_get_indices (path);
8499
8500   /* First, find the parent tree */
8501   while (i < depth - 1)
8502     {
8503       if (tmptree == NULL)
8504         {
8505           /* We aren't showing the node */
8506           node_visible = FALSE;
8507           goto done;
8508         }
8509
8510       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8511       if (tmpnode == NULL)
8512         {
8513           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8514                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8515                      "before the parent was inserted.");
8516           goto done;
8517         }
8518       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8519         {
8520           /* FIXME enforce correct behavior on model, probably */
8521           /* In theory, the model should have emitted has_child_toggled here.  We
8522            * try to catch it anyway, just to be safe, in case the model hasn't.
8523            */
8524           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8525                                                            tree,
8526                                                            tmpnode);
8527           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8528           gtk_tree_path_free (tmppath);
8529           goto done;
8530         }
8531
8532       tmptree = tmpnode->children;
8533       tree = tmptree;
8534       i++;
8535     }
8536
8537   if (tree == NULL)
8538     {
8539       node_visible = FALSE;
8540       goto done;
8541     }
8542
8543   /* ref the node */
8544   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8545   if (indices[depth - 1] == 0)
8546     {
8547       tmpnode = _gtk_rbtree_find_count (tree, 1);
8548       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8549     }
8550   else
8551     {
8552       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8553       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8554     }
8555
8556  done:
8557   if (height > 0)
8558     {
8559       if (tree)
8560         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8561
8562       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8563         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8564       else
8565         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8566     }
8567   else
8568     install_presize_handler (tree_view);
8569   if (free_path)
8570     gtk_tree_path_free (path);
8571 }
8572
8573 static void
8574 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8575                                      GtkTreePath  *path,
8576                                      GtkTreeIter  *iter,
8577                                      gpointer      data)
8578 {
8579   GtkTreeView *tree_view = (GtkTreeView *)data;
8580   GtkTreeIter real_iter;
8581   gboolean has_child;
8582   GtkRBTree *tree;
8583   GtkRBNode *node;
8584   gboolean free_path = FALSE;
8585
8586   g_return_if_fail (path != NULL || iter != NULL);
8587
8588   if (iter)
8589     real_iter = *iter;
8590
8591   if (path == NULL)
8592     {
8593       path = gtk_tree_model_get_path (model, iter);
8594       free_path = TRUE;
8595     }
8596   else if (iter == NULL)
8597     gtk_tree_model_get_iter (model, &real_iter, path);
8598
8599   if (_gtk_tree_view_find_node (tree_view,
8600                                 path,
8601                                 &tree,
8602                                 &node))
8603     /* We aren't actually showing the node */
8604     goto done;
8605
8606   if (tree == NULL)
8607     goto done;
8608
8609   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8610   /* Sanity check.
8611    */
8612   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8613     goto done;
8614
8615   if (has_child)
8616     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8617   else
8618     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8619
8620   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8621     {
8622       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8623       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8624         {
8625           GList *list;
8626
8627           for (list = tree_view->priv->columns; list; list = list->next)
8628             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8629               {
8630                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8631                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8632                 break;
8633               }
8634         }
8635       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8636     }
8637   else
8638     {
8639       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8640     }
8641
8642  done:
8643   if (free_path)
8644     gtk_tree_path_free (path);
8645 }
8646
8647 static void
8648 count_children_helper (GtkRBTree *tree,
8649                        GtkRBNode *node,
8650                        gpointer   data)
8651 {
8652   if (node->children)
8653     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8654   (*((gint *)data))++;
8655 }
8656
8657 static void
8658 check_selection_helper (GtkRBTree *tree,
8659                         GtkRBNode *node,
8660                         gpointer   data)
8661 {
8662   gint *value = (gint *)data;
8663
8664   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8665
8666   if (node->children && !*value)
8667     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8668 }
8669
8670 static void
8671 gtk_tree_view_row_deleted (GtkTreeModel *model,
8672                            GtkTreePath  *path,
8673                            gpointer      data)
8674 {
8675   GtkTreeView *tree_view = (GtkTreeView *)data;
8676   GtkRBTree *tree;
8677   GtkRBNode *node;
8678   GList *list;
8679   gint selection_changed = FALSE;
8680
8681   g_return_if_fail (path != NULL);
8682
8683   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8684
8685   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8686     return;
8687
8688   if (tree == NULL)
8689     return;
8690
8691   /* check if the selection has been changed */
8692   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8693                         check_selection_helper, &selection_changed);
8694
8695   for (list = tree_view->priv->columns; list; list = list->next)
8696     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
8697         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8698       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8699
8700   /* Ensure we don't have a dangling pointer to a dead node */
8701   ensure_unprelighted (tree_view);
8702
8703   /* Cancel editting if we've started */
8704   gtk_tree_view_stop_editing (tree_view, TRUE);
8705
8706   /* If we have a node expanded/collapsed timeout, remove it */
8707   remove_expand_collapse_timeout (tree_view);
8708
8709   if (tree_view->priv->destroy_count_func)
8710     {
8711       gint child_count = 0;
8712       if (node->children)
8713         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8714       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8715     }
8716
8717   if (tree->root->count == 1)
8718     {
8719       if (tree_view->priv->tree == tree)
8720         tree_view->priv->tree = NULL;
8721
8722       _gtk_rbtree_remove (tree);
8723     }
8724   else
8725     {
8726       _gtk_rbtree_remove_node (tree, node);
8727     }
8728
8729   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8730     {
8731       gtk_tree_row_reference_free (tree_view->priv->top_row);
8732       tree_view->priv->top_row = NULL;
8733     }
8734
8735   install_scroll_sync_handler (tree_view);
8736
8737   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8738
8739   if (selection_changed)
8740     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8741 }
8742
8743 static void
8744 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8745                               GtkTreePath  *parent,
8746                               GtkTreeIter  *iter,
8747                               gint         *new_order,
8748                               gpointer      data)
8749 {
8750   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8751   GtkRBTree *tree;
8752   GtkRBNode *node;
8753   gint len;
8754
8755   len = gtk_tree_model_iter_n_children (model, iter);
8756
8757   if (len < 2)
8758     return;
8759
8760   gtk_tree_row_reference_reordered (G_OBJECT (data),
8761                                     parent,
8762                                     iter,
8763                                     new_order);
8764
8765   if (_gtk_tree_view_find_node (tree_view,
8766                                 parent,
8767                                 &tree,
8768                                 &node))
8769     return;
8770
8771   /* We need to special case the parent path */
8772   if (tree == NULL)
8773     tree = tree_view->priv->tree;
8774   else
8775     tree = node->children;
8776
8777   if (tree == NULL)
8778     return;
8779
8780   if (tree_view->priv->edited_column)
8781     gtk_tree_view_stop_editing (tree_view, TRUE);
8782
8783   /* we need to be unprelighted */
8784   ensure_unprelighted (tree_view);
8785
8786   /* clear the timeout */
8787   cancel_arrow_animation (tree_view);
8788   
8789   _gtk_rbtree_reorder (tree, new_order, len);
8790
8791   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8792
8793   gtk_tree_view_dy_to_top_row (tree_view);
8794 }
8795
8796
8797 /* Internal tree functions
8798  */
8799
8800
8801 static void
8802 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8803                                      GtkRBTree         *tree,
8804                                      GtkTreeViewColumn *column,
8805                                      gint              *x1,
8806                                      gint              *x2)
8807 {
8808   GtkTreeViewColumn *tmp_column = NULL;
8809   gint total_width;
8810   GList *list;
8811   gboolean rtl;
8812
8813   if (x1)
8814     *x1 = 0;
8815
8816   if (x2)
8817     *x2 = 0;
8818
8819   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8820
8821   total_width = 0;
8822   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8823        list;
8824        list = (rtl ? list->prev : list->next))
8825     {
8826       tmp_column = list->data;
8827
8828       if (tmp_column == column)
8829         break;
8830
8831       if (gtk_tree_view_column_get_visible (tmp_column))
8832         total_width += gtk_tree_view_column_get_width (tmp_column);
8833     }
8834
8835   if (tmp_column != column)
8836     {
8837       g_warning (G_STRLOC": passed-in column isn't in the tree");
8838       return;
8839     }
8840
8841   if (x1)
8842     *x1 = total_width;
8843
8844   if (x2)
8845     {
8846       if (gtk_tree_view_column_get_visible (column))
8847         *x2 = total_width + gtk_tree_view_column_get_width (column);
8848       else
8849         *x2 = total_width; /* width of 0 */
8850     }
8851 }
8852 static void
8853 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8854                                 GtkRBTree   *tree,
8855                                 gint        *x1,
8856                                 gint        *x2)
8857 {
8858   gint x_offset = 0;
8859   GList *list;
8860   GtkTreeViewColumn *tmp_column = NULL;
8861   gint total_width;
8862   gboolean indent_expanders;
8863   gboolean rtl;
8864
8865   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8866
8867   total_width = 0;
8868   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8869        list;
8870        list = (rtl ? list->prev : list->next))
8871     {
8872       tmp_column = list->data;
8873
8874       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8875         {
8876           if (rtl)
8877             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - tree_view->priv->expander_size;
8878           else
8879             x_offset = total_width;
8880           break;
8881         }
8882
8883       if (gtk_tree_view_column_get_visible (tmp_column))
8884         total_width += gtk_tree_view_column_get_width (tmp_column);
8885     }
8886
8887   gtk_widget_style_get (GTK_WIDGET (tree_view),
8888                         "indent-expanders", &indent_expanders,
8889                         NULL);
8890
8891   if (indent_expanders)
8892     {
8893       if (rtl)
8894         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8895       else
8896         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8897     }
8898
8899   *x1 = x_offset;
8900
8901   if (tmp_column &&
8902       gtk_tree_view_column_get_visible (tmp_column))
8903     /* +1 because x2 isn't included in the range. */
8904     *x2 = *x1 + tree_view->priv->expander_size + 1;
8905   else
8906     *x2 = *x1;
8907 }
8908
8909 static void
8910 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8911                           GtkRBTree   *tree,
8912                           GtkTreeIter *iter,
8913                           gint         depth,
8914                           gboolean     recurse)
8915 {
8916   GtkRBNode *temp = NULL;
8917   GtkTreePath *path = NULL;
8918   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8919
8920   do
8921     {
8922       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8923       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8924
8925       if (tree_view->priv->fixed_height > 0)
8926         {
8927           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8928             {
8929               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8930               _gtk_rbtree_node_mark_valid (tree, temp);
8931             }
8932         }
8933
8934       if (is_list)
8935         continue;
8936
8937       if (recurse)
8938         {
8939           GtkTreeIter child;
8940
8941           if (!path)
8942             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8943           else
8944             gtk_tree_path_next (path);
8945
8946           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8947             {
8948               gboolean expand;
8949
8950               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8951
8952               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8953                   && !expand)
8954                 {
8955                   temp->children = _gtk_rbtree_new ();
8956                   temp->children->parent_tree = tree;
8957                   temp->children->parent_node = temp;
8958                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8959                 }
8960             }
8961         }
8962
8963       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8964         {
8965           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8966             temp->flags ^= GTK_RBNODE_IS_PARENT;
8967         }
8968     }
8969   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8970
8971   if (path)
8972     gtk_tree_path_free (path);
8973 }
8974
8975 /* Make sure the node is visible vertically */
8976 static void
8977 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8978                                   GtkRBTree   *tree,
8979                                   GtkRBNode   *node)
8980 {
8981   gint node_dy, height;
8982   GtkTreePath *path = NULL;
8983
8984   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8985     return;
8986
8987   /* just return if the node is visible, avoiding a costly expose */
8988   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8989   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8990   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8991       && node_dy >= tree_view->priv->vadjustment->value
8992       && node_dy + height <= (tree_view->priv->vadjustment->value
8993                               + tree_view->priv->vadjustment->page_size))
8994     return;
8995
8996   path = _gtk_tree_view_find_path (tree_view, tree, node);
8997   if (path)
8998     {
8999       /* We process updates because we want to clear old selected items when we scroll.
9000        * if this is removed, we get a "selection streak" at the bottom. */
9001       gtk_tree_view_bin_process_updates (tree_view);
9002
9003       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9004       gtk_tree_path_free (path);
9005     }
9006 }
9007
9008 static void
9009 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9010                                     GtkTreeViewColumn *column,
9011                                     gboolean           focus_to_cell)
9012 {
9013   GtkAllocation allocation;
9014   gint x, width;
9015
9016   if (column == NULL)
9017     return;
9018
9019   gtk_widget_get_allocation (column->button, &allocation);
9020   x = allocation.x;
9021   width = allocation.width;
9022
9023   if (width > tree_view->priv->hadjustment->page_size)
9024     {
9025       /* The column is larger than the horizontal page size.  If the
9026        * column has cells which can be focussed individually, then we make
9027        * sure the cell which gets focus is fully visible (if even the
9028        * focus cell is bigger than the page size, we make sure the
9029        * left-hand side of the cell is visible).
9030        *
9031        * If the column does not have those so-called special cells, we
9032        * make sure the left-hand side of the column is visible.
9033        */
9034
9035       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
9036         {
9037           GtkTreePath *cursor_path;
9038           GdkRectangle background_area, cell_area, focus_area;
9039
9040           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9041
9042           gtk_tree_view_get_cell_area (tree_view,
9043                                        cursor_path, column, &cell_area);
9044           gtk_tree_view_get_background_area (tree_view,
9045                                              cursor_path, column,
9046                                              &background_area);
9047
9048           gtk_tree_path_free (cursor_path);
9049
9050           _gtk_tree_view_column_get_focus_area (column,
9051                                                 &background_area,
9052                                                 &cell_area,
9053                                                 &focus_area);
9054
9055           x = focus_area.x;
9056           width = focus_area.width;
9057
9058           if (width < tree_view->priv->hadjustment->page_size)
9059             {
9060               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
9061                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
9062                                           x + width - tree_view->priv->hadjustment->page_size);
9063               else if (tree_view->priv->hadjustment->value > x)
9064                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9065             }
9066         }
9067
9068       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9069     }
9070   else
9071     {
9072       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
9073           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9074                                     x + width - tree_view->priv->hadjustment->page_size);
9075       else if (tree_view->priv->hadjustment->value > x)
9076         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9077   }
9078 }
9079
9080 /* This function could be more efficient.  I'll optimize it if profiling seems
9081  * to imply that it is important */
9082 GtkTreePath *
9083 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9084                           GtkRBTree   *tree,
9085                           GtkRBNode   *node)
9086 {
9087   GtkTreePath *path;
9088   GtkRBTree *tmp_tree;
9089   GtkRBNode *tmp_node, *last;
9090   gint count;
9091
9092   path = gtk_tree_path_new ();
9093
9094   g_return_val_if_fail (node != NULL, path);
9095   g_return_val_if_fail (node != tree->nil, path);
9096
9097   count = 1 + node->left->count;
9098
9099   last = node;
9100   tmp_node = node->parent;
9101   tmp_tree = tree;
9102   while (tmp_tree)
9103     {
9104       while (tmp_node != tmp_tree->nil)
9105         {
9106           if (tmp_node->right == last)
9107             count += 1 + tmp_node->left->count;
9108           last = tmp_node;
9109           tmp_node = tmp_node->parent;
9110         }
9111       gtk_tree_path_prepend_index (path, count - 1);
9112       last = tmp_tree->parent_node;
9113       tmp_tree = tmp_tree->parent_tree;
9114       if (last)
9115         {
9116           count = 1 + last->left->count;
9117           tmp_node = last->parent;
9118         }
9119     }
9120   return path;
9121 }
9122
9123 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9124  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9125  * both set to NULL.
9126  */
9127 gboolean
9128 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9129                           GtkTreePath  *path,
9130                           GtkRBTree   **tree,
9131                           GtkRBNode   **node)
9132 {
9133   GtkRBNode *tmpnode = NULL;
9134   GtkRBTree *tmptree = tree_view->priv->tree;
9135   gint *indices = gtk_tree_path_get_indices (path);
9136   gint depth = gtk_tree_path_get_depth (path);
9137   gint i = 0;
9138
9139   *node = NULL;
9140   *tree = NULL;
9141
9142   if (depth == 0 || tmptree == NULL)
9143     return FALSE;
9144   do
9145     {
9146       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9147       ++i;
9148       if (tmpnode == NULL)
9149         {
9150           *tree = NULL;
9151           *node = NULL;
9152           return FALSE;
9153         }
9154       if (i >= depth)
9155         {
9156           *tree = tmptree;
9157           *node = tmpnode;
9158           return FALSE;
9159         }
9160       *tree = tmptree;
9161       *node = tmpnode;
9162       tmptree = tmpnode->children;
9163       if (tmptree == NULL)
9164         return TRUE;
9165     }
9166   while (1);
9167 }
9168
9169 static gboolean
9170 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9171                                   GtkTreeViewColumn *column)
9172 {
9173   GList *list;
9174
9175   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9176     return FALSE;
9177
9178   if (tree_view->priv->expander_column != NULL)
9179     {
9180       if (tree_view->priv->expander_column == column)
9181         return TRUE;
9182       return FALSE;
9183     }
9184   else
9185     {
9186       for (list = tree_view->priv->columns;
9187            list;
9188            list = list->next)
9189         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9190           break;
9191       if (list && list->data == column)
9192         return TRUE;
9193     }
9194   return FALSE;
9195 }
9196
9197 static void
9198 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9199                                 guint           keyval,
9200                                 guint           modmask,
9201                                 gboolean        add_shifted_binding,
9202                                 GtkMovementStep step,
9203                                 gint            count)
9204 {
9205   
9206   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9207                                 "move-cursor", 2,
9208                                 G_TYPE_ENUM, step,
9209                                 G_TYPE_INT, count);
9210
9211   if (add_shifted_binding)
9212     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9213                                   "move-cursor", 2,
9214                                   G_TYPE_ENUM, step,
9215                                   G_TYPE_INT, count);
9216
9217   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9218    return;
9219
9220   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9221                                 "move-cursor", 2,
9222                                 G_TYPE_ENUM, step,
9223                                 G_TYPE_INT, count);
9224
9225   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9226                                 "move-cursor", 2,
9227                                 G_TYPE_ENUM, step,
9228                                 G_TYPE_INT, count);
9229 }
9230
9231 static gint
9232 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9233                                  GtkTreeIter  *iter,
9234                                  GtkRBTree    *tree,
9235                                  GtkRBNode    *node)
9236 {
9237   gint retval = FALSE;
9238   do
9239     {
9240       g_return_val_if_fail (node != NULL, FALSE);
9241
9242       if (node->children)
9243         {
9244           GtkTreeIter child;
9245           GtkRBTree *new_tree;
9246           GtkRBNode *new_node;
9247
9248           new_tree = node->children;
9249           new_node = new_tree->root;
9250
9251           while (new_node && new_node->left != new_tree->nil)
9252             new_node = new_node->left;
9253
9254           if (!gtk_tree_model_iter_children (model, &child, iter))
9255             return FALSE;
9256
9257           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9258         }
9259
9260       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9261         retval = TRUE;
9262       gtk_tree_model_unref_node (model, iter);
9263       node = _gtk_rbtree_next (tree, node);
9264     }
9265   while (gtk_tree_model_iter_next (model, iter));
9266
9267   return retval;
9268 }
9269
9270 static gint
9271 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9272                                               GtkRBTree   *tree)
9273 {
9274   GtkTreeIter iter;
9275   GtkTreePath *path;
9276   GtkRBNode *node;
9277   gint retval;
9278
9279   if (!tree)
9280     return FALSE;
9281
9282   node = tree->root;
9283   while (node && node->left != tree->nil)
9284     node = node->left;
9285
9286   g_return_val_if_fail (node != NULL, FALSE);
9287   path = _gtk_tree_view_find_path (tree_view, tree, node);
9288   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9289                            &iter, path);
9290   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9291   gtk_tree_path_free (path);
9292
9293   return retval;
9294 }
9295
9296 static void
9297 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9298                                     GtkTreeViewColumn *column)
9299 {
9300   GtkTreeViewColumn *left_column;
9301   GtkTreeViewColumn *cur_column = NULL;
9302   GtkTreeViewColumnReorder *reorder;
9303   gboolean rtl;
9304   GList *tmp_list;
9305   gint left;
9306
9307   /* We want to precalculate the motion list such that we know what column slots
9308    * are available.
9309    */
9310   left_column = NULL;
9311   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9312
9313   /* First, identify all possible drop spots */
9314   if (rtl)
9315     tmp_list = g_list_last (tree_view->priv->columns);
9316   else
9317     tmp_list = g_list_first (tree_view->priv->columns);
9318
9319   while (tmp_list)
9320     {
9321       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9322       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9323
9324       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9325         continue;
9326
9327       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9328       if (left_column != column && cur_column != column &&
9329           tree_view->priv->column_drop_func &&
9330           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9331         {
9332           left_column = cur_column;
9333           continue;
9334         }
9335       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9336       reorder->left_column = left_column;
9337       left_column = reorder->right_column = cur_column;
9338
9339       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9340     }
9341
9342   /* Add the last one */
9343   if (tree_view->priv->column_drop_func == NULL ||
9344       ((left_column != column) &&
9345        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9346     {
9347       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9348       reorder->left_column = left_column;
9349       reorder->right_column = NULL;
9350       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9351     }
9352
9353   /* We quickly check to see if it even makes sense to reorder columns. */
9354   /* If there is nothing that can be moved, then we return */
9355
9356   if (tree_view->priv->column_drag_info == NULL)
9357     return;
9358
9359   /* We know there are always 2 slots possbile, as you can always return column. */
9360   /* If that's all there is, return */
9361   if (tree_view->priv->column_drag_info->next == NULL || 
9362       (tree_view->priv->column_drag_info->next->next == NULL &&
9363        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9364        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9365     {
9366       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9367         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9368       g_list_free (tree_view->priv->column_drag_info);
9369       tree_view->priv->column_drag_info = NULL;
9370       return;
9371     }
9372   /* We fill in the ranges for the columns, now that we've isolated them */
9373   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9374
9375   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9376     {
9377       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9378
9379       reorder->left_align = left;
9380       if (tmp_list->next != NULL)
9381         {
9382           GtkAllocation right_allocation, left_allocation;
9383
9384           g_assert (tmp_list->next->data);
9385
9386           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
9387           gtk_widget_get_allocation (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button, &left_allocation);
9388           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9389         }
9390       else
9391         {
9392           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9393                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9394         }
9395     }
9396 }
9397
9398 void
9399 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9400                                   GtkTreeViewColumn *column,
9401                                   GdkDevice         *device)
9402 {
9403   GdkEvent *send_event;
9404   GtkAllocation allocation;
9405   GtkAllocation button_allocation;
9406   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9407   GdkDisplay *display = gdk_screen_get_display (screen);
9408
9409   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9410   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9411
9412   gtk_tree_view_set_column_drag_info (tree_view, column);
9413
9414   if (tree_view->priv->column_drag_info == NULL)
9415     return;
9416
9417   if (tree_view->priv->drag_window == NULL)
9418     {
9419       GdkWindowAttr attributes;
9420       guint attributes_mask;
9421
9422       gtk_widget_get_allocation (column->button, &button_allocation);
9423
9424       attributes.window_type = GDK_WINDOW_CHILD;
9425       attributes.wclass = GDK_INPUT_OUTPUT;
9426       attributes.x = button_allocation.x;
9427       attributes.y = 0;
9428       attributes.width = button_allocation.width;
9429       attributes.height = button_allocation.height;
9430       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9431       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9432       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9433
9434       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9435                                                      &attributes,
9436                                                      attributes_mask);
9437       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9438     }
9439
9440   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9441   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9442
9443   gtk_grab_remove (column->button);
9444
9445   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9446   send_event->crossing.send_event = TRUE;
9447   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (column->button)));
9448   send_event->crossing.subwindow = NULL;
9449   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9450   send_event->crossing.time = GDK_CURRENT_TIME;
9451   gdk_event_set_device (send_event, device);
9452
9453   gtk_propagate_event (column->button, send_event);
9454   gdk_event_free (send_event);
9455
9456   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9457   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9458   send_event->button.send_event = TRUE;
9459   send_event->button.time = GDK_CURRENT_TIME;
9460   send_event->button.x = -1;
9461   send_event->button.y = -1;
9462   send_event->button.axes = NULL;
9463   send_event->button.state = 0;
9464   send_event->button.button = 1;
9465   send_event->button.x_root = 0;
9466   send_event->button.y_root = 0;
9467   gdk_event_set_device (send_event, device);
9468
9469   gtk_propagate_event (column->button, send_event);
9470   gdk_event_free (send_event);
9471
9472   /* Kids, don't try this at home */
9473   g_object_ref (column->button);
9474   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9475   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9476   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9477   g_object_unref (column->button);
9478
9479   gtk_widget_get_allocation (column->button, &button_allocation);
9480   tree_view->priv->drag_column_x = button_allocation.x;
9481   allocation = button_allocation;
9482   allocation.x = 0;
9483   gtk_widget_size_allocate (column->button, &allocation);
9484   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9485
9486   tree_view->priv->drag_column = column;
9487   gdk_window_show (tree_view->priv->drag_window);
9488
9489   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9490   while (gtk_events_pending ())
9491     gtk_main_iteration ();
9492
9493   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9494   gdk_pointer_grab (tree_view->priv->drag_window,
9495                     FALSE,
9496                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9497                     NULL, NULL, GDK_CURRENT_TIME);
9498   gdk_keyboard_grab (tree_view->priv->drag_window,
9499                      FALSE,
9500                      GDK_CURRENT_TIME);
9501 }
9502
9503 static void
9504 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9505                                 GtkRBTree          *tree,
9506                                 GtkRBNode          *node)
9507 {
9508   GtkAllocation allocation;
9509   GdkRectangle rect;
9510
9511   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9512     return;
9513
9514   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9515   rect.x = 0;
9516   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9517
9518   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9519   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9520
9521   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9522 }
9523
9524 void
9525 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9526                                 GtkRBTree          *tree,
9527                                 GtkRBNode          *node,
9528                                 const GdkRectangle *clip_rect)
9529 {
9530   GtkAllocation allocation;
9531   GdkRectangle rect;
9532
9533   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9534     return;
9535
9536   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9537   rect.x = 0;
9538   rect.width = MAX (tree_view->priv->width, allocation.width);
9539
9540   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9541   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9542
9543   if (clip_rect)
9544     {
9545       GdkRectangle new_rect;
9546
9547       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9548
9549       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9550     }
9551   else
9552     {
9553       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9554     }
9555 }
9556
9557 static void
9558 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9559                                GtkTreePath        *path,
9560                                const GdkRectangle *clip_rect)
9561 {
9562   GtkRBTree *tree = NULL;
9563   GtkRBNode *node = NULL;
9564
9565   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9566
9567   if (tree)
9568     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9569 }
9570
9571 /* x and y are the mouse position
9572  */
9573 static void
9574 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9575                           cairo_t     *cr,
9576                           GtkRBTree   *tree,
9577                           GtkRBNode   *node,
9578                           /* in bin_window coordinates */
9579                           gint         x,
9580                           gint         y)
9581 {
9582   GdkRectangle area;
9583   GtkStateType state;
9584   GtkWidget *widget;
9585   gint x_offset = 0;
9586   gint x2;
9587   gint vertical_separator;
9588   gint expander_size;
9589   GtkExpanderStyle expander_style;
9590
9591   widget = GTK_WIDGET (tree_view);
9592
9593   gtk_widget_style_get (widget,
9594                         "vertical-separator", &vertical_separator,
9595                         NULL);
9596   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9597
9598   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9599     return;
9600
9601   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9602
9603   area.x = x_offset;
9604   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9605   area.width = expander_size + 2;
9606   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9607
9608   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9609     {
9610       state = GTK_STATE_INSENSITIVE;
9611     }
9612   else if (node == tree_view->priv->button_pressed_node)
9613     {
9614       if (x >= area.x && x <= (area.x + area.width) &&
9615           y >= area.y && y <= (area.y + area.height))
9616         state = GTK_STATE_ACTIVE;
9617       else
9618         state = GTK_STATE_NORMAL;
9619     }
9620   else
9621     {
9622       if (node == tree_view->priv->prelight_node &&
9623           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9624         state = GTK_STATE_PRELIGHT;
9625       else
9626         state = GTK_STATE_NORMAL;
9627     }
9628
9629   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9630     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9631   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9632     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9633   else if (node->children != NULL)
9634     expander_style = GTK_EXPANDER_EXPANDED;
9635   else
9636     expander_style = GTK_EXPANDER_COLLAPSED;
9637
9638   gtk_paint_expander (gtk_widget_get_style (widget),
9639                       cr,
9640                       state,
9641                       widget,
9642                       "treeview",
9643                       area.x + area.width / 2,
9644                       area.y + area.height / 2,
9645                       expander_style);
9646 }
9647
9648 static void
9649 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9650
9651 {
9652   GtkTreePath *cursor_path;
9653
9654   if ((tree_view->priv->tree == NULL) ||
9655       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
9656     return;
9657
9658   cursor_path = NULL;
9659   if (tree_view->priv->cursor)
9660     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9661
9662   if (cursor_path == NULL)
9663     {
9664       /* Consult the selection before defaulting to the
9665        * first focusable element
9666        */
9667       GList *selected_rows;
9668       GtkTreeModel *model;
9669       GtkTreeSelection *selection;
9670
9671       selection = gtk_tree_view_get_selection (tree_view);
9672       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9673
9674       if (selected_rows)
9675         {
9676           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9677           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9678           g_list_free (selected_rows);
9679         }
9680       else
9681         {
9682           cursor_path = gtk_tree_path_new_first ();
9683           search_first_focusable_path (tree_view, &cursor_path,
9684                                        TRUE, NULL, NULL);
9685         }
9686
9687       gtk_tree_row_reference_free (tree_view->priv->cursor);
9688       tree_view->priv->cursor = NULL;
9689
9690       if (cursor_path)
9691         {
9692           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9693             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9694           else
9695             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9696         }
9697     }
9698
9699   if (cursor_path)
9700     {
9701       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9702
9703       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9704       gtk_tree_path_free (cursor_path);
9705
9706       if (tree_view->priv->focus_column == NULL)
9707         {
9708           GList *list;
9709           for (list = tree_view->priv->columns; list; list = list->next)
9710             {
9711               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9712                 {
9713                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9714                   break;
9715                 }
9716             }
9717         }
9718     }
9719 }
9720
9721 static void
9722 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9723                                    gint         count)
9724 {
9725   gint selection_count;
9726   GtkRBTree *cursor_tree = NULL;
9727   GtkRBNode *cursor_node = NULL;
9728   GtkRBTree *new_cursor_tree = NULL;
9729   GtkRBNode *new_cursor_node = NULL;
9730   GtkTreePath *cursor_path = NULL;
9731   gboolean grab_focus = TRUE;
9732   gboolean selectable;
9733
9734   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9735     return;
9736
9737   cursor_path = NULL;
9738   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9739     /* FIXME: we lost the cursor; should we get the first? */
9740     return;
9741
9742   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9743   _gtk_tree_view_find_node (tree_view, cursor_path,
9744                             &cursor_tree, &cursor_node);
9745
9746   if (cursor_tree == NULL)
9747     /* FIXME: we lost the cursor; should we get the first? */
9748     return;
9749
9750   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9751   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9752                                                       cursor_node,
9753                                                       cursor_path);
9754
9755   if (selection_count == 0
9756       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9757       && !tree_view->priv->ctrl_pressed
9758       && selectable)
9759     {
9760       /* Don't move the cursor, but just select the current node */
9761       new_cursor_tree = cursor_tree;
9762       new_cursor_node = cursor_node;
9763     }
9764   else
9765     {
9766       if (count == -1)
9767         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9768                                &new_cursor_tree, &new_cursor_node);
9769       else
9770         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9771                                &new_cursor_tree, &new_cursor_node);
9772     }
9773
9774   gtk_tree_path_free (cursor_path);
9775
9776   if (new_cursor_node)
9777     {
9778       cursor_path = _gtk_tree_view_find_path (tree_view,
9779                                               new_cursor_tree, new_cursor_node);
9780
9781       search_first_focusable_path (tree_view, &cursor_path,
9782                                    (count != -1),
9783                                    &new_cursor_tree,
9784                                    &new_cursor_node);
9785
9786       if (cursor_path)
9787         gtk_tree_path_free (cursor_path);
9788     }
9789
9790   /*
9791    * If the list has only one item and multi-selection is set then select
9792    * the row (if not yet selected).
9793    */
9794   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9795       new_cursor_node == NULL)
9796     {
9797       if (count == -1)
9798         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9799                                &new_cursor_tree, &new_cursor_node);
9800       else
9801         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9802                                &new_cursor_tree, &new_cursor_node);
9803
9804       if (new_cursor_node == NULL
9805           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9806         {
9807           new_cursor_node = cursor_node;
9808           new_cursor_tree = cursor_tree;
9809         }
9810       else
9811         {
9812           new_cursor_node = NULL;
9813         }
9814     }
9815
9816   if (new_cursor_node)
9817     {
9818       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9819       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9820       gtk_tree_path_free (cursor_path);
9821     }
9822   else
9823     {
9824       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9825
9826       if (!tree_view->priv->shift_pressed)
9827         {
9828           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9829                                           count < 0 ?
9830                                           GTK_DIR_UP : GTK_DIR_DOWN))
9831             {
9832               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9833
9834               if (toplevel)
9835                 gtk_widget_child_focus (toplevel,
9836                                         count < 0 ?
9837                                         GTK_DIR_TAB_BACKWARD :
9838                                         GTK_DIR_TAB_FORWARD);
9839
9840               grab_focus = FALSE;
9841             }
9842         }
9843       else
9844         {
9845           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9846         }
9847     }
9848
9849   if (grab_focus)
9850     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9851 }
9852
9853 static void
9854 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9855                                         gint         count)
9856 {
9857   GtkRBTree *cursor_tree = NULL;
9858   GtkRBNode *cursor_node = NULL;
9859   GtkTreePath *old_cursor_path = NULL;
9860   GtkTreePath *cursor_path = NULL;
9861   GtkRBTree *start_cursor_tree = NULL;
9862   GtkRBNode *start_cursor_node = NULL;
9863   gint y;
9864   gint window_y;
9865   gint vertical_separator;
9866
9867   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9868     return;
9869
9870   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9871     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9872   else
9873     /* This is sorta weird.  Focus in should give us a cursor */
9874     return;
9875
9876   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9877   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9878                             &cursor_tree, &cursor_node);
9879
9880   if (cursor_tree == NULL)
9881     {
9882       /* FIXME: we lost the cursor.  Should we try to get one? */
9883       gtk_tree_path_free (old_cursor_path);
9884       return;
9885     }
9886   g_return_if_fail (cursor_node != NULL);
9887
9888   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9889   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9890   y += tree_view->priv->cursor_offset;
9891   y += count * (int)tree_view->priv->vadjustment->page_increment;
9892   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9893
9894   if (y >= tree_view->priv->height)
9895     y = tree_view->priv->height - 1;
9896
9897   tree_view->priv->cursor_offset =
9898     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9899                              &cursor_tree, &cursor_node);
9900
9901   if (cursor_tree == NULL)
9902     {
9903       /* FIXME: we lost the cursor.  Should we try to get one? */
9904       gtk_tree_path_free (old_cursor_path);
9905       return;
9906     }
9907
9908   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9909     {
9910       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9911                              &cursor_tree, &cursor_node);
9912       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9913     }
9914
9915   y -= tree_view->priv->cursor_offset;
9916   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9917
9918   start_cursor_tree = cursor_tree;
9919   start_cursor_node = cursor_node;
9920
9921   if (! search_first_focusable_path (tree_view, &cursor_path,
9922                                      (count != -1),
9923                                      &cursor_tree, &cursor_node))
9924     {
9925       /* It looks like we reached the end of the view without finding
9926        * a focusable row.  We will step backwards to find the last
9927        * focusable row.
9928        */
9929       cursor_tree = start_cursor_tree;
9930       cursor_node = start_cursor_node;
9931       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9932
9933       search_first_focusable_path (tree_view, &cursor_path,
9934                                    (count == -1),
9935                                    &cursor_tree, &cursor_node);
9936     }
9937
9938   if (!cursor_path)
9939     goto cleanup;
9940
9941   /* update y */
9942   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9943
9944   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9945
9946   y -= window_y;
9947   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9948   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9949   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9950
9951   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9952     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9953
9954   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9955
9956 cleanup:
9957   gtk_tree_path_free (old_cursor_path);
9958   gtk_tree_path_free (cursor_path);
9959 }
9960
9961 static void
9962 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9963                                       gint         count)
9964 {
9965   GtkRBTree *cursor_tree = NULL;
9966   GtkRBNode *cursor_node = NULL;
9967   GtkTreePath *cursor_path = NULL;
9968   GtkTreeViewColumn *column;
9969   GtkTreeIter iter;
9970   GList *list;
9971   gboolean found_column = FALSE;
9972   gboolean rtl;
9973
9974   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9975
9976   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9977     return;
9978
9979   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9980     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9981   else
9982     return;
9983
9984   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9985   if (cursor_tree == NULL)
9986     return;
9987   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9988     {
9989       gtk_tree_path_free (cursor_path);
9990       return;
9991     }
9992   gtk_tree_path_free (cursor_path);
9993
9994   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9995   if (tree_view->priv->focus_column)
9996     {
9997       for (; list; list = (rtl ? list->prev : list->next))
9998         {
9999           if (list->data == tree_view->priv->focus_column)
10000             break;
10001         }
10002     }
10003
10004   while (list)
10005     {
10006       gboolean left, right;
10007
10008       column = list->data;
10009       if (gtk_tree_view_column_get_visible (column) == FALSE)
10010         goto loop_end;
10011
10012       gtk_tree_view_column_cell_set_cell_data (column,
10013                                                tree_view->priv->model,
10014                                                &iter,
10015                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10016                                                cursor_node->children?TRUE:FALSE);
10017
10018       if (rtl)
10019         {
10020           right = list->prev ? TRUE : FALSE;
10021           left = list->next ? TRUE : FALSE;
10022         }
10023       else
10024         {
10025           left = list->prev ? TRUE : FALSE;
10026           right = list->next ? TRUE : FALSE;
10027         }
10028
10029       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
10030         {
10031           tree_view->priv->focus_column = column;
10032           found_column = TRUE;
10033           break;
10034         }
10035     loop_end:
10036       if (count == 1)
10037         list = rtl ? list->prev : list->next;
10038       else
10039         list = rtl ? list->next : list->prev;
10040     }
10041
10042   if (found_column)
10043     {
10044       if (!gtk_tree_view_has_special_cell (tree_view))
10045         _gtk_tree_view_queue_draw_node (tree_view,
10046                                         cursor_tree,
10047                                         cursor_node,
10048                                         NULL);
10049       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10050       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10051     }
10052   else
10053     {
10054       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10055     }
10056
10057   gtk_tree_view_clamp_column_visible (tree_view,
10058                                       tree_view->priv->focus_column, TRUE);
10059 }
10060
10061 static void
10062 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10063                                      gint         count)
10064 {
10065   GtkRBTree *cursor_tree;
10066   GtkRBNode *cursor_node;
10067   GtkTreePath *path;
10068   GtkTreePath *old_path;
10069
10070   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10071     return;
10072
10073   g_return_if_fail (tree_view->priv->tree != NULL);
10074
10075   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10076
10077   cursor_tree = tree_view->priv->tree;
10078   cursor_node = cursor_tree->root;
10079
10080   if (count == -1)
10081     {
10082       while (cursor_node && cursor_node->left != cursor_tree->nil)
10083         cursor_node = cursor_node->left;
10084
10085       /* Now go forward to find the first focusable row. */
10086       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10087       search_first_focusable_path (tree_view, &path,
10088                                    TRUE, &cursor_tree, &cursor_node);
10089     }
10090   else
10091     {
10092       do
10093         {
10094           while (cursor_node && cursor_node->right != cursor_tree->nil)
10095             cursor_node = cursor_node->right;
10096           if (cursor_node->children == NULL)
10097             break;
10098
10099           cursor_tree = cursor_node->children;
10100           cursor_node = cursor_tree->root;
10101         }
10102       while (1);
10103
10104       /* Now go backwards to find last focusable row. */
10105       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10106       search_first_focusable_path (tree_view, &path,
10107                                    FALSE, &cursor_tree, &cursor_node);
10108     }
10109
10110   if (!path)
10111     goto cleanup;
10112
10113   if (gtk_tree_path_compare (old_path, path))
10114     {
10115       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10116       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10117     }
10118   else
10119     {
10120       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10121     }
10122
10123 cleanup:
10124   gtk_tree_path_free (old_path);
10125   gtk_tree_path_free (path);
10126 }
10127
10128 static gboolean
10129 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10130 {
10131   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10132     return FALSE;
10133
10134   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10135     return FALSE;
10136
10137   gtk_tree_selection_select_all (tree_view->priv->selection);
10138
10139   return TRUE;
10140 }
10141
10142 static gboolean
10143 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10144 {
10145   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10146     return FALSE;
10147
10148   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10149     return FALSE;
10150
10151   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10152
10153   return TRUE;
10154 }
10155
10156 static gboolean
10157 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10158                                       gboolean     start_editing)
10159 {
10160   GtkRBTree *new_tree = NULL;
10161   GtkRBNode *new_node = NULL;
10162   GtkRBTree *cursor_tree = NULL;
10163   GtkRBNode *cursor_node = NULL;
10164   GtkTreePath *cursor_path = NULL;
10165   GtkTreeSelectMode mode = 0;
10166
10167   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10168     return FALSE;
10169
10170   if (tree_view->priv->cursor)
10171     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10172
10173   if (cursor_path == NULL)
10174     return FALSE;
10175
10176   _gtk_tree_view_find_node (tree_view, cursor_path,
10177                             &cursor_tree, &cursor_node);
10178
10179   if (cursor_tree == NULL)
10180     {
10181       gtk_tree_path_free (cursor_path);
10182       return FALSE;
10183     }
10184
10185   if (!tree_view->priv->shift_pressed && start_editing &&
10186       tree_view->priv->focus_column)
10187     {
10188       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10189         {
10190           gtk_tree_path_free (cursor_path);
10191           return TRUE;
10192         }
10193     }
10194
10195   if (tree_view->priv->ctrl_pressed)
10196     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10197   if (tree_view->priv->shift_pressed)
10198     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10199
10200   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10201                                             cursor_node,
10202                                             cursor_tree,
10203                                             cursor_path,
10204                                             mode,
10205                                             FALSE);
10206
10207   /* We bail out if the original (tree, node) don't exist anymore after
10208    * handling the selection-changed callback.  We do return TRUE because
10209    * the key press has been handled at this point.
10210    */
10211   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10212
10213   if (cursor_tree != new_tree || cursor_node != new_node)
10214     return FALSE;
10215
10216   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10217
10218   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10219   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10220
10221   if (!tree_view->priv->shift_pressed)
10222     gtk_tree_view_row_activated (tree_view, cursor_path,
10223                                  tree_view->priv->focus_column);
10224     
10225   gtk_tree_path_free (cursor_path);
10226
10227   return TRUE;
10228 }
10229
10230 static gboolean
10231 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10232 {
10233   GtkRBTree *new_tree = NULL;
10234   GtkRBNode *new_node = NULL;
10235   GtkRBTree *cursor_tree = NULL;
10236   GtkRBNode *cursor_node = NULL;
10237   GtkTreePath *cursor_path = NULL;
10238
10239   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10240     return FALSE;
10241
10242   cursor_path = NULL;
10243   if (tree_view->priv->cursor)
10244     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10245
10246   if (cursor_path == NULL)
10247     return FALSE;
10248
10249   _gtk_tree_view_find_node (tree_view, cursor_path,
10250                             &cursor_tree, &cursor_node);
10251   if (cursor_tree == NULL)
10252     {
10253       gtk_tree_path_free (cursor_path);
10254       return FALSE;
10255     }
10256
10257   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10258                                             cursor_node,
10259                                             cursor_tree,
10260                                             cursor_path,
10261                                             GTK_TREE_SELECT_MODE_TOGGLE,
10262                                             FALSE);
10263
10264   /* We bail out if the original (tree, node) don't exist anymore after
10265    * handling the selection-changed callback.  We do return TRUE because
10266    * the key press has been handled at this point.
10267    */
10268   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10269
10270   if (cursor_tree != new_tree || cursor_node != new_node)
10271     return FALSE;
10272
10273   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10274
10275   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10276   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10277   gtk_tree_path_free (cursor_path);
10278
10279   return TRUE;
10280 }
10281
10282 static gboolean
10283 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10284                                                gboolean     logical,
10285                                                gboolean     expand,
10286                                                gboolean     open_all)
10287 {
10288   GtkTreePath *cursor_path = NULL;
10289   GtkRBTree *tree;
10290   GtkRBNode *node;
10291
10292   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10293     return FALSE;
10294
10295   cursor_path = NULL;
10296   if (tree_view->priv->cursor)
10297     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10298
10299   if (cursor_path == NULL)
10300     return FALSE;
10301
10302   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10303     return FALSE;
10304
10305   /* Don't handle the event if we aren't an expander */
10306   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10307     return FALSE;
10308
10309   if (!logical
10310       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10311     expand = !expand;
10312
10313   if (expand)
10314     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10315   else
10316     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10317
10318   gtk_tree_path_free (cursor_path);
10319
10320   return TRUE;
10321 }
10322
10323 static gboolean
10324 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10325 {
10326   GtkRBTree *cursor_tree = NULL;
10327   GtkRBNode *cursor_node = NULL;
10328   GtkTreePath *cursor_path = NULL;
10329   GdkModifierType state;
10330
10331   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10332     goto out;
10333
10334   cursor_path = NULL;
10335   if (tree_view->priv->cursor)
10336     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10337
10338   if (cursor_path == NULL)
10339     goto out;
10340
10341   _gtk_tree_view_find_node (tree_view, cursor_path,
10342                             &cursor_tree, &cursor_node);
10343   if (cursor_tree == NULL)
10344     {
10345       gtk_tree_path_free (cursor_path);
10346       goto out;
10347     }
10348
10349   if (cursor_tree->parent_node)
10350     {
10351       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10352       cursor_node = cursor_tree->parent_node;
10353       cursor_tree = cursor_tree->parent_tree;
10354
10355       gtk_tree_path_up (cursor_path);
10356
10357       if (gtk_get_current_event_state (&state))
10358         {
10359           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10360             tree_view->priv->ctrl_pressed = TRUE;
10361         }
10362
10363       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10364       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10365
10366       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10367       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10368       gtk_tree_path_free (cursor_path);
10369
10370       tree_view->priv->ctrl_pressed = FALSE;
10371
10372       return TRUE;
10373     }
10374
10375  out:
10376
10377   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10378   return FALSE;
10379 }
10380
10381 static gboolean
10382 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10383 {
10384   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10385   tree_view->priv->typeselect_flush_timeout = 0;
10386
10387   return FALSE;
10388 }
10389
10390 /* Cut and paste from gtkwindow.c */
10391 static void
10392 send_focus_change (GtkWidget *widget,
10393                    GdkDevice *device,
10394                    gboolean   in)
10395 {
10396   GdkDeviceManager *device_manager;
10397   GList *devices, *d;
10398
10399   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10400   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10401   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10402   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10403
10404   for (d = devices; d; d = d->next)
10405     {
10406       GdkDevice *dev = d->data;
10407       GdkEvent *fevent;
10408       GdkWindow *window;
10409
10410       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10411         continue;
10412
10413       window = gtk_widget_get_window (widget);
10414
10415       /* Skip non-master keyboards that haven't
10416        * selected for events from this window
10417        */
10418       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10419           !gdk_window_get_device_events (window, dev))
10420         continue;
10421
10422       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10423
10424       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10425       fevent->focus_change.window = g_object_ref (window);
10426       fevent->focus_change.in = in;
10427       gdk_event_set_device (fevent, device);
10428
10429       gtk_widget_send_focus_change (widget, fevent);
10430
10431       gdk_event_free (fevent);
10432     }
10433 }
10434
10435 static void
10436 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10437 {
10438   GtkWidget *frame, *vbox, *toplevel;
10439   GdkScreen *screen;
10440
10441   if (tree_view->priv->search_custom_entry_set)
10442     return;
10443
10444   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10445   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10446
10447    if (tree_view->priv->search_window != NULL)
10448      {
10449        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10450          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10451                                       GTK_WINDOW (tree_view->priv->search_window));
10452        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10453          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10454                                          GTK_WINDOW (tree_view->priv->search_window));
10455
10456        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10457
10458        return;
10459      }
10460    
10461   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10462   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10463
10464   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10465     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10466                                  GTK_WINDOW (tree_view->priv->search_window));
10467
10468   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10469                             GDK_WINDOW_TYPE_HINT_UTILITY);
10470   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10471   g_signal_connect (tree_view->priv->search_window, "delete-event",
10472                     G_CALLBACK (gtk_tree_view_search_delete_event),
10473                     tree_view);
10474   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10475                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10476                     tree_view);
10477   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10478                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10479                     tree_view);
10480   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10481                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10482                     tree_view);
10483
10484   frame = gtk_frame_new (NULL);
10485   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10486   gtk_widget_show (frame);
10487   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10488
10489   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10490   gtk_widget_show (vbox);
10491   gtk_container_add (GTK_CONTAINER (frame), vbox);
10492   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10493
10494   /* add entry */
10495   tree_view->priv->search_entry = gtk_entry_new ();
10496   gtk_widget_show (tree_view->priv->search_entry);
10497   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10498                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10499                     tree_view);
10500   g_signal_connect (tree_view->priv->search_entry,
10501                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10502                     tree_view);
10503
10504   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
10505                     "preedit-changed",
10506                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10507                     tree_view);
10508
10509   gtk_container_add (GTK_CONTAINER (vbox),
10510                      tree_view->priv->search_entry);
10511
10512   gtk_widget_realize (tree_view->priv->search_entry);
10513 }
10514
10515 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10516  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10517  */
10518 static gboolean
10519 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10520                                              GdkDevice   *device,
10521                                              gboolean     keybinding)
10522 {
10523   /* We only start interactive search if we have focus or the columns
10524    * have focus.  If one of our children have focus, we don't want to
10525    * start the search.
10526    */
10527   GList *list;
10528   gboolean found_focus = FALSE;
10529   GtkWidgetClass *entry_parent_class;
10530   
10531   if (!tree_view->priv->enable_search && !keybinding)
10532     return FALSE;
10533
10534   if (tree_view->priv->search_custom_entry_set)
10535     return FALSE;
10536
10537   if (tree_view->priv->search_window != NULL &&
10538       gtk_widget_get_visible (tree_view->priv->search_window))
10539     return TRUE;
10540
10541   for (list = tree_view->priv->columns; list; list = list->next)
10542     {
10543       GtkTreeViewColumn *column;
10544
10545       column = list->data;
10546       if (!gtk_tree_view_column_get_visible (column))
10547         continue;
10548
10549       if (gtk_widget_has_focus (column->button))
10550         {
10551           found_focus = TRUE;
10552           break;
10553         }
10554     }
10555   
10556   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10557     found_focus = TRUE;
10558
10559   if (!found_focus)
10560     return FALSE;
10561
10562   if (tree_view->priv->search_column < 0)
10563     return FALSE;
10564
10565   gtk_tree_view_ensure_interactive_directory (tree_view);
10566
10567   if (keybinding)
10568     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10569
10570   /* done, show it */
10571   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10572   gtk_widget_show (tree_view->priv->search_window);
10573   if (tree_view->priv->search_entry_changed_id == 0)
10574     {
10575       tree_view->priv->search_entry_changed_id =
10576         g_signal_connect (tree_view->priv->search_entry, "changed",
10577                           G_CALLBACK (gtk_tree_view_search_init),
10578                           tree_view);
10579     }
10580
10581   tree_view->priv->typeselect_flush_timeout =
10582     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10583                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10584                    tree_view);
10585
10586   /* Grab focus will select all the text.  We don't want that to happen, so we
10587    * call the parent instance and bypass the selection change.  This is probably
10588    * really non-kosher. */
10589   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10590   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10591
10592   /* send focus-in event */
10593   send_focus_change (tree_view->priv->search_entry, device, TRUE);
10594
10595   /* search first matching iter */
10596   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10597
10598   return TRUE;
10599 }
10600
10601 static gboolean
10602 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10603 {
10604   return gtk_tree_view_real_start_interactive_search (tree_view,
10605                                                       gtk_get_current_event_device (),
10606                                                       TRUE);
10607 }
10608
10609 /* this function returns the new width of the column being resized given
10610  * the column and x position of the cursor; the x cursor position is passed
10611  * in as a pointer and automagicly corrected if it's beyond min/max limits
10612  */
10613 static gint
10614 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10615                                 gint       i,
10616                                 gint      *x)
10617 {
10618   GtkAllocation allocation;
10619   GtkTreeViewColumn *column;
10620   GtkRequisition button_req;
10621   gint max_width, min_width;
10622   gint width;
10623   gboolean rtl;
10624
10625   /* first translate the x position from widget->window
10626    * to clist->clist_window
10627    */
10628   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10629   column = g_list_nth (tree_view->priv->columns, i)->data;
10630   gtk_widget_get_allocation (column->button, &allocation);
10631   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
10632
10633   /* Clamp down the value */
10634   min_width = gtk_tree_view_column_get_min_width (column);
10635   if (min_width == -1)
10636     {
10637       gtk_widget_get_preferred_size (column->button, &button_req, NULL);
10638       width = MAX (button_req.width, width);
10639     }
10640   else
10641     width = MAX (min_width, width);
10642
10643   max_width = gtk_tree_view_column_get_max_width (column);
10644   if (max_width != -1)
10645     width = MIN (width, max_width);
10646
10647   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
10648
10649   return width;
10650 }
10651
10652
10653 /* FIXME this adjust_allocation is a big cut-and-paste from
10654  * GtkCList, needs to be some "official" way to do this
10655  * factored out.
10656  */
10657 typedef struct
10658 {
10659   GdkWindow *window;
10660   int dx;
10661   int dy;
10662 } ScrollData;
10663
10664 /* The window to which widget->window is relative */
10665 #define ALLOCATION_WINDOW(widget)               \
10666    (!gtk_widget_get_has_window (widget) ?                   \
10667     gtk_widget_get_window (widget) :                        \
10668     gdk_window_get_parent (gtk_widget_get_window (widget)))
10669
10670 static void
10671 adjust_allocation_recurse (GtkWidget *widget,
10672                            gpointer   data)
10673 {
10674   GtkAllocation allocation;
10675   ScrollData *scroll_data = data;
10676
10677   /* Need to really size allocate instead of just poking
10678    * into widget->allocation if the widget is not realized.
10679    * FIXME someone figure out why this was.
10680    */
10681   gtk_widget_get_allocation (widget, &allocation);
10682   if (!gtk_widget_get_realized (widget))
10683     {
10684       if (gtk_widget_get_visible (widget))
10685         {
10686           GdkRectangle tmp_rectangle = allocation;
10687           tmp_rectangle.x += scroll_data->dx;
10688           tmp_rectangle.y += scroll_data->dy;
10689           
10690           gtk_widget_size_allocate (widget, &tmp_rectangle);
10691         }
10692     }
10693   else
10694     {
10695       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10696         {
10697           allocation.x += scroll_data->dx;
10698           allocation.y += scroll_data->dy;
10699           gtk_widget_set_allocation (widget, &allocation);
10700
10701           if (GTK_IS_CONTAINER (widget))
10702             gtk_container_forall (GTK_CONTAINER (widget),
10703                                   adjust_allocation_recurse,
10704                                   data);
10705         }
10706     }
10707 }
10708
10709 static void
10710 adjust_allocation (GtkWidget *widget,
10711                    int        dx,
10712                    int        dy)
10713 {
10714   ScrollData scroll_data;
10715
10716   if (gtk_widget_get_realized (widget))
10717     scroll_data.window = ALLOCATION_WINDOW (widget);
10718   else
10719     scroll_data.window = NULL;
10720     
10721   scroll_data.dx = dx;
10722   scroll_data.dy = dy;
10723   
10724   adjust_allocation_recurse (widget, &scroll_data);
10725 }
10726
10727 /* Callbacks */
10728 static void
10729 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10730                                   GtkTreeView   *tree_view)
10731 {
10732   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10733     {
10734       gint dy;
10735         
10736       gdk_window_move (tree_view->priv->bin_window,
10737                        - tree_view->priv->hadjustment->value,
10738                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10739       gdk_window_move (tree_view->priv->header_window,
10740                        - tree_view->priv->hadjustment->value,
10741                        0);
10742       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10743       if (dy)
10744         {
10745           update_prelight (tree_view,
10746                            tree_view->priv->event_last_x,
10747                            tree_view->priv->event_last_y - dy);
10748
10749           if (tree_view->priv->edited_column &&
10750               GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10751             {
10752               GList *list;
10753               GtkWidget *widget;
10754               GtkTreeViewChild *child = NULL;
10755
10756               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10757               adjust_allocation (widget, 0, dy); 
10758               
10759               for (list = tree_view->priv->children; list; list = list->next)
10760                 {
10761                   child = (GtkTreeViewChild *)list->data;
10762                   if (child->widget == widget)
10763                     {
10764                       child->y += dy;
10765                       break;
10766                     }
10767                 }
10768             }
10769         }
10770       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10771
10772       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10773         {
10774           /* update our dy and top_row */
10775           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10776
10777           if (!tree_view->priv->in_top_row_to_dy)
10778             gtk_tree_view_dy_to_top_row (tree_view);
10779         }
10780
10781       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10782       gtk_tree_view_bin_process_updates (tree_view);
10783     }
10784 }
10785
10786 \f
10787
10788 /* Public methods
10789  */
10790
10791 /**
10792  * gtk_tree_view_new:
10793  *
10794  * Creates a new #GtkTreeView widget.
10795  *
10796  * Return value: A newly created #GtkTreeView widget.
10797  **/
10798 GtkWidget *
10799 gtk_tree_view_new (void)
10800 {
10801   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10802 }
10803
10804 /**
10805  * gtk_tree_view_new_with_model:
10806  * @model: the model.
10807  *
10808  * Creates a new #GtkTreeView widget with the model initialized to @model.
10809  *
10810  * Return value: A newly created #GtkTreeView widget.
10811  **/
10812 GtkWidget *
10813 gtk_tree_view_new_with_model (GtkTreeModel *model)
10814 {
10815   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10816 }
10817
10818 /* Public Accessors
10819  */
10820
10821 /**
10822  * gtk_tree_view_get_model:
10823  * @tree_view: a #GtkTreeView
10824  *
10825  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10826  * model is unset.
10827  *
10828  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
10829  **/
10830 GtkTreeModel *
10831 gtk_tree_view_get_model (GtkTreeView *tree_view)
10832 {
10833   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10834
10835   return tree_view->priv->model;
10836 }
10837
10838 /**
10839  * gtk_tree_view_set_model:
10840  * @tree_view: A #GtkTreeNode.
10841  * @model: (allow-none): The model.
10842  *
10843  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10844  * set, it will remove it before setting the new model.  If @model is %NULL,
10845  * then it will unset the old model.
10846  **/
10847 void
10848 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10849                          GtkTreeModel *model)
10850 {
10851   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10852   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10853
10854   if (model == tree_view->priv->model)
10855     return;
10856
10857   if (tree_view->priv->scroll_to_path)
10858     {
10859       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10860       tree_view->priv->scroll_to_path = NULL;
10861     }
10862
10863   if (tree_view->priv->model)
10864     {
10865       GList *tmplist = tree_view->priv->columns;
10866
10867       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10868       gtk_tree_view_stop_editing (tree_view, TRUE);
10869
10870       remove_expand_collapse_timeout (tree_view);
10871
10872       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10873                                             gtk_tree_view_row_changed,
10874                                             tree_view);
10875       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10876                                             gtk_tree_view_row_inserted,
10877                                             tree_view);
10878       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10879                                             gtk_tree_view_row_has_child_toggled,
10880                                             tree_view);
10881       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10882                                             gtk_tree_view_row_deleted,
10883                                             tree_view);
10884       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10885                                             gtk_tree_view_rows_reordered,
10886                                             tree_view);
10887
10888       for (; tmplist; tmplist = tmplist->next)
10889         _gtk_tree_view_column_unset_model (tmplist->data,
10890                                            tree_view->priv->model);
10891
10892       if (tree_view->priv->tree)
10893         gtk_tree_view_free_rbtree (tree_view);
10894
10895       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10896       tree_view->priv->drag_dest_row = NULL;
10897       gtk_tree_row_reference_free (tree_view->priv->cursor);
10898       tree_view->priv->cursor = NULL;
10899       gtk_tree_row_reference_free (tree_view->priv->anchor);
10900       tree_view->priv->anchor = NULL;
10901       gtk_tree_row_reference_free (tree_view->priv->top_row);
10902       tree_view->priv->top_row = NULL;
10903       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10904       tree_view->priv->scroll_to_path = NULL;
10905
10906       tree_view->priv->scroll_to_column = NULL;
10907
10908       g_object_unref (tree_view->priv->model);
10909
10910       tree_view->priv->search_column = -1;
10911       tree_view->priv->fixed_height_check = 0;
10912       tree_view->priv->fixed_height = -1;
10913       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10914       tree_view->priv->last_button_x = -1;
10915       tree_view->priv->last_button_y = -1;
10916     }
10917
10918   tree_view->priv->model = model;
10919
10920   if (tree_view->priv->model)
10921     {
10922       gint i;
10923       GtkTreePath *path;
10924       GtkTreeIter iter;
10925       GtkTreeModelFlags flags;
10926
10927       if (tree_view->priv->search_column == -1)
10928         {
10929           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10930             {
10931               GType type = gtk_tree_model_get_column_type (model, i);
10932
10933               if (g_value_type_transformable (type, G_TYPE_STRING))
10934                 {
10935                   tree_view->priv->search_column = i;
10936                   break;
10937                 }
10938             }
10939         }
10940
10941       g_object_ref (tree_view->priv->model);
10942       g_signal_connect (tree_view->priv->model,
10943                         "row-changed",
10944                         G_CALLBACK (gtk_tree_view_row_changed),
10945                         tree_view);
10946       g_signal_connect (tree_view->priv->model,
10947                         "row-inserted",
10948                         G_CALLBACK (gtk_tree_view_row_inserted),
10949                         tree_view);
10950       g_signal_connect (tree_view->priv->model,
10951                         "row-has-child-toggled",
10952                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10953                         tree_view);
10954       g_signal_connect (tree_view->priv->model,
10955                         "row-deleted",
10956                         G_CALLBACK (gtk_tree_view_row_deleted),
10957                         tree_view);
10958       g_signal_connect (tree_view->priv->model,
10959                         "rows-reordered",
10960                         G_CALLBACK (gtk_tree_view_rows_reordered),
10961                         tree_view);
10962
10963       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10964       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10965         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10966       else
10967         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10968
10969       path = gtk_tree_path_new_first ();
10970       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10971         {
10972           tree_view->priv->tree = _gtk_rbtree_new ();
10973           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10974         }
10975       gtk_tree_path_free (path);
10976
10977       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10978       install_presize_handler (tree_view);
10979     }
10980
10981   g_object_notify (G_OBJECT (tree_view), "model");
10982
10983   if (tree_view->priv->selection)
10984   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10985
10986   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10987     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10988 }
10989
10990 /**
10991  * gtk_tree_view_get_selection:
10992  * @tree_view: A #GtkTreeView.
10993  *
10994  * Gets the #GtkTreeSelection associated with @tree_view.
10995  *
10996  * Return value: (transfer none): A #GtkTreeSelection object.
10997  **/
10998 GtkTreeSelection *
10999 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11000 {
11001   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11002
11003   return tree_view->priv->selection;
11004 }
11005
11006 /**
11007  * gtk_tree_view_get_hadjustment:
11008  * @tree_view: A #GtkTreeView
11009  *
11010  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11011  *
11012  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11013  *     if none is currently being used.
11014  *
11015  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11016  **/
11017 GtkAdjustment *
11018 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11019 {
11020   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11021
11022   return tree_view->priv->hadjustment;
11023 }
11024
11025 /**
11026  * gtk_tree_view_set_hadjustment:
11027  * @tree_view: A #GtkTreeView
11028  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11029  *
11030  * Sets the #GtkAdjustment for the current horizontal aspect.
11031  *
11032  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11033  **/
11034 void
11035 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11036                                GtkAdjustment *adjustment)
11037 {
11038   GtkTreeViewPrivate *priv = tree_view->priv;
11039
11040   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11041   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11042
11043   if (adjustment && priv->hadjustment == adjustment)
11044     return;
11045
11046   if (priv->hadjustment != NULL)
11047     {
11048       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11049                                             gtk_tree_view_adjustment_changed,
11050                                             tree_view);
11051       g_object_unref (priv->hadjustment);
11052     }
11053
11054   if (adjustment == NULL)
11055     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11056                                      0.0, 0.0, 0.0);
11057
11058   g_signal_connect (adjustment, "value-changed",
11059                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11060   priv->hadjustment = g_object_ref_sink (adjustment);
11061   /* FIXME: Adjustment should probably be populated here with fresh values, but
11062    * internal details are too complicated for me to decipher right now.
11063    */
11064   gtk_tree_view_adjustment_changed (NULL, tree_view);
11065
11066   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11067 }
11068
11069 /**
11070  * gtk_tree_view_get_vadjustment:
11071  * @tree_view: A #GtkTreeView
11072  *
11073  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11074  *
11075  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11076  *     if none is currently being used.
11077  *
11078  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11079  **/
11080 GtkAdjustment *
11081 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11082 {
11083   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11084
11085   return tree_view->priv->vadjustment;
11086 }
11087
11088 /**
11089  * gtk_tree_view_set_vadjustment:
11090  * @tree_view: A #GtkTreeView
11091  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11092  *
11093  * Sets the #GtkAdjustment for the current vertical aspect.
11094  *
11095  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11096  **/
11097 void
11098 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11099                                GtkAdjustment *adjustment)
11100 {
11101   GtkTreeViewPrivate *priv = tree_view->priv;
11102
11103   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11104   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11105
11106   if (adjustment && priv->vadjustment == adjustment)
11107     return;
11108
11109   if (priv->vadjustment != NULL)
11110     {
11111       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11112                                             gtk_tree_view_adjustment_changed,
11113                                             tree_view);
11114       g_object_unref (priv->vadjustment);
11115     }
11116
11117   if (adjustment == NULL)
11118     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11119                                      0.0, 0.0, 0.0);
11120
11121   g_signal_connect (adjustment, "value-changed",
11122                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11123   priv->vadjustment = g_object_ref_sink (adjustment);
11124   /* FIXME: Adjustment should probably be populated here with fresh values, but
11125    * internal details are too complicated for me to decipher right now.
11126    */
11127   gtk_tree_view_adjustment_changed (NULL, tree_view);
11128   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11129 }
11130
11131 /* Column and header operations */
11132
11133 /**
11134  * gtk_tree_view_get_headers_visible:
11135  * @tree_view: A #GtkTreeView.
11136  *
11137  * Returns %TRUE if the headers on the @tree_view are visible.
11138  *
11139  * Return value: Whether the headers are visible or not.
11140  **/
11141 gboolean
11142 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11143 {
11144   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11145
11146   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11147 }
11148
11149 /**
11150  * gtk_tree_view_set_headers_visible:
11151  * @tree_view: A #GtkTreeView.
11152  * @headers_visible: %TRUE if the headers are visible
11153  *
11154  * Sets the visibility state of the headers.
11155  **/
11156 void
11157 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11158                                    gboolean     headers_visible)
11159 {
11160   gint x, y;
11161   GList *list;
11162   GtkTreeViewColumn *column;
11163   GtkAllocation allocation;
11164
11165   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11166
11167   headers_visible = !! headers_visible;
11168
11169   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
11170     return;
11171
11172   if (headers_visible)
11173     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11174   else
11175     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11176
11177   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11178     {
11179       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11180       if (headers_visible)
11181         {
11182           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11183           gdk_window_move_resize (tree_view->priv->bin_window,
11184                                   x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view),
11185                                   tree_view->priv->width, allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
11186
11187           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11188             gtk_tree_view_map_buttons (tree_view);
11189         }
11190       else
11191         {
11192           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11193
11194           for (list = tree_view->priv->columns; list; list = list->next)
11195             {
11196               column = list->data;
11197               gtk_widget_unmap (column->button);
11198             }
11199           gdk_window_hide (tree_view->priv->header_window);
11200         }
11201     }
11202
11203   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11204   tree_view->priv->vadjustment->page_size = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11205   tree_view->priv->vadjustment->page_increment = (allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11206   tree_view->priv->vadjustment->lower = 0;
11207   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11208   gtk_adjustment_changed (tree_view->priv->vadjustment);
11209
11210   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11211
11212   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11213 }
11214
11215 /**
11216  * gtk_tree_view_columns_autosize:
11217  * @tree_view: A #GtkTreeView.
11218  *
11219  * Resizes all columns to their optimal width. Only works after the
11220  * treeview has been realized.
11221  **/
11222 void
11223 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11224 {
11225   gboolean dirty = FALSE;
11226   GList *list;
11227   GtkTreeViewColumn *column;
11228
11229   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11230
11231   for (list = tree_view->priv->columns; list; list = list->next)
11232     {
11233       column = list->data;
11234       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11235         continue;
11236       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11237       dirty = TRUE;
11238     }
11239
11240   if (dirty)
11241     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11242 }
11243
11244 /**
11245  * gtk_tree_view_set_headers_clickable:
11246  * @tree_view: A #GtkTreeView.
11247  * @setting: %TRUE if the columns are clickable.
11248  *
11249  * Allow the column title buttons to be clicked.
11250  **/
11251 void
11252 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11253                                      gboolean   setting)
11254 {
11255   GList *list;
11256
11257   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11258
11259   for (list = tree_view->priv->columns; list; list = list->next)
11260     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11261
11262   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11263 }
11264
11265
11266 /**
11267  * gtk_tree_view_get_headers_clickable:
11268  * @tree_view: A #GtkTreeView.
11269  *
11270  * Returns whether all header columns are clickable.
11271  *
11272  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11273  *
11274  * Since: 2.10
11275  **/
11276 gboolean 
11277 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11278 {
11279   GList *list;
11280   
11281   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11282
11283   for (list = tree_view->priv->columns; list; list = list->next)
11284     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11285       return FALSE;
11286
11287   return TRUE;
11288 }
11289
11290 /**
11291  * gtk_tree_view_set_rules_hint
11292  * @tree_view: a #GtkTreeView
11293  * @setting: %TRUE if the tree requires reading across rows
11294  *
11295  * This function tells GTK+ that the user interface for your
11296  * application requires users to read across tree rows and associate
11297  * cells with one another. By default, GTK+ will then render the tree
11298  * with alternating row colors. Do <emphasis>not</emphasis> use it
11299  * just because you prefer the appearance of the ruled tree; that's a
11300  * question for the theme. Some themes will draw tree rows in
11301  * alternating colors even when rules are turned off, and users who
11302  * prefer that appearance all the time can choose those themes. You
11303  * should call this function only as a <emphasis>semantic</emphasis>
11304  * hint to the theme engine that your tree makes alternating colors
11305  * useful from a functional standpoint (since it has lots of columns,
11306  * generally).
11307  *
11308  **/
11309 void
11310 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11311                               gboolean      setting)
11312 {
11313   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11314
11315   setting = setting != FALSE;
11316
11317   if (tree_view->priv->has_rules != setting)
11318     {
11319       tree_view->priv->has_rules = setting;
11320       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11321     }
11322
11323   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11324 }
11325
11326 /**
11327  * gtk_tree_view_get_rules_hint
11328  * @tree_view: a #GtkTreeView
11329  *
11330  * Gets the setting set by gtk_tree_view_set_rules_hint().
11331  *
11332  * Return value: %TRUE if rules are useful for the user of this tree
11333  **/
11334 gboolean
11335 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11336 {
11337   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11338
11339   return tree_view->priv->has_rules;
11340 }
11341
11342 /* Public Column functions
11343  */
11344
11345 /**
11346  * gtk_tree_view_append_column:
11347  * @tree_view: A #GtkTreeView.
11348  * @column: The #GtkTreeViewColumn to add.
11349  *
11350  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11351  * mode enabled, then @column must have its "sizing" property set to be
11352  * GTK_TREE_VIEW_COLUMN_FIXED.
11353  *
11354  * Return value: The number of columns in @tree_view after appending.
11355  **/
11356 gint
11357 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11358                              GtkTreeViewColumn *column)
11359 {
11360   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11361   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11362   g_return_val_if_fail (column->tree_view == NULL, -1);
11363
11364   return gtk_tree_view_insert_column (tree_view, column, -1);
11365 }
11366
11367
11368 /**
11369  * gtk_tree_view_remove_column:
11370  * @tree_view: A #GtkTreeView.
11371  * @column: The #GtkTreeViewColumn to remove.
11372  *
11373  * Removes @column from @tree_view.
11374  *
11375  * Return value: The number of columns in @tree_view after removing.
11376  **/
11377 gint
11378 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11379                              GtkTreeViewColumn *column)
11380 {
11381   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11382   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11383   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11384
11385   if (tree_view->priv->focus_column == column)
11386     tree_view->priv->focus_column = NULL;
11387
11388   if (tree_view->priv->edited_column == column)
11389     {
11390       gtk_tree_view_stop_editing (tree_view, TRUE);
11391
11392       /* no need to, but just to be sure ... */
11393       tree_view->priv->edited_column = NULL;
11394     }
11395
11396   if (tree_view->priv->expander_column == column)
11397     tree_view->priv->expander_column = NULL;
11398
11399   g_signal_handlers_disconnect_by_func (column,
11400                                         G_CALLBACK (column_sizing_notify),
11401                                         tree_view);
11402
11403   _gtk_tree_view_column_unset_tree_view (column);
11404
11405   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11406   tree_view->priv->n_columns--;
11407
11408   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11409     {
11410       GList *list;
11411
11412       _gtk_tree_view_column_unrealize_button (column);
11413       for (list = tree_view->priv->columns; list; list = list->next)
11414         {
11415           GtkTreeViewColumn *tmp_column;
11416
11417           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11418           if (gtk_tree_view_column_get_visible (tmp_column))
11419             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11420         }
11421
11422       if (tree_view->priv->n_columns == 0 &&
11423           gtk_tree_view_get_headers_visible (tree_view))
11424         gdk_window_hide (tree_view->priv->header_window);
11425
11426       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11427     }
11428
11429   g_object_unref (column);
11430   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11431
11432   return tree_view->priv->n_columns;
11433 }
11434
11435 /**
11436  * gtk_tree_view_insert_column:
11437  * @tree_view: A #GtkTreeView.
11438  * @column: The #GtkTreeViewColumn to be inserted.
11439  * @position: The position to insert @column in.
11440  *
11441  * This inserts the @column into the @tree_view at @position.  If @position is
11442  * -1, then the column is inserted at the end. If @tree_view has
11443  * "fixed_height" mode enabled, then @column must have its "sizing" property
11444  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11445  *
11446  * Return value: The number of columns in @tree_view after insertion.
11447  **/
11448 gint
11449 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11450                              GtkTreeViewColumn *column,
11451                              gint               position)
11452 {
11453   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11454   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11455   g_return_val_if_fail (column->tree_view == NULL, -1);
11456
11457   if (tree_view->priv->fixed_height_mode)
11458     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11459                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11460
11461   g_object_ref_sink (column);
11462
11463   if (tree_view->priv->n_columns == 0 &&
11464       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11465       gtk_tree_view_get_headers_visible (tree_view))
11466     {
11467       gdk_window_show (tree_view->priv->header_window);
11468     }
11469
11470   g_signal_connect (column, "notify::sizing",
11471                     G_CALLBACK (column_sizing_notify), tree_view);
11472
11473   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11474                                             column, position);
11475   tree_view->priv->n_columns++;
11476
11477   _gtk_tree_view_column_set_tree_view (column, tree_view);
11478
11479   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11480     {
11481       GList *list;
11482
11483       _gtk_tree_view_column_realize_button (column);
11484
11485       for (list = tree_view->priv->columns; list; list = list->next)
11486         {
11487           column = GTK_TREE_VIEW_COLUMN (list->data);
11488           if (gtk_tree_view_column_get_visible (column))
11489             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11490         }
11491       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11492     }
11493
11494   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11495
11496   return tree_view->priv->n_columns;
11497 }
11498
11499 /**
11500  * gtk_tree_view_insert_column_with_attributes:
11501  * @tree_view: A #GtkTreeView
11502  * @position: The position to insert the new column in.
11503  * @title: The title to set the header to.
11504  * @cell: The #GtkCellRenderer.
11505  * @Varargs: A %NULL-terminated list of attributes.
11506  *
11507  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11508  * @position.  If @position is -1, then the newly created column is inserted at
11509  * the end.  The column is initialized with the attributes given. If @tree_view
11510  * has "fixed_height" mode enabled, then the new column will have its sizing
11511  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11512  *
11513  * Return value: The number of columns in @tree_view after insertion.
11514  **/
11515 gint
11516 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11517                                              gint             position,
11518                                              const gchar     *title,
11519                                              GtkCellRenderer *cell,
11520                                              ...)
11521 {
11522   GtkTreeViewColumn *column;
11523   gchar *attribute;
11524   va_list args;
11525   gint column_id;
11526
11527   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11528
11529   column = gtk_tree_view_column_new ();
11530   if (tree_view->priv->fixed_height_mode)
11531     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11532
11533   gtk_tree_view_column_set_title (column, title);
11534   gtk_tree_view_column_pack_start (column, cell, TRUE);
11535
11536   va_start (args, cell);
11537
11538   attribute = va_arg (args, gchar *);
11539
11540   while (attribute != NULL)
11541     {
11542       column_id = va_arg (args, gint);
11543       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11544       attribute = va_arg (args, gchar *);
11545     }
11546
11547   va_end (args);
11548
11549   gtk_tree_view_insert_column (tree_view, column, position);
11550
11551   return tree_view->priv->n_columns;
11552 }
11553
11554 /**
11555  * gtk_tree_view_insert_column_with_data_func:
11556  * @tree_view: a #GtkTreeView
11557  * @position: Position to insert, -1 for append
11558  * @title: column title
11559  * @cell: cell renderer for column
11560  * @func: function to set attributes of cell renderer
11561  * @data: data for @func
11562  * @dnotify: destroy notifier for @data
11563  *
11564  * Convenience function that inserts a new column into the #GtkTreeView
11565  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11566  * attributes (normally using data from the model). See also
11567  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11568  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11569  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11570  *
11571  * Return value: number of columns in the tree view post-insert
11572  **/
11573 gint
11574 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11575                                              gint                       position,
11576                                              const gchar               *title,
11577                                              GtkCellRenderer           *cell,
11578                                              GtkTreeCellDataFunc        func,
11579                                              gpointer                   data,
11580                                              GDestroyNotify             dnotify)
11581 {
11582   GtkTreeViewColumn *column;
11583
11584   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11585
11586   column = gtk_tree_view_column_new ();
11587   if (tree_view->priv->fixed_height_mode)
11588     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11589
11590   gtk_tree_view_column_set_title (column, title);
11591   gtk_tree_view_column_pack_start (column, cell, TRUE);
11592   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11593
11594   gtk_tree_view_insert_column (tree_view, column, position);
11595
11596   return tree_view->priv->n_columns;
11597 }
11598
11599 /**
11600  * gtk_tree_view_get_column:
11601  * @tree_view: A #GtkTreeView.
11602  * @n: The position of the column, counting from 0.
11603  *
11604  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11605  *
11606  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
11607  *     position is outside the range of columns.
11608  **/
11609 GtkTreeViewColumn *
11610 gtk_tree_view_get_column (GtkTreeView *tree_view,
11611                           gint         n)
11612 {
11613   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11614
11615   if (n < 0 || n >= tree_view->priv->n_columns)
11616     return NULL;
11617
11618   if (tree_view->priv->columns == NULL)
11619     return NULL;
11620
11621   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11622 }
11623
11624 /**
11625  * gtk_tree_view_get_columns:
11626  * @tree_view: A #GtkTreeView
11627  *
11628  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11629  * The returned list must be freed with g_list_free ().
11630  *
11631  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11632  **/
11633 GList *
11634 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11635 {
11636   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11637
11638   return g_list_copy (tree_view->priv->columns);
11639 }
11640
11641 /**
11642  * gtk_tree_view_move_column_after:
11643  * @tree_view: A #GtkTreeView
11644  * @column: The #GtkTreeViewColumn to be moved.
11645  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11646  *
11647  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11648  * @column is placed in the first position.
11649  **/
11650 void
11651 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11652                                  GtkTreeViewColumn *column,
11653                                  GtkTreeViewColumn *base_column)
11654 {
11655   GList *column_list_el, *base_el = NULL;
11656
11657   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11658
11659   column_list_el = g_list_find (tree_view->priv->columns, column);
11660   g_return_if_fail (column_list_el != NULL);
11661
11662   if (base_column)
11663     {
11664       base_el = g_list_find (tree_view->priv->columns, base_column);
11665       g_return_if_fail (base_el != NULL);
11666     }
11667
11668   if (column_list_el->prev == base_el)
11669     return;
11670
11671   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11672   if (base_el == NULL)
11673     {
11674       column_list_el->prev = NULL;
11675       column_list_el->next = tree_view->priv->columns;
11676       if (column_list_el->next)
11677         column_list_el->next->prev = column_list_el;
11678       tree_view->priv->columns = column_list_el;
11679     }
11680   else
11681     {
11682       column_list_el->prev = base_el;
11683       column_list_el->next = base_el->next;
11684       if (column_list_el->next)
11685         column_list_el->next->prev = column_list_el;
11686       base_el->next = column_list_el;
11687     }
11688
11689   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11690     {
11691       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11692       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11693     }
11694
11695   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11696 }
11697
11698 /**
11699  * gtk_tree_view_set_expander_column:
11700  * @tree_view: A #GtkTreeView
11701  * @column: %NULL, or the column to draw the expander arrow at.
11702  *
11703  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11704  * If @column is %NULL, then the expander arrow is always at the first 
11705  * visible column.
11706  *
11707  * If you do not want expander arrow to appear in your tree, set the 
11708  * expander column to a hidden column.
11709  **/
11710 void
11711 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11712                                    GtkTreeViewColumn *column)
11713 {
11714   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11715   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11716
11717   if (tree_view->priv->expander_column != column)
11718     {
11719       GList *list;
11720
11721       if (column)
11722         {
11723           /* Confirm that column is in tree_view */
11724           for (list = tree_view->priv->columns; list; list = list->next)
11725             if (list->data == column)
11726               break;
11727           g_return_if_fail (list != NULL);
11728         }
11729
11730       tree_view->priv->expander_column = column;
11731       g_object_notify (G_OBJECT (tree_view), "expander-column");
11732     }
11733 }
11734
11735 /**
11736  * gtk_tree_view_get_expander_column:
11737  * @tree_view: A #GtkTreeView
11738  *
11739  * Returns the column that is the current expander column.
11740  * This column has the expander arrow drawn next to it.
11741  *
11742  * Return value: (transfer none): The expander column.
11743  **/
11744 GtkTreeViewColumn *
11745 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11746 {
11747   GList *list;
11748
11749   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11750
11751   for (list = tree_view->priv->columns; list; list = list->next)
11752     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11753       return (GtkTreeViewColumn *) list->data;
11754   return NULL;
11755 }
11756
11757
11758 /**
11759  * gtk_tree_view_set_column_drag_function:
11760  * @tree_view: A #GtkTreeView.
11761  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
11762  * @user_data: (allow-none): User data to be passed to @func, or %NULL
11763  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
11764  *
11765  * Sets a user function for determining where a column may be dropped when
11766  * dragged.  This function is called on every column pair in turn at the
11767  * beginning of a column drag to determine where a drop can take place.  The
11768  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11769  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11770  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11771  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11772  * @tree_view reverts to the default behavior of allowing all columns to be
11773  * dropped everywhere.
11774  **/
11775 void
11776 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11777                                         GtkTreeViewColumnDropFunc  func,
11778                                         gpointer                   user_data,
11779                                         GDestroyNotify             destroy)
11780 {
11781   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11782
11783   if (tree_view->priv->column_drop_func_data_destroy)
11784     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11785
11786   tree_view->priv->column_drop_func = func;
11787   tree_view->priv->column_drop_func_data = user_data;
11788   tree_view->priv->column_drop_func_data_destroy = destroy;
11789 }
11790
11791 /**
11792  * gtk_tree_view_scroll_to_point:
11793  * @tree_view: a #GtkTreeView
11794  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11795  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11796  *
11797  * Scrolls the tree view such that the top-left corner of the visible
11798  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11799  * in tree coordinates.  The @tree_view must be realized before
11800  * this function is called.  If it isn't, you probably want to be
11801  * using gtk_tree_view_scroll_to_cell().
11802  *
11803  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11804  **/
11805 void
11806 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11807                                gint         tree_x,
11808                                gint         tree_y)
11809 {
11810   GtkAdjustment *hadj;
11811   GtkAdjustment *vadj;
11812
11813   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11814   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
11815
11816   hadj = tree_view->priv->hadjustment;
11817   vadj = tree_view->priv->vadjustment;
11818
11819   if (tree_x != -1)
11820     gtk_adjustment_set_value (hadj, tree_x);
11821   if (tree_y != -1)
11822     gtk_adjustment_set_value (vadj, tree_y);
11823 }
11824
11825 /**
11826  * gtk_tree_view_scroll_to_cell:
11827  * @tree_view: A #GtkTreeView.
11828  * @path: (allow-none): The path of the row to move to, or %NULL.
11829  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11830  * @use_align: whether to use alignment arguments, or %FALSE.
11831  * @row_align: The vertical alignment of the row specified by @path.
11832  * @col_align: The horizontal alignment of the column specified by @column.
11833  *
11834  * Moves the alignments of @tree_view to the position specified by @column and
11835  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11836  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11837  * or @path need to be non-%NULL.  @row_align determines where the row is
11838  * placed, and @col_align determines where @column is placed.  Both are expected
11839  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11840  * right/bottom alignment, 0.5 means center.
11841  *
11842  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11843  * tree does the minimum amount of work to scroll the cell onto the screen.
11844  * This means that the cell will be scrolled to the edge closest to its current
11845  * position.  If the cell is currently visible on the screen, nothing is done.
11846  *
11847  * This function only works if the model is set, and @path is a valid row on the
11848  * model.  If the model changes before the @tree_view is realized, the centered
11849  * path will be modified to reflect this change.
11850  **/
11851 void
11852 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11853                               GtkTreePath       *path,
11854                               GtkTreeViewColumn *column,
11855                               gboolean           use_align,
11856                               gfloat             row_align,
11857                               gfloat             col_align)
11858 {
11859   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11860   g_return_if_fail (tree_view->priv->model != NULL);
11861   g_return_if_fail (tree_view->priv->tree != NULL);
11862   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11863   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11864   g_return_if_fail (path != NULL || column != NULL);
11865
11866 #if 0
11867   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11868            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11869 #endif
11870   row_align = CLAMP (row_align, 0.0, 1.0);
11871   col_align = CLAMP (col_align, 0.0, 1.0);
11872
11873
11874   /* Note: Despite the benefits that come from having one code path for the
11875    * scrolling code, we short-circuit validate_visible_area's immplementation as
11876    * it is much slower than just going to the point.
11877    */
11878   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
11879       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
11880       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
11881       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11882     {
11883       if (tree_view->priv->scroll_to_path)
11884         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11885
11886       tree_view->priv->scroll_to_path = NULL;
11887       tree_view->priv->scroll_to_column = NULL;
11888
11889       if (path)
11890         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11891       if (column)
11892         tree_view->priv->scroll_to_column = column;
11893       tree_view->priv->scroll_to_use_align = use_align;
11894       tree_view->priv->scroll_to_row_align = row_align;
11895       tree_view->priv->scroll_to_col_align = col_align;
11896
11897       install_presize_handler (tree_view);
11898     }
11899   else
11900     {
11901       GdkRectangle cell_rect;
11902       GdkRectangle vis_rect;
11903       gint dest_x, dest_y;
11904
11905       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11906       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11907
11908       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11909
11910       dest_x = vis_rect.x;
11911       dest_y = vis_rect.y;
11912
11913       if (column)
11914         {
11915           if (use_align)
11916             {
11917               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11918             }
11919           else
11920             {
11921               if (cell_rect.x < vis_rect.x)
11922                 dest_x = cell_rect.x;
11923               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11924                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11925             }
11926         }
11927
11928       if (path)
11929         {
11930           if (use_align)
11931             {
11932               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11933               dest_y = MAX (dest_y, 0);
11934             }
11935           else
11936             {
11937               if (cell_rect.y < vis_rect.y)
11938                 dest_y = cell_rect.y;
11939               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11940                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11941             }
11942         }
11943
11944       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11945     }
11946 }
11947
11948 /**
11949  * gtk_tree_view_row_activated:
11950  * @tree_view: A #GtkTreeView
11951  * @path: The #GtkTreePath to be activated.
11952  * @column: The #GtkTreeViewColumn to be activated.
11953  *
11954  * Activates the cell determined by @path and @column.
11955  **/
11956 void
11957 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11958                              GtkTreePath       *path,
11959                              GtkTreeViewColumn *column)
11960 {
11961   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11962
11963   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11964 }
11965
11966
11967 static void
11968 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11969                                           GtkRBNode *node,
11970                                           gpointer   data)
11971 {
11972   GtkTreeView *tree_view = data;
11973
11974   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11975       node->children)
11976     {
11977       GtkTreePath *path;
11978       GtkTreeIter iter;
11979
11980       path = _gtk_tree_view_find_path (tree_view, tree, node);
11981       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11982
11983       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11984
11985       gtk_tree_path_free (path);
11986     }
11987
11988   if (node->children)
11989     _gtk_rbtree_traverse (node->children,
11990                           node->children->root,
11991                           G_PRE_ORDER,
11992                           gtk_tree_view_expand_all_emission_helper,
11993                           tree_view);
11994 }
11995
11996 /**
11997  * gtk_tree_view_expand_all:
11998  * @tree_view: A #GtkTreeView.
11999  *
12000  * Recursively expands all nodes in the @tree_view.
12001  **/
12002 void
12003 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12004 {
12005   GtkTreePath *path;
12006   GtkRBTree *tree;
12007   GtkRBNode *node;
12008
12009   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12010
12011   if (tree_view->priv->tree == NULL)
12012     return;
12013
12014   path = gtk_tree_path_new_first ();
12015   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12016
12017   while (node)
12018     {
12019       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12020       node = _gtk_rbtree_next (tree, node);
12021       gtk_tree_path_next (path);
12022   }
12023
12024   gtk_tree_path_free (path);
12025 }
12026
12027 /* Timeout to animate the expander during expands and collapses */
12028 static gboolean
12029 expand_collapse_timeout (gpointer data)
12030 {
12031   return do_expand_collapse (data);
12032 }
12033
12034 static void
12035 add_expand_collapse_timeout (GtkTreeView *tree_view,
12036                              GtkRBTree   *tree,
12037                              GtkRBNode   *node,
12038                              gboolean     expand)
12039 {
12040   if (tree_view->priv->expand_collapse_timeout != 0)
12041     return;
12042
12043   tree_view->priv->expand_collapse_timeout =
12044       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
12045   tree_view->priv->expanded_collapsed_tree = tree;
12046   tree_view->priv->expanded_collapsed_node = node;
12047
12048   if (expand)
12049     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12050   else
12051     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12052 }
12053
12054 static void
12055 remove_expand_collapse_timeout (GtkTreeView *tree_view)
12056 {
12057   if (tree_view->priv->expand_collapse_timeout)
12058     {
12059       g_source_remove (tree_view->priv->expand_collapse_timeout);
12060       tree_view->priv->expand_collapse_timeout = 0;
12061     }
12062
12063   if (tree_view->priv->expanded_collapsed_node != NULL)
12064     {
12065       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
12066       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12067
12068       tree_view->priv->expanded_collapsed_node = NULL;
12069     }
12070 }
12071
12072 static void
12073 cancel_arrow_animation (GtkTreeView *tree_view)
12074 {
12075   if (tree_view->priv->expand_collapse_timeout)
12076     {
12077       while (do_expand_collapse (tree_view));
12078
12079       remove_expand_collapse_timeout (tree_view);
12080     }
12081 }
12082
12083 static gboolean
12084 do_expand_collapse (GtkTreeView *tree_view)
12085 {
12086   GtkRBNode *node;
12087   GtkRBTree *tree;
12088   gboolean expanding;
12089   gboolean redraw;
12090
12091   redraw = FALSE;
12092   expanding = TRUE;
12093
12094   node = tree_view->priv->expanded_collapsed_node;
12095   tree = tree_view->priv->expanded_collapsed_tree;
12096
12097   if (node->children == NULL)
12098     expanding = FALSE;
12099
12100   if (expanding)
12101     {
12102       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12103         {
12104           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12105           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12106
12107           redraw = TRUE;
12108
12109         }
12110       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12111         {
12112           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12113
12114           redraw = TRUE;
12115         }
12116     }
12117   else
12118     {
12119       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
12120         {
12121           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12122           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12123
12124           redraw = TRUE;
12125         }
12126       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12127         {
12128           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12129
12130           redraw = TRUE;
12131
12132         }
12133     }
12134
12135   if (redraw)
12136     {
12137       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
12138
12139       return TRUE;
12140     }
12141
12142   return FALSE;
12143 }
12144
12145 /**
12146  * gtk_tree_view_collapse_all:
12147  * @tree_view: A #GtkTreeView.
12148  *
12149  * Recursively collapses all visible, expanded nodes in @tree_view.
12150  **/
12151 void
12152 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12153 {
12154   GtkRBTree *tree;
12155   GtkRBNode *node;
12156   GtkTreePath *path;
12157   gint *indices;
12158
12159   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12160
12161   if (tree_view->priv->tree == NULL)
12162     return;
12163
12164   path = gtk_tree_path_new ();
12165   gtk_tree_path_down (path);
12166   indices = gtk_tree_path_get_indices (path);
12167
12168   tree = tree_view->priv->tree;
12169   node = tree->root;
12170   while (node && node->left != tree->nil)
12171     node = node->left;
12172
12173   while (node)
12174     {
12175       if (node->children)
12176         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12177       indices[0]++;
12178       node = _gtk_rbtree_next (tree, node);
12179     }
12180
12181   gtk_tree_path_free (path);
12182 }
12183
12184 /**
12185  * gtk_tree_view_expand_to_path:
12186  * @tree_view: A #GtkTreeView.
12187  * @path: path to a row.
12188  *
12189  * Expands the row at @path. This will also expand all parent rows of
12190  * @path as necessary.
12191  *
12192  * Since: 2.2
12193  **/
12194 void
12195 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12196                               GtkTreePath *path)
12197 {
12198   gint i, depth;
12199   gint *indices;
12200   GtkTreePath *tmp;
12201
12202   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12203   g_return_if_fail (path != NULL);
12204
12205   depth = gtk_tree_path_get_depth (path);
12206   indices = gtk_tree_path_get_indices (path);
12207
12208   tmp = gtk_tree_path_new ();
12209   g_return_if_fail (tmp != NULL);
12210
12211   for (i = 0; i < depth; i++)
12212     {
12213       gtk_tree_path_append_index (tmp, indices[i]);
12214       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12215     }
12216
12217   gtk_tree_path_free (tmp);
12218 }
12219
12220 /* FIXME the bool return values for expand_row and collapse_row are
12221  * not analagous; they should be TRUE if the row had children and
12222  * was not already in the requested state.
12223  */
12224
12225
12226 static gboolean
12227 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12228                                GtkTreePath *path,
12229                                GtkRBTree   *tree,
12230                                GtkRBNode   *node,
12231                                gboolean     open_all,
12232                                gboolean     animate)
12233 {
12234   GtkTreeIter iter;
12235   GtkTreeIter temp;
12236   gboolean expand;
12237
12238   if (animate)
12239     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12240                   "gtk-enable-animations", &animate,
12241                   NULL);
12242
12243   remove_auto_expand_timeout (tree_view);
12244
12245   if (node->children && !open_all)
12246     return FALSE;
12247
12248   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12249     return FALSE;
12250
12251   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12252   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12253     return FALSE;
12254
12255
12256    if (node->children && open_all)
12257     {
12258       gboolean retval = FALSE;
12259       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12260
12261       gtk_tree_path_append_index (tmp_path, 0);
12262       tree = node->children;
12263       node = tree->root;
12264       while (node->left != tree->nil)
12265         node = node->left;
12266       /* try to expand the children */
12267       do
12268         {
12269          gboolean t;
12270          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12271                                             TRUE, animate);
12272          if (t)
12273            retval = TRUE;
12274
12275          gtk_tree_path_next (tmp_path);
12276          node = _gtk_rbtree_next (tree, node);
12277        }
12278       while (node != NULL);
12279
12280       gtk_tree_path_free (tmp_path);
12281
12282       return retval;
12283     }
12284
12285   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12286
12287   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12288     return FALSE;
12289
12290   if (expand)
12291     return FALSE;
12292
12293   node->children = _gtk_rbtree_new ();
12294   node->children->parent_tree = tree;
12295   node->children->parent_node = node;
12296
12297   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12298
12299   gtk_tree_view_build_tree (tree_view,
12300                             node->children,
12301                             &temp,
12302                             gtk_tree_path_get_depth (path) + 1,
12303                             open_all);
12304
12305   remove_expand_collapse_timeout (tree_view);
12306
12307   if (animate)
12308     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12309
12310   install_presize_handler (tree_view);
12311
12312   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12313   if (open_all && node->children)
12314     {
12315       _gtk_rbtree_traverse (node->children,
12316                             node->children->root,
12317                             G_PRE_ORDER,
12318                             gtk_tree_view_expand_all_emission_helper,
12319                             tree_view);
12320     }
12321   return TRUE;
12322 }
12323
12324
12325 /**
12326  * gtk_tree_view_expand_row:
12327  * @tree_view: a #GtkTreeView
12328  * @path: path to a row
12329  * @open_all: whether to recursively expand, or just expand immediate children
12330  *
12331  * Opens the row so its children are visible.
12332  *
12333  * Return value: %TRUE if the row existed and had children
12334  **/
12335 gboolean
12336 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12337                           GtkTreePath *path,
12338                           gboolean     open_all)
12339 {
12340   GtkRBTree *tree;
12341   GtkRBNode *node;
12342
12343   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12344   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12345   g_return_val_if_fail (path != NULL, FALSE);
12346
12347   if (_gtk_tree_view_find_node (tree_view,
12348                                 path,
12349                                 &tree,
12350                                 &node))
12351     return FALSE;
12352
12353   if (tree != NULL)
12354     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12355   else
12356     return FALSE;
12357 }
12358
12359 static gboolean
12360 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12361                                  GtkTreePath *path,
12362                                  GtkRBTree   *tree,
12363                                  GtkRBNode   *node,
12364                                  gboolean     animate)
12365 {
12366   GtkTreeIter iter;
12367   GtkTreeIter children;
12368   gboolean collapse;
12369   gint x, y;
12370   GList *list;
12371   GdkWindow *child, *parent;
12372
12373   if (animate)
12374     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12375                   "gtk-enable-animations", &animate,
12376                   NULL);
12377
12378   remove_auto_expand_timeout (tree_view);
12379
12380   if (node->children == NULL)
12381     return FALSE;
12382
12383   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12384
12385   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12386
12387   if (collapse)
12388     return FALSE;
12389
12390   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12391    * a chance to prelight the correct node below */
12392
12393   if (tree_view->priv->prelight_tree)
12394     {
12395       GtkRBTree *parent_tree;
12396       GtkRBNode *parent_node;
12397
12398       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12399       parent_node = tree_view->priv->prelight_tree->parent_node;
12400       while (parent_tree)
12401         {
12402           if (parent_tree == tree && parent_node == node)
12403             {
12404               ensure_unprelighted (tree_view);
12405               break;
12406             }
12407           parent_node = parent_tree->parent_node;
12408           parent_tree = parent_tree->parent_tree;
12409         }
12410     }
12411
12412   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12413
12414   for (list = tree_view->priv->columns; list; list = list->next)
12415     {
12416       GtkTreeViewColumn *column = list->data;
12417
12418       if (gtk_tree_view_column_get_visible (column) == FALSE)
12419         continue;
12420       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12421         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12422     }
12423
12424   if (tree_view->priv->destroy_count_func)
12425     {
12426       GtkTreePath *child_path;
12427       gint child_count = 0;
12428       child_path = gtk_tree_path_copy (path);
12429       gtk_tree_path_down (child_path);
12430       if (node->children)
12431         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12432       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12433       gtk_tree_path_free (child_path);
12434     }
12435
12436   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12437     {
12438       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12439
12440       if (gtk_tree_path_is_ancestor (path, cursor_path))
12441         {
12442           gtk_tree_row_reference_free (tree_view->priv->cursor);
12443           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12444                                                                       tree_view->priv->model,
12445                                                                       path);
12446         }
12447       gtk_tree_path_free (cursor_path);
12448     }
12449
12450   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12451     {
12452       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12453       if (gtk_tree_path_is_ancestor (path, anchor_path))
12454         {
12455           gtk_tree_row_reference_free (tree_view->priv->anchor);
12456           tree_view->priv->anchor = NULL;
12457         }
12458       gtk_tree_path_free (anchor_path);
12459     }
12460
12461   /* Stop a pending double click */
12462   tree_view->priv->last_button_x = -1;
12463   tree_view->priv->last_button_y = -1;
12464
12465   remove_expand_collapse_timeout (tree_view);
12466
12467   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12468     {
12469       _gtk_rbtree_remove (node->children);
12470       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12471     }
12472   else
12473     _gtk_rbtree_remove (node->children);
12474   
12475   if (animate)
12476     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12477   
12478   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12479     {
12480       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12481     }
12482
12483   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12484
12485   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12486     {
12487       /* now that we've collapsed all rows, we want to try to set the prelight
12488        * again. To do this, we fake a motion event and send it to ourselves. */
12489
12490       child = tree_view->priv->bin_window;
12491       parent = gdk_window_get_parent (child);
12492
12493       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12494         {
12495           GdkEventMotion event;
12496           gint child_x, child_y;
12497
12498           gdk_window_get_position (child, &child_x, &child_y);
12499
12500           event.window = tree_view->priv->bin_window;
12501           event.x = x - child_x;
12502           event.y = y - child_y;
12503
12504           /* despite the fact this isn't a real event, I'm almost positive it will
12505            * never trigger a drag event.  maybe_drag is the only function that uses
12506            * more than just event.x and event.y. */
12507           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12508         }
12509     }
12510
12511   return TRUE;
12512 }
12513
12514 /**
12515  * gtk_tree_view_collapse_row:
12516  * @tree_view: a #GtkTreeView
12517  * @path: path to a row in the @tree_view
12518  *
12519  * Collapses a row (hides its child rows, if they exist).
12520  *
12521  * Return value: %TRUE if the row was collapsed.
12522  **/
12523 gboolean
12524 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12525                             GtkTreePath *path)
12526 {
12527   GtkRBTree *tree;
12528   GtkRBNode *node;
12529
12530   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12531   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12532   g_return_val_if_fail (path != NULL, FALSE);
12533
12534   if (_gtk_tree_view_find_node (tree_view,
12535                                 path,
12536                                 &tree,
12537                                 &node))
12538     return FALSE;
12539
12540   if (tree == NULL || node->children == NULL)
12541     return FALSE;
12542
12543   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12544 }
12545
12546 static void
12547 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12548                                         GtkRBTree              *tree,
12549                                         GtkTreePath            *path,
12550                                         GtkTreeViewMappingFunc  func,
12551                                         gpointer                user_data)
12552 {
12553   GtkRBNode *node;
12554
12555   if (tree == NULL || tree->root == NULL)
12556     return;
12557
12558   node = tree->root;
12559
12560   while (node && node->left != tree->nil)
12561     node = node->left;
12562
12563   while (node)
12564     {
12565       if (node->children)
12566         {
12567           (* func) (tree_view, path, user_data);
12568           gtk_tree_path_down (path);
12569           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12570           gtk_tree_path_up (path);
12571         }
12572       gtk_tree_path_next (path);
12573       node = _gtk_rbtree_next (tree, node);
12574     }
12575 }
12576
12577 /**
12578  * gtk_tree_view_map_expanded_rows:
12579  * @tree_view: A #GtkTreeView
12580  * @func: (scope call): A function to be called
12581  * @data: User data to be passed to the function.
12582  *
12583  * Calls @func on all expanded rows.
12584  **/
12585 void
12586 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12587                                  GtkTreeViewMappingFunc  func,
12588                                  gpointer                user_data)
12589 {
12590   GtkTreePath *path;
12591
12592   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12593   g_return_if_fail (func != NULL);
12594
12595   path = gtk_tree_path_new_first ();
12596
12597   gtk_tree_view_map_expanded_rows_helper (tree_view,
12598                                           tree_view->priv->tree,
12599                                           path, func, user_data);
12600
12601   gtk_tree_path_free (path);
12602 }
12603
12604 /**
12605  * gtk_tree_view_row_expanded:
12606  * @tree_view: A #GtkTreeView.
12607  * @path: A #GtkTreePath to test expansion state.
12608  *
12609  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12610  *
12611  * Return value: %TRUE if #path is expanded.
12612  **/
12613 gboolean
12614 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12615                             GtkTreePath *path)
12616 {
12617   GtkRBTree *tree;
12618   GtkRBNode *node;
12619
12620   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12621   g_return_val_if_fail (path != NULL, FALSE);
12622
12623   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12624
12625   if (node == NULL)
12626     return FALSE;
12627
12628   return (node->children != NULL);
12629 }
12630
12631 /**
12632  * gtk_tree_view_get_reorderable:
12633  * @tree_view: a #GtkTreeView
12634  *
12635  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12636  * gtk_tree_view_set_reorderable().
12637  *
12638  * Return value: %TRUE if the tree can be reordered.
12639  **/
12640 gboolean
12641 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12642 {
12643   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12644
12645   return tree_view->priv->reorderable;
12646 }
12647
12648 /**
12649  * gtk_tree_view_set_reorderable:
12650  * @tree_view: A #GtkTreeView.
12651  * @reorderable: %TRUE, if the tree can be reordered.
12652  *
12653  * This function is a convenience function to allow you to reorder
12654  * models that support the #GtkDragSourceIface and the
12655  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12656  * these.  If @reorderable is %TRUE, then the user can reorder the
12657  * model by dragging and dropping rows. The developer can listen to
12658  * these changes by connecting to the model's row_inserted and
12659  * row_deleted signals. The reordering is implemented by setting up
12660  * the tree view as a drag source and destination. Therefore, drag and
12661  * drop can not be used in a reorderable view for any other purpose.
12662  *
12663  * This function does not give you any degree of control over the order -- any
12664  * reordering is allowed.  If more control is needed, you should probably
12665  * handle drag and drop manually.
12666  **/
12667 void
12668 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12669                                gboolean     reorderable)
12670 {
12671   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12672
12673   reorderable = reorderable != FALSE;
12674
12675   if (tree_view->priv->reorderable == reorderable)
12676     return;
12677
12678   if (reorderable)
12679     {
12680       const GtkTargetEntry row_targets[] = {
12681         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12682       };
12683
12684       gtk_tree_view_enable_model_drag_source (tree_view,
12685                                               GDK_BUTTON1_MASK,
12686                                               row_targets,
12687                                               G_N_ELEMENTS (row_targets),
12688                                               GDK_ACTION_MOVE);
12689       gtk_tree_view_enable_model_drag_dest (tree_view,
12690                                             row_targets,
12691                                             G_N_ELEMENTS (row_targets),
12692                                             GDK_ACTION_MOVE);
12693     }
12694   else
12695     {
12696       gtk_tree_view_unset_rows_drag_source (tree_view);
12697       gtk_tree_view_unset_rows_drag_dest (tree_view);
12698     }
12699
12700   tree_view->priv->reorderable = reorderable;
12701
12702   g_object_notify (G_OBJECT (tree_view), "reorderable");
12703 }
12704
12705 static void
12706 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12707                                GtkTreePath     *path,
12708                                gboolean         clear_and_select,
12709                                gboolean         clamp_node)
12710 {
12711   GtkRBTree *tree = NULL;
12712   GtkRBNode *node = NULL;
12713
12714   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12715     {
12716       GtkTreePath *cursor_path;
12717       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12718       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12719       gtk_tree_path_free (cursor_path);
12720     }
12721
12722   gtk_tree_row_reference_free (tree_view->priv->cursor);
12723   tree_view->priv->cursor = NULL;
12724
12725   /* One cannot set the cursor on a separator.   Also, if
12726    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12727    * before finding the tree and node belonging to path.  The
12728    * path maps to a non-existing path and we will silently bail out.
12729    * We unset tree and node to avoid further processing.
12730    */
12731   if (!row_is_separator (tree_view, NULL, path)
12732       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12733     {
12734       tree_view->priv->cursor =
12735           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12736                                             tree_view->priv->model,
12737                                             path);
12738     }
12739   else
12740     {
12741       tree = NULL;
12742       node = NULL;
12743     }
12744
12745   if (tree != NULL)
12746     {
12747       GtkRBTree *new_tree = NULL;
12748       GtkRBNode *new_node = NULL;
12749
12750       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12751         {
12752           GtkTreeSelectMode mode = 0;
12753
12754           if (tree_view->priv->ctrl_pressed)
12755             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12756           if (tree_view->priv->shift_pressed)
12757             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12758
12759           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12760                                                     node, tree, path, mode,
12761                                                     FALSE);
12762         }
12763
12764       /* We have to re-find tree and node here again, somebody might have
12765        * cleared the node or the whole tree in the GtkTreeSelection::changed
12766        * callback. If the nodes differ we bail out here.
12767        */
12768       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12769
12770       if (tree != new_tree || node != new_node)
12771         return;
12772
12773       if (clamp_node)
12774         {
12775           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12776           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12777         }
12778     }
12779
12780   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12781 }
12782
12783 /**
12784  * gtk_tree_view_get_cursor:
12785  * @tree_view: A #GtkTreeView
12786  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
12787  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
12788  *
12789  * Fills in @path and @focus_column with the current path and focus column.  If
12790  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12791  * currently has focus, then *@focus_column will be %NULL.
12792  *
12793  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12794  * you are done with it.
12795  **/
12796 void
12797 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12798                           GtkTreePath       **path,
12799                           GtkTreeViewColumn **focus_column)
12800 {
12801   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12802
12803   if (path)
12804     {
12805       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12806         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12807       else
12808         *path = NULL;
12809     }
12810
12811   if (focus_column)
12812     {
12813       *focus_column = tree_view->priv->focus_column;
12814     }
12815 }
12816
12817 /**
12818  * gtk_tree_view_set_cursor:
12819  * @tree_view: A #GtkTreeView
12820  * @path: A #GtkTreePath
12821  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12822  * @start_editing: %TRUE if the specified cell should start being edited.
12823  *
12824  * Sets the current keyboard focus to be at @path, and selects it.  This is
12825  * useful when you want to focus the user's attention on a particular row.  If
12826  * @focus_column is not %NULL, then focus is given to the column specified by 
12827  * it. Additionally, if @focus_column is specified, and @start_editing is 
12828  * %TRUE, then editing should be started in the specified cell.  
12829  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12830  * in order to give keyboard focus to the widget.  Please note that editing 
12831  * can only happen when the widget is realized.
12832  *
12833  * If @path is invalid for @model, the current cursor (if any) will be unset
12834  * and the function will return without failing.
12835  **/
12836 void
12837 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12838                           GtkTreePath       *path,
12839                           GtkTreeViewColumn *focus_column,
12840                           gboolean           start_editing)
12841 {
12842   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12843                                     NULL, start_editing);
12844 }
12845
12846 /**
12847  * gtk_tree_view_set_cursor_on_cell:
12848  * @tree_view: A #GtkTreeView
12849  * @path: A #GtkTreePath
12850  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12851  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12852  * @start_editing: %TRUE if the specified cell should start being edited.
12853  *
12854  * Sets the current keyboard focus to be at @path, and selects it.  This is
12855  * useful when you want to focus the user's attention on a particular row.  If
12856  * @focus_column is not %NULL, then focus is given to the column specified by
12857  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12858  * contains 2 or more editable or activatable cells, then focus is given to
12859  * the cell specified by @focus_cell. Additionally, if @focus_column is
12860  * specified, and @start_editing is %TRUE, then editing should be started in
12861  * the specified cell.  This function is often followed by
12862  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12863  * widget.  Please note that editing can only happen when the widget is
12864  * realized.
12865  *
12866  * If @path is invalid for @model, the current cursor (if any) will be unset
12867  * and the function will return without failing.
12868  *
12869  * Since: 2.2
12870  **/
12871 void
12872 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12873                                   GtkTreePath       *path,
12874                                   GtkTreeViewColumn *focus_column,
12875                                   GtkCellRenderer   *focus_cell,
12876                                   gboolean           start_editing)
12877 {
12878   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12879   g_return_if_fail (path != NULL);
12880   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12881
12882   if (!tree_view->priv->model)
12883     return;
12884
12885   if (focus_cell)
12886     {
12887       g_return_if_fail (focus_column);
12888       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12889     }
12890
12891   /* cancel the current editing, if it exists */
12892   if (tree_view->priv->edited_column &&
12893       tree_view->priv->edited_column->editable_widget)
12894     gtk_tree_view_stop_editing (tree_view, TRUE);
12895
12896   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12897
12898   if (focus_column &&
12899       gtk_tree_view_column_get_visible (focus_column))
12900     {
12901       GList *list;
12902       gboolean column_in_tree = FALSE;
12903
12904       for (list = tree_view->priv->columns; list; list = list->next)
12905         if (list->data == focus_column)
12906           {
12907             column_in_tree = TRUE;
12908             break;
12909           }
12910       g_return_if_fail (column_in_tree);
12911       tree_view->priv->focus_column = focus_column;
12912       if (focus_cell)
12913         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12914       if (start_editing)
12915         gtk_tree_view_start_editing (tree_view, path);
12916     }
12917 }
12918
12919 /**
12920  * gtk_tree_view_get_bin_window:
12921  * @tree_view: A #GtkTreeView
12922  *
12923  * Returns the window that @tree_view renders to.
12924  * This is used primarily to compare to <literal>event->window</literal>
12925  * to confirm that the event on @tree_view is on the right window.
12926  *
12927  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
12928  *     hasn't been realized yet
12929  **/
12930 GdkWindow *
12931 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12932 {
12933   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12934
12935   return tree_view->priv->bin_window;
12936 }
12937
12938 /**
12939  * gtk_tree_view_get_path_at_pos:
12940  * @tree_view: A #GtkTreeView.
12941  * @x: The x position to be identified (relative to bin_window).
12942  * @y: The y position to be identified (relative to bin_window).
12943  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12944  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12945  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
12946  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12947  *
12948  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12949  * (please see gtk_tree_view_get_bin_window()).
12950  * That is, @x and @y are relative to an events coordinates. @x and @y must
12951  * come from an event on the @tree_view only where <literal>event->window ==
12952  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12953  * things like popup menus. If @path is non-%NULL, then it will be filled
12954  * with the #GtkTreePath at that point.  This path should be freed with
12955  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12956  * with the column at that point.  @cell_x and @cell_y return the coordinates
12957  * relative to the cell background (i.e. the @background_area passed to
12958  * gtk_cell_renderer_render()).  This function is only meaningful if
12959  * @tree_view is realized.  Therefore this function will always return %FALSE
12960  * if @tree_view is not realized or does not have a model.
12961  *
12962  * For converting widget coordinates (eg. the ones you get from
12963  * GtkWidget::query-tooltip), please see
12964  * gtk_tree_view_convert_widget_to_bin_window_coords().
12965  *
12966  * Return value: %TRUE if a row exists at that coordinate.
12967  **/
12968 gboolean
12969 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12970                                gint                x,
12971                                gint                y,
12972                                GtkTreePath       **path,
12973                                GtkTreeViewColumn **column,
12974                                gint               *cell_x,
12975                                gint               *cell_y)
12976 {
12977   GtkRBTree *tree;
12978   GtkRBNode *node;
12979   gint y_offset;
12980
12981   g_return_val_if_fail (tree_view != NULL, FALSE);
12982
12983   if (path)
12984     *path = NULL;
12985   if (column)
12986     *column = NULL;
12987
12988   if (tree_view->priv->bin_window == NULL)
12989     return FALSE;
12990
12991   if (tree_view->priv->tree == NULL)
12992     return FALSE;
12993
12994   if (x > tree_view->priv->hadjustment->upper)
12995     return FALSE;
12996
12997   if (x < 0 || y < 0)
12998     return FALSE;
12999
13000   if (column || cell_x)
13001     {
13002       GtkTreeViewColumn *tmp_column;
13003       GtkTreeViewColumn *last_column = NULL;
13004       GList *list;
13005       gint remaining_x = x;
13006       gboolean found = FALSE;
13007       gboolean rtl;
13008       gint width;
13009
13010       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13011       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13012            list;
13013            list = (rtl ? list->prev : list->next))
13014         {
13015           tmp_column = list->data;
13016
13017           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13018             continue;
13019
13020           last_column = tmp_column;
13021           width = gtk_tree_view_column_get_width (tmp_column);
13022           if (remaining_x <= width)
13023             {
13024               found = TRUE;
13025
13026               if (column)
13027                 *column = tmp_column;
13028
13029               if (cell_x)
13030                 *cell_x = remaining_x;
13031
13032               break;
13033             }
13034           remaining_x -= width;
13035         }
13036
13037       /* If found is FALSE and there is a last_column, then it the remainder
13038        * space is in that area
13039        */
13040       if (!found)
13041         {
13042           if (last_column)
13043             {
13044               if (column)
13045                 *column = last_column;
13046               
13047               if (cell_x)
13048                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13049             }
13050           else
13051             {
13052               return FALSE;
13053             }
13054         }
13055     }
13056
13057   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13058                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13059                                       &tree, &node);
13060
13061   if (tree == NULL)
13062     return FALSE;
13063
13064   if (cell_y)
13065     *cell_y = y_offset;
13066
13067   if (path)
13068     *path = _gtk_tree_view_find_path (tree_view, tree, node);
13069
13070   return TRUE;
13071 }
13072
13073
13074 /**
13075  * gtk_tree_view_get_cell_area:
13076  * @tree_view: a #GtkTreeView
13077  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13078  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13079  * @rect: rectangle to fill with cell rect
13080  *
13081  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13082  * row specified by @path and the column specified by @column.  If @path is
13083  * %NULL, or points to a path not currently displayed, the @y and @height fields
13084  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13085  * fields will be filled with 0.  The sum of all cell rects does not cover the
13086  * entire tree; there are extra pixels in between rows, for example. The
13087  * returned rectangle is equivalent to the @cell_area passed to
13088  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13089  * realized.
13090  **/
13091 void
13092 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13093                              GtkTreePath        *path,
13094                              GtkTreeViewColumn  *column,
13095                              GdkRectangle       *rect)
13096 {
13097   GtkAllocation allocation;
13098   GtkRBTree *tree = NULL;
13099   GtkRBNode *node = NULL;
13100   gint vertical_separator;
13101   gint horizontal_separator;
13102
13103   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13104   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13105   g_return_if_fail (rect != NULL);
13106   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
13107   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13108
13109   gtk_widget_style_get (GTK_WIDGET (tree_view),
13110                         "vertical-separator", &vertical_separator,
13111                         "horizontal-separator", &horizontal_separator,
13112                         NULL);
13113
13114   rect->x = 0;
13115   rect->y = 0;
13116   rect->width = 0;
13117   rect->height = 0;
13118
13119   if (column)
13120     {
13121       gtk_widget_get_allocation (column->button, &allocation);
13122       rect->x = allocation.x + horizontal_separator/2;
13123       rect->width = allocation.width - horizontal_separator;
13124     }
13125
13126   if (path)
13127     {
13128       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13129
13130       /* Get vertical coords */
13131       if ((!ret && tree == NULL) || ret)
13132         return;
13133
13134       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
13135       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
13136
13137       if (column &&
13138           gtk_tree_view_is_expander_column (tree_view, column))
13139         {
13140           gint depth = gtk_tree_path_get_depth (path);
13141           gboolean rtl;
13142
13143           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13144
13145           if (!rtl)
13146             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13147           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13148
13149           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
13150             {
13151               if (!rtl)
13152                 rect->x += depth * tree_view->priv->expander_size;
13153               rect->width -= depth * tree_view->priv->expander_size;
13154             }
13155
13156           rect->width = MAX (rect->width, 0);
13157         }
13158     }
13159 }
13160
13161 /**
13162  * gtk_tree_view_get_background_area:
13163  * @tree_view: a #GtkTreeView
13164  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13165  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13166  * @rect: rectangle to fill with cell background rect
13167  *
13168  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13169  * row specified by @path and the column specified by @column.  If @path is
13170  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13171  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13172  * fields will be filled with 0.  The returned rectangle is equivalent to the
13173  * @background_area passed to gtk_cell_renderer_render().  These background
13174  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13175  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13176  * itself, excluding surrounding borders and the tree expander area.
13177  *
13178  **/
13179 void
13180 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13181                                    GtkTreePath        *path,
13182                                    GtkTreeViewColumn  *column,
13183                                    GdkRectangle       *rect)
13184 {
13185   GtkRBTree *tree = NULL;
13186   GtkRBNode *node = NULL;
13187
13188   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13189   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13190   g_return_if_fail (rect != NULL);
13191
13192   rect->x = 0;
13193   rect->y = 0;
13194   rect->width = 0;
13195   rect->height = 0;
13196
13197   if (path)
13198     {
13199       /* Get vertical coords */
13200
13201       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13202           tree == NULL)
13203         return;
13204
13205       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13206
13207       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13208     }
13209
13210   if (column)
13211     {
13212       gint x2 = 0;
13213
13214       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13215       rect->width = x2 - rect->x;
13216     }
13217 }
13218
13219 /**
13220  * gtk_tree_view_get_visible_rect:
13221  * @tree_view: a #GtkTreeView
13222  * @visible_rect: rectangle to fill
13223  *
13224  * Fills @visible_rect with the currently-visible region of the
13225  * buffer, in tree coordinates. Convert to bin_window coordinates with
13226  * gtk_tree_view_convert_tree_to_bin_window_coords().
13227  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13228  * scrollable area of the tree.
13229  **/
13230 void
13231 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13232                                 GdkRectangle *visible_rect)
13233 {
13234   GtkAllocation allocation;
13235   GtkWidget *widget;
13236
13237   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13238
13239   widget = GTK_WIDGET (tree_view);
13240
13241   if (visible_rect)
13242     {
13243       gtk_widget_get_allocation (widget, &allocation);
13244       visible_rect->x = tree_view->priv->hadjustment->value;
13245       visible_rect->y = tree_view->priv->vadjustment->value;
13246       visible_rect->width = allocation.width;
13247       visible_rect->height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13248     }
13249 }
13250
13251 /**
13252  * gtk_tree_view_convert_widget_to_tree_coords:
13253  * @tree_view: a #GtkTreeView
13254  * @wx: X coordinate relative to the widget
13255  * @wy: Y coordinate relative to the widget
13256  * @tx: return location for tree X coordinate
13257  * @ty: return location for tree Y coordinate
13258  *
13259  * Converts widget coordinates to coordinates for the
13260  * tree (the full scrollable area of the tree).
13261  *
13262  * Since: 2.12
13263  **/
13264 void
13265 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13266                                              gint         wx,
13267                                              gint         wy,
13268                                              gint        *tx,
13269                                              gint        *ty)
13270 {
13271   gint x, y;
13272
13273   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13274
13275   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13276                                                      wx, wy,
13277                                                      &x, &y);
13278   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13279                                                    x, y,
13280                                                    tx, ty);
13281 }
13282
13283 /**
13284  * gtk_tree_view_convert_tree_to_widget_coords:
13285  * @tree_view: a #GtkTreeView
13286  * @tx: X coordinate relative to the tree
13287  * @ty: Y coordinate relative to the tree
13288  * @wx: return location for widget X coordinate
13289  * @wy: return location for widget Y coordinate
13290  *
13291  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13292  * to widget coordinates.
13293  *
13294  * Since: 2.12
13295  **/
13296 void
13297 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13298                                              gint         tx,
13299                                              gint         ty,
13300                                              gint        *wx,
13301                                              gint        *wy)
13302 {
13303   gint x, y;
13304
13305   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13306
13307   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13308                                                    tx, ty,
13309                                                    &x, &y);
13310   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13311                                                      x, y,
13312                                                      wx, wy);
13313 }
13314
13315 /**
13316  * gtk_tree_view_convert_widget_to_bin_window_coords:
13317  * @tree_view: a #GtkTreeView
13318  * @wx: X coordinate relative to the widget
13319  * @wy: Y coordinate relative to the widget
13320  * @bx: return location for bin_window X coordinate
13321  * @by: return location for bin_window Y coordinate
13322  *
13323  * Converts widget coordinates to coordinates for the bin_window
13324  * (see gtk_tree_view_get_bin_window()).
13325  *
13326  * Since: 2.12
13327  **/
13328 void
13329 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13330                                                    gint         wx,
13331                                                    gint         wy,
13332                                                    gint        *bx,
13333                                                    gint        *by)
13334 {
13335   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13336
13337   if (bx)
13338     *bx = wx + tree_view->priv->hadjustment->value;
13339   if (by)
13340     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13341 }
13342
13343 /**
13344  * gtk_tree_view_convert_bin_window_to_widget_coords:
13345  * @tree_view: a #GtkTreeView
13346  * @bx: bin_window X coordinate
13347  * @by: bin_window Y coordinate
13348  * @wx: return location for widget X coordinate
13349  * @wy: return location for widget Y coordinate
13350  *
13351  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13352  * to widget relative coordinates.
13353  *
13354  * Since: 2.12
13355  **/
13356 void
13357 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13358                                                    gint         bx,
13359                                                    gint         by,
13360                                                    gint        *wx,
13361                                                    gint        *wy)
13362 {
13363   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13364
13365   if (wx)
13366     *wx = bx - tree_view->priv->hadjustment->value;
13367   if (wy)
13368     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13369 }
13370
13371 /**
13372  * gtk_tree_view_convert_tree_to_bin_window_coords:
13373  * @tree_view: a #GtkTreeView
13374  * @tx: tree X coordinate
13375  * @ty: tree Y coordinate
13376  * @bx: return location for X coordinate relative to bin_window
13377  * @by: return location for Y coordinate relative to bin_window
13378  *
13379  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13380  * to bin_window coordinates.
13381  *
13382  * Since: 2.12
13383  **/
13384 void
13385 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13386                                                  gint         tx,
13387                                                  gint         ty,
13388                                                  gint        *bx,
13389                                                  gint        *by)
13390 {
13391   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13392
13393   if (bx)
13394     *bx = tx;
13395   if (by)
13396     *by = ty - tree_view->priv->dy;
13397 }
13398
13399 /**
13400  * gtk_tree_view_convert_bin_window_to_tree_coords:
13401  * @tree_view: a #GtkTreeView
13402  * @bx: X coordinate relative to bin_window
13403  * @by: Y coordinate relative to bin_window
13404  * @tx: return location for tree X coordinate
13405  * @ty: return location for tree Y coordinate
13406  *
13407  * Converts bin_window coordinates to coordinates for the
13408  * tree (the full scrollable area of the tree).
13409  *
13410  * Since: 2.12
13411  **/
13412 void
13413 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13414                                                  gint         bx,
13415                                                  gint         by,
13416                                                  gint        *tx,
13417                                                  gint        *ty)
13418 {
13419   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13420
13421   if (tx)
13422     *tx = bx;
13423   if (ty)
13424     *ty = by + tree_view->priv->dy;
13425 }
13426
13427
13428
13429 /**
13430  * gtk_tree_view_get_visible_range:
13431  * @tree_view: A #GtkTreeView
13432  * @start_path: (allow-none): Return location for start of region, or %NULL.
13433  * @end_path: (allow-none): Return location for end of region, or %NULL.
13434  *
13435  * Sets @start_path and @end_path to be the first and last visible path.
13436  * Note that there may be invisible paths in between.
13437  *
13438  * The paths should be freed with gtk_tree_path_free() after use.
13439  *
13440  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13441  *
13442  * Since: 2.8
13443  **/
13444 gboolean
13445 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13446                                  GtkTreePath **start_path,
13447                                  GtkTreePath **end_path)
13448 {
13449   GtkRBTree *tree;
13450   GtkRBNode *node;
13451   gboolean retval;
13452   
13453   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13454
13455   if (!tree_view->priv->tree)
13456     return FALSE;
13457
13458   retval = TRUE;
13459
13460   if (start_path)
13461     {
13462       _gtk_rbtree_find_offset (tree_view->priv->tree,
13463                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13464                                &tree, &node);
13465       if (node)
13466         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13467       else
13468         retval = FALSE;
13469     }
13470
13471   if (end_path)
13472     {
13473       gint y;
13474
13475       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13476         y = tree_view->priv->height - 1;
13477       else
13478         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13479
13480       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13481       if (node)
13482         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13483       else
13484         retval = FALSE;
13485     }
13486
13487   return retval;
13488 }
13489
13490 static void
13491 unset_reorderable (GtkTreeView *tree_view)
13492 {
13493   if (tree_view->priv->reorderable)
13494     {
13495       tree_view->priv->reorderable = FALSE;
13496       g_object_notify (G_OBJECT (tree_view), "reorderable");
13497     }
13498 }
13499
13500 /**
13501  * gtk_tree_view_enable_model_drag_source:
13502  * @tree_view: a #GtkTreeView
13503  * @start_button_mask: Mask of allowed buttons to start drag
13504  * @targets: (array): the table of targets that the drag will support
13505  * @n_targets: the number of items in @targets
13506  * @actions: the bitmask of possible actions for a drag from this
13507  *    widget
13508  *
13509  * Turns @tree_view into a drag source for automatic DND. Calling this
13510  * method sets #GtkTreeView:reorderable to %FALSE.
13511  **/
13512 void
13513 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13514                                         GdkModifierType           start_button_mask,
13515                                         const GtkTargetEntry     *targets,
13516                                         gint                      n_targets,
13517                                         GdkDragAction             actions)
13518 {
13519   TreeViewDragInfo *di;
13520
13521   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13522
13523   gtk_drag_source_set (GTK_WIDGET (tree_view),
13524                        0,
13525                        targets,
13526                        n_targets,
13527                        actions);
13528
13529   di = ensure_info (tree_view);
13530
13531   di->start_button_mask = start_button_mask;
13532   di->source_actions = actions;
13533   di->source_set = TRUE;
13534
13535   unset_reorderable (tree_view);
13536 }
13537
13538 /**
13539  * gtk_tree_view_enable_model_drag_dest:
13540  * @tree_view: a #GtkTreeView
13541  * @targets: (array): the table of targets that the drag will support
13542  * @n_targets: the number of items in @targets
13543  * @actions: the bitmask of possible actions for a drag from this
13544  *    widget
13545  * 
13546  * Turns @tree_view into a drop destination for automatic DND. Calling
13547  * this method sets #GtkTreeView:reorderable to %FALSE.
13548  **/
13549 void
13550 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13551                                       const GtkTargetEntry     *targets,
13552                                       gint                      n_targets,
13553                                       GdkDragAction             actions)
13554 {
13555   TreeViewDragInfo *di;
13556
13557   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13558
13559   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13560                      0,
13561                      targets,
13562                      n_targets,
13563                      actions);
13564
13565   di = ensure_info (tree_view);
13566   di->dest_set = TRUE;
13567
13568   unset_reorderable (tree_view);
13569 }
13570
13571 /**
13572  * gtk_tree_view_unset_rows_drag_source:
13573  * @tree_view: a #GtkTreeView
13574  *
13575  * Undoes the effect of
13576  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13577  * #GtkTreeView:reorderable to %FALSE.
13578  **/
13579 void
13580 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13581 {
13582   TreeViewDragInfo *di;
13583
13584   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13585
13586   di = get_info (tree_view);
13587
13588   if (di)
13589     {
13590       if (di->source_set)
13591         {
13592           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13593           di->source_set = FALSE;
13594         }
13595
13596       if (!di->dest_set && !di->source_set)
13597         remove_info (tree_view);
13598     }
13599   
13600   unset_reorderable (tree_view);
13601 }
13602
13603 /**
13604  * gtk_tree_view_unset_rows_drag_dest:
13605  * @tree_view: a #GtkTreeView
13606  *
13607  * Undoes the effect of
13608  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13609  * #GtkTreeView:reorderable to %FALSE.
13610  **/
13611 void
13612 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13613 {
13614   TreeViewDragInfo *di;
13615
13616   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13617
13618   di = get_info (tree_view);
13619
13620   if (di)
13621     {
13622       if (di->dest_set)
13623         {
13624           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13625           di->dest_set = FALSE;
13626         }
13627
13628       if (!di->dest_set && !di->source_set)
13629         remove_info (tree_view);
13630     }
13631
13632   unset_reorderable (tree_view);
13633 }
13634
13635 /**
13636  * gtk_tree_view_set_drag_dest_row:
13637  * @tree_view: a #GtkTreeView
13638  * @path: (allow-none): The path of the row to highlight, or %NULL.
13639  * @pos: Specifies whether to drop before, after or into the row
13640  * 
13641  * Sets the row that is highlighted for feedback.
13642  **/
13643 void
13644 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13645                                  GtkTreePath            *path,
13646                                  GtkTreeViewDropPosition pos)
13647 {
13648   GtkTreePath *current_dest;
13649
13650   /* Note; this function is exported to allow a custom DND
13651    * implementation, so it can't touch TreeViewDragInfo
13652    */
13653
13654   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13655
13656   current_dest = NULL;
13657
13658   if (tree_view->priv->drag_dest_row)
13659     {
13660       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13661       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13662     }
13663
13664   /* special case a drop on an empty model */
13665   tree_view->priv->empty_view_drop = 0;
13666
13667   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13668       && gtk_tree_path_get_depth (path) == 1
13669       && gtk_tree_path_get_indices (path)[0] == 0)
13670     {
13671       gint n_children;
13672
13673       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13674                                                    NULL);
13675
13676       if (!n_children)
13677         tree_view->priv->empty_view_drop = 1;
13678     }
13679
13680   tree_view->priv->drag_dest_pos = pos;
13681
13682   if (path)
13683     {
13684       tree_view->priv->drag_dest_row =
13685         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13686       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13687     }
13688   else
13689     tree_view->priv->drag_dest_row = NULL;
13690
13691   if (current_dest)
13692     {
13693       GtkRBTree *tree, *new_tree;
13694       GtkRBNode *node, *new_node;
13695
13696       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13697       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13698
13699       if (tree && node)
13700         {
13701           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13702           if (new_tree && new_node)
13703             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13704
13705           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13706           if (new_tree && new_node)
13707             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13708         }
13709       gtk_tree_path_free (current_dest);
13710     }
13711 }
13712
13713 /**
13714  * gtk_tree_view_get_drag_dest_row:
13715  * @tree_view: a #GtkTreeView
13716  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13717  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13718  * 
13719  * Gets information about the row that is highlighted for feedback.
13720  **/
13721 void
13722 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13723                                  GtkTreePath             **path,
13724                                  GtkTreeViewDropPosition  *pos)
13725 {
13726   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13727
13728   if (path)
13729     {
13730       if (tree_view->priv->drag_dest_row)
13731         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13732       else
13733         {
13734           if (tree_view->priv->empty_view_drop)
13735             *path = gtk_tree_path_new_from_indices (0, -1);
13736           else
13737             *path = NULL;
13738         }
13739     }
13740
13741   if (pos)
13742     *pos = tree_view->priv->drag_dest_pos;
13743 }
13744
13745 /**
13746  * gtk_tree_view_get_dest_row_at_pos:
13747  * @tree_view: a #GtkTreeView
13748  * @drag_x: the position to determine the destination row for
13749  * @drag_y: the position to determine the destination row for
13750  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13751  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13752  * 
13753  * Determines the destination row for a given position.  @drag_x and
13754  * @drag_y are expected to be in widget coordinates.  This function is only
13755  * meaningful if @tree_view is realized.  Therefore this function will always
13756  * return %FALSE if @tree_view is not realized or does not have a model.
13757  * 
13758  * Return value: whether there is a row at the given position, %TRUE if this
13759  * is indeed the case.
13760  **/
13761 gboolean
13762 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13763                                    gint                     drag_x,
13764                                    gint                     drag_y,
13765                                    GtkTreePath            **path,
13766                                    GtkTreeViewDropPosition *pos)
13767 {
13768   gint cell_y;
13769   gint bin_x, bin_y;
13770   gdouble offset_into_row;
13771   gdouble third;
13772   GdkRectangle cell;
13773   GtkTreeViewColumn *column = NULL;
13774   GtkTreePath *tmp_path = NULL;
13775
13776   /* Note; this function is exported to allow a custom DND
13777    * implementation, so it can't touch TreeViewDragInfo
13778    */
13779
13780   g_return_val_if_fail (tree_view != NULL, FALSE);
13781   g_return_val_if_fail (drag_x >= 0, FALSE);
13782   g_return_val_if_fail (drag_y >= 0, FALSE);
13783
13784   if (path)
13785     *path = NULL;
13786
13787   if (tree_view->priv->bin_window == NULL)
13788     return FALSE;
13789
13790   if (tree_view->priv->tree == NULL)
13791     return FALSE;
13792
13793   /* If in the top third of a row, we drop before that row; if
13794    * in the bottom third, drop after that row; if in the middle,
13795    * and the row has children, drop into the row.
13796    */
13797   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13798                                                      &bin_x, &bin_y);
13799
13800   if (!gtk_tree_view_get_path_at_pos (tree_view,
13801                                       bin_x,
13802                                       bin_y,
13803                                       &tmp_path,
13804                                       &column,
13805                                       NULL,
13806                                       &cell_y))
13807     return FALSE;
13808
13809   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13810                                      &cell);
13811
13812   offset_into_row = cell_y;
13813
13814   if (path)
13815     *path = tmp_path;
13816   else
13817     gtk_tree_path_free (tmp_path);
13818
13819   tmp_path = NULL;
13820
13821   third = cell.height / 3.0;
13822
13823   if (pos)
13824     {
13825       if (offset_into_row < third)
13826         {
13827           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13828         }
13829       else if (offset_into_row < (cell.height / 2.0))
13830         {
13831           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13832         }
13833       else if (offset_into_row < third * 2.0)
13834         {
13835           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13836         }
13837       else
13838         {
13839           *pos = GTK_TREE_VIEW_DROP_AFTER;
13840         }
13841     }
13842
13843   return TRUE;
13844 }
13845
13846
13847
13848 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13849 /**
13850  * gtk_tree_view_create_row_drag_icon:
13851  * @tree_view: a #GtkTreeView
13852  * @path: a #GtkTreePath in @tree_view
13853  *
13854  * Creates a #cairo_surface_t representation of the row at @path.  
13855  * This image is used for a drag icon.
13856  *
13857  * Return value: (transfer full): a newly-allocated surface of the drag icon.
13858  **/
13859 cairo_surface_t *
13860 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13861                                     GtkTreePath  *path)
13862 {
13863   GtkTreeIter   iter;
13864   GtkRBTree    *tree;
13865   GtkRBNode    *node;
13866   GtkStyle *style;
13867   gint cell_offset;
13868   GList *list;
13869   GdkRectangle background_area;
13870   GtkWidget *widget;
13871   gint depth;
13872   /* start drawing inside the black outline */
13873   gint x = 1, y = 1;
13874   cairo_surface_t *surface;
13875   gint bin_window_width;
13876   gboolean is_separator = FALSE;
13877   gboolean rtl;
13878   cairo_t *cr;
13879
13880   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13881   g_return_val_if_fail (path != NULL, NULL);
13882
13883   widget = GTK_WIDGET (tree_view);
13884
13885   if (!gtk_widget_get_realized (widget))
13886     return NULL;
13887
13888   depth = gtk_tree_path_get_depth (path);
13889
13890   _gtk_tree_view_find_node (tree_view,
13891                             path,
13892                             &tree,
13893                             &node);
13894
13895   if (tree == NULL)
13896     return NULL;
13897
13898   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13899                                 &iter,
13900                                 path))
13901     return NULL;
13902
13903   style = gtk_widget_get_style (widget);
13904
13905   is_separator = row_is_separator (tree_view, &iter, NULL);
13906
13907   cell_offset = x;
13908
13909   background_area.y = y;
13910   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13911
13912   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
13913
13914   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
13915                                                CAIRO_CONTENT_COLOR,
13916                                                bin_window_width + 2,
13917                                                background_area.height + 2);
13918
13919   cr = cairo_create (surface);
13920   gdk_cairo_set_source_color (cr, &style->base [gtk_widget_get_state (widget)]);
13921   cairo_paint (cr);
13922
13923   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13924
13925   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13926       list;
13927       list = (rtl ? list->prev : list->next))
13928     {
13929       GtkTreeViewColumn *column = list->data;
13930       GdkRectangle cell_area;
13931       gint vertical_separator;
13932
13933       if (!gtk_tree_view_column_get_visible (column))
13934         continue;
13935
13936       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13937                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13938                                                node->children?TRUE:FALSE);
13939
13940       background_area.x = cell_offset;
13941       background_area.width = gtk_tree_view_column_get_width (column);
13942
13943       gtk_widget_style_get (widget,
13944                             "vertical-separator", &vertical_separator,
13945                             NULL);
13946
13947       cell_area = background_area;
13948
13949       cell_area.y += vertical_separator / 2;
13950       cell_area.height -= vertical_separator;
13951
13952       if (gtk_tree_view_is_expander_column (tree_view, column))
13953         {
13954           if (!rtl)
13955             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13956           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13957
13958           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13959             {
13960               if (!rtl)
13961                 cell_area.x += depth * tree_view->priv->expander_size;
13962               cell_area.width -= depth * tree_view->priv->expander_size;
13963             }
13964         }
13965
13966       if (gtk_tree_view_column_cell_is_visible (column))
13967         {
13968           if (is_separator)
13969             gtk_paint_hline (style,
13970                                    cr,
13971                                    GTK_STATE_NORMAL,
13972                                    widget,
13973                                    NULL,
13974                                    cell_area.x,
13975                                    cell_area.x + cell_area.width,
13976                                    cell_area.y + cell_area.height / 2);
13977           else
13978             _gtk_tree_view_column_cell_render (column,
13979                                                cr,
13980                                                &background_area,
13981                                                &cell_area,
13982                                                0);
13983         }
13984       cell_offset += gtk_tree_view_column_get_width (column);
13985     }
13986
13987   cairo_set_source_rgb (cr, 0, 0, 0);
13988   cairo_rectangle (cr, 
13989                    0.5, 0.5, 
13990                    bin_window_width + 1,
13991                    background_area.height + 1);
13992   cairo_set_line_width (cr, 1.0);
13993   cairo_stroke (cr);
13994
13995   cairo_destroy (cr);
13996
13997   cairo_surface_set_device_offset (surface, 2, 2);
13998
13999   return surface;
14000 }
14001
14002
14003 /**
14004  * gtk_tree_view_set_destroy_count_func:
14005  * @tree_view: A #GtkTreeView
14006  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14007  * @data: (allow-none): User data to be passed to @func, or %NULL
14008  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14009  *
14010  * This function should almost never be used.  It is meant for private use by
14011  * ATK for determining the number of visible children that are removed when the
14012  * user collapses a row, or a row is deleted.
14013  **/
14014 void
14015 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14016                                       GtkTreeDestroyCountFunc  func,
14017                                       gpointer                 data,
14018                                       GDestroyNotify           destroy)
14019 {
14020   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14021
14022   if (tree_view->priv->destroy_count_destroy)
14023     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14024
14025   tree_view->priv->destroy_count_func = func;
14026   tree_view->priv->destroy_count_data = data;
14027   tree_view->priv->destroy_count_destroy = destroy;
14028 }
14029
14030
14031 /*
14032  * Interactive search
14033  */
14034
14035 /**
14036  * gtk_tree_view_set_enable_search:
14037  * @tree_view: A #GtkTreeView
14038  * @enable_search: %TRUE, if the user can search interactively
14039  *
14040  * If @enable_search is set, then the user can type in text to search through
14041  * the tree interactively (this is sometimes called "typeahead find").
14042  * 
14043  * Note that even if this is %FALSE, the user can still initiate a search 
14044  * using the "start-interactive-search" key binding.
14045  */
14046 void
14047 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14048                                  gboolean     enable_search)
14049 {
14050   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14051
14052   enable_search = !!enable_search;
14053   
14054   if (tree_view->priv->enable_search != enable_search)
14055     {
14056        tree_view->priv->enable_search = enable_search;
14057        g_object_notify (G_OBJECT (tree_view), "enable-search");
14058     }
14059 }
14060
14061 /**
14062  * gtk_tree_view_get_enable_search:
14063  * @tree_view: A #GtkTreeView
14064  *
14065  * Returns whether or not the tree allows to start interactive searching 
14066  * by typing in text.
14067  *
14068  * Return value: whether or not to let the user search interactively
14069  */
14070 gboolean
14071 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14072 {
14073   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14074
14075   return tree_view->priv->enable_search;
14076 }
14077
14078
14079 /**
14080  * gtk_tree_view_get_search_column:
14081  * @tree_view: A #GtkTreeView
14082  *
14083  * Gets the column searched on by the interactive search code.
14084  *
14085  * Return value: the column the interactive search code searches in.
14086  */
14087 gint
14088 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14089 {
14090   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14091
14092   return (tree_view->priv->search_column);
14093 }
14094
14095 /**
14096  * gtk_tree_view_set_search_column:
14097  * @tree_view: A #GtkTreeView
14098  * @column: the column of the model to search in, or -1 to disable searching
14099  *
14100  * Sets @column as the column where the interactive search code should
14101  * search in for the current model. 
14102  * 
14103  * If the search column is set, users can use the "start-interactive-search"
14104  * key binding to bring up search popup. The enable-search property controls
14105  * whether simply typing text will also start an interactive search.
14106  *
14107  * Note that @column refers to a column of the current model. The search 
14108  * column is reset to -1 when the model is changed.
14109  */
14110 void
14111 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14112                                  gint         column)
14113 {
14114   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14115   g_return_if_fail (column >= -1);
14116
14117   if (tree_view->priv->search_column == column)
14118     return;
14119
14120   tree_view->priv->search_column = column;
14121   g_object_notify (G_OBJECT (tree_view), "search-column");
14122 }
14123
14124 /**
14125  * gtk_tree_view_get_search_equal_func:
14126  * @tree_view: A #GtkTreeView
14127  *
14128  * Returns the compare function currently in use.
14129  *
14130  * Return value: the currently used compare function for the search code.
14131  */
14132
14133 GtkTreeViewSearchEqualFunc
14134 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14135 {
14136   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14137
14138   return tree_view->priv->search_equal_func;
14139 }
14140
14141 /**
14142  * gtk_tree_view_set_search_equal_func:
14143  * @tree_view: A #GtkTreeView
14144  * @search_equal_func: the compare function to use during the search
14145  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14146  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14147  *
14148  * Sets the compare function for the interactive search capabilities; note
14149  * that somewhat like strcmp() returning 0 for equality
14150  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14151  **/
14152 void
14153 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14154                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14155                                      gpointer                    search_user_data,
14156                                      GDestroyNotify              search_destroy)
14157 {
14158   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14159   g_return_if_fail (search_equal_func != NULL);
14160
14161   if (tree_view->priv->search_destroy)
14162     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14163
14164   tree_view->priv->search_equal_func = search_equal_func;
14165   tree_view->priv->search_user_data = search_user_data;
14166   tree_view->priv->search_destroy = search_destroy;
14167   if (tree_view->priv->search_equal_func == NULL)
14168     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14169 }
14170
14171 /**
14172  * gtk_tree_view_get_search_entry:
14173  * @tree_view: A #GtkTreeView
14174  *
14175  * Returns the #GtkEntry which is currently in use as interactive search
14176  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14177  * will be returned.
14178  *
14179  * Return value: (transfer none): the entry currently in use as search entry.
14180  *
14181  * Since: 2.10
14182  */
14183 GtkEntry *
14184 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14185 {
14186   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14187
14188   if (tree_view->priv->search_custom_entry_set)
14189     return GTK_ENTRY (tree_view->priv->search_entry);
14190
14191   return NULL;
14192 }
14193
14194 /**
14195  * gtk_tree_view_set_search_entry:
14196  * @tree_view: A #GtkTreeView
14197  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14198  *
14199  * Sets the entry which the interactive search code will use for this
14200  * @tree_view.  This is useful when you want to provide a search entry
14201  * in our interface at all time at a fixed position.  Passing %NULL for
14202  * @entry will make the interactive search code use the built-in popup
14203  * entry again.
14204  *
14205  * Since: 2.10
14206  */
14207 void
14208 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14209                                 GtkEntry    *entry)
14210 {
14211   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14212   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14213
14214   if (tree_view->priv->search_custom_entry_set)
14215     {
14216       if (tree_view->priv->search_entry_changed_id)
14217         {
14218           g_signal_handler_disconnect (tree_view->priv->search_entry,
14219                                        tree_view->priv->search_entry_changed_id);
14220           tree_view->priv->search_entry_changed_id = 0;
14221         }
14222       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14223                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14224                                             tree_view);
14225
14226       g_object_unref (tree_view->priv->search_entry);
14227     }
14228   else if (tree_view->priv->search_window)
14229     {
14230       gtk_widget_destroy (tree_view->priv->search_window);
14231
14232       tree_view->priv->search_window = NULL;
14233     }
14234
14235   if (entry)
14236     {
14237       tree_view->priv->search_entry = g_object_ref (entry);
14238       tree_view->priv->search_custom_entry_set = TRUE;
14239
14240       if (tree_view->priv->search_entry_changed_id == 0)
14241         {
14242           tree_view->priv->search_entry_changed_id =
14243             g_signal_connect (tree_view->priv->search_entry, "changed",
14244                               G_CALLBACK (gtk_tree_view_search_init),
14245                               tree_view);
14246         }
14247       
14248         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14249                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14250                           tree_view);
14251
14252         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14253     }
14254   else
14255     {
14256       tree_view->priv->search_entry = NULL;
14257       tree_view->priv->search_custom_entry_set = FALSE;
14258     }
14259 }
14260
14261 /**
14262  * gtk_tree_view_set_search_position_func:
14263  * @tree_view: A #GtkTreeView
14264  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14265  *    to use the default search position function
14266  * @data: (allow-none): user data to pass to @func, or %NULL
14267  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14268  *
14269  * Sets the function to use when positioning the search dialog.
14270  *
14271  * Since: 2.10
14272  **/
14273 void
14274 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14275                                         GtkTreeViewSearchPositionFunc  func,
14276                                         gpointer                       user_data,
14277                                         GDestroyNotify                 destroy)
14278 {
14279   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14280
14281   if (tree_view->priv->search_position_destroy)
14282     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14283
14284   tree_view->priv->search_position_func = func;
14285   tree_view->priv->search_position_user_data = user_data;
14286   tree_view->priv->search_position_destroy = destroy;
14287   if (tree_view->priv->search_position_func == NULL)
14288     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14289 }
14290
14291 /**
14292  * gtk_tree_view_get_search_position_func:
14293  * @tree_view: A #GtkTreeView
14294  *
14295  * Returns the positioning function currently in use.
14296  *
14297  * Return value: the currently used function for positioning the search dialog.
14298  *
14299  * Since: 2.10
14300  */
14301 GtkTreeViewSearchPositionFunc
14302 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14303 {
14304   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14305
14306   return tree_view->priv->search_position_func;
14307 }
14308
14309
14310 static void
14311 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14312                                   GtkTreeView *tree_view,
14313                                   GdkDevice   *device)
14314 {
14315   if (tree_view->priv->disable_popdown)
14316     return;
14317
14318   if (tree_view->priv->search_entry_changed_id)
14319     {
14320       g_signal_handler_disconnect (tree_view->priv->search_entry,
14321                                    tree_view->priv->search_entry_changed_id);
14322       tree_view->priv->search_entry_changed_id = 0;
14323     }
14324   if (tree_view->priv->typeselect_flush_timeout)
14325     {
14326       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14327       tree_view->priv->typeselect_flush_timeout = 0;
14328     }
14329         
14330   if (gtk_widget_get_visible (search_dialog))
14331     {
14332       /* send focus-in event */
14333       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14334       gtk_widget_hide (search_dialog);
14335       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14336       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14337     }
14338 }
14339
14340 static void
14341 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14342                                     GtkWidget   *search_dialog,
14343                                     gpointer     user_data)
14344 {
14345   gint x, y;
14346   gint tree_x, tree_y;
14347   gint tree_width, tree_height;
14348   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14349   GdkScreen *screen = gdk_window_get_screen (tree_window);
14350   GtkRequisition requisition;
14351   gint monitor_num;
14352   GdkRectangle monitor;
14353
14354   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14355   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14356
14357   gtk_widget_realize (search_dialog);
14358
14359   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14360   tree_width = gdk_window_get_width (tree_window);
14361   tree_height = gdk_window_get_height (tree_window);
14362   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14363
14364   if (tree_x + tree_width > gdk_screen_get_width (screen))
14365     x = gdk_screen_get_width (screen) - requisition.width;
14366   else if (tree_x + tree_width - requisition.width < 0)
14367     x = 0;
14368   else
14369     x = tree_x + tree_width - requisition.width;
14370
14371   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14372     y = gdk_screen_get_height (screen) - requisition.height;
14373   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14374     y = 0;
14375   else
14376     y = tree_y + tree_height;
14377
14378   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14379 }
14380
14381 static void
14382 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14383                                       GtkMenu  *menu,
14384                                       gpointer  data)
14385 {
14386   GtkTreeView *tree_view = (GtkTreeView *)data;
14387
14388   tree_view->priv->disable_popdown = 1;
14389   g_signal_connect (menu, "hide",
14390                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14391 }
14392
14393 /* Because we're visible but offscreen, we just set a flag in the preedit
14394  * callback.
14395  */
14396 static void
14397 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14398                                       GtkTreeView  *tree_view)
14399 {
14400   tree_view->priv->imcontext_changed = 1;
14401   if (tree_view->priv->typeselect_flush_timeout)
14402     {
14403       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14404       tree_view->priv->typeselect_flush_timeout =
14405         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14406                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14407                        tree_view);
14408     }
14409
14410 }
14411
14412 static void
14413 gtk_tree_view_search_activate (GtkEntry    *entry,
14414                                GtkTreeView *tree_view)
14415 {
14416   GtkTreePath *path;
14417   GtkRBNode *node;
14418   GtkRBTree *tree;
14419
14420   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14421                                     tree_view,
14422                                     gtk_get_current_event_device ());
14423
14424   /* If we have a row selected and it's the cursor row, we activate
14425    * the row XXX */
14426   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14427     {
14428       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14429       
14430       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14431       
14432       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14433         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14434       
14435       gtk_tree_path_free (path);
14436     }
14437 }
14438
14439 static gboolean
14440 gtk_tree_view_real_search_enable_popdown (gpointer data)
14441 {
14442   GtkTreeView *tree_view = (GtkTreeView *)data;
14443
14444   tree_view->priv->disable_popdown = 0;
14445
14446   return FALSE;
14447 }
14448
14449 static void
14450 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14451                                      gpointer   data)
14452 {
14453   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14454 }
14455
14456 static gboolean
14457 gtk_tree_view_search_delete_event (GtkWidget *widget,
14458                                    GdkEventAny *event,
14459                                    GtkTreeView *tree_view)
14460 {
14461   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14462
14463   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14464
14465   return TRUE;
14466 }
14467
14468 static gboolean
14469 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14470                                          GdkEventButton *event,
14471                                          GtkTreeView *tree_view)
14472 {
14473   GdkDevice *keyb_device;
14474
14475   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14476
14477   keyb_device = gdk_device_get_associated_device (event->device);
14478   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14479
14480   if (event->window == tree_view->priv->bin_window)
14481     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14482
14483   return TRUE;
14484 }
14485
14486 static gboolean
14487 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14488                                    GdkEventScroll *event,
14489                                    GtkTreeView *tree_view)
14490 {
14491   gboolean retval = FALSE;
14492
14493   if (event->direction == GDK_SCROLL_UP)
14494     {
14495       gtk_tree_view_search_move (widget, tree_view, TRUE);
14496       retval = TRUE;
14497     }
14498   else if (event->direction == GDK_SCROLL_DOWN)
14499     {
14500       gtk_tree_view_search_move (widget, tree_view, FALSE);
14501       retval = TRUE;
14502     }
14503
14504   /* renew the flush timeout */
14505   if (retval && tree_view->priv->typeselect_flush_timeout
14506       && !tree_view->priv->search_custom_entry_set)
14507     {
14508       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14509       tree_view->priv->typeselect_flush_timeout =
14510         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14511                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14512                        tree_view);
14513     }
14514
14515   return retval;
14516 }
14517
14518 static gboolean
14519 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14520                                       GdkEventKey *event,
14521                                       GtkTreeView *tree_view)
14522 {
14523   gboolean retval = FALSE;
14524
14525   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14526   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14527
14528   /* close window and cancel the search */
14529   if (!tree_view->priv->search_custom_entry_set
14530       && (event->keyval == GDK_KEY_Escape ||
14531           event->keyval == GDK_KEY_Tab ||
14532             event->keyval == GDK_KEY_KP_Tab ||
14533             event->keyval == GDK_KEY_ISO_Left_Tab))
14534     {
14535       gtk_tree_view_search_dialog_hide (widget, tree_view,
14536                                         gdk_event_get_device ((GdkEvent *) event));
14537       return TRUE;
14538     }
14539
14540   /* select previous matching iter */
14541   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
14542     {
14543       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14544         gtk_widget_error_bell (widget);
14545
14546       retval = TRUE;
14547     }
14548
14549   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14550       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14551     {
14552       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14553         gtk_widget_error_bell (widget);
14554
14555       retval = TRUE;
14556     }
14557
14558   /* select next matching iter */
14559   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
14560     {
14561       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14562         gtk_widget_error_bell (widget);
14563
14564       retval = TRUE;
14565     }
14566
14567   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14568       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14569     {
14570       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14571         gtk_widget_error_bell (widget);
14572
14573       retval = TRUE;
14574     }
14575
14576   /* renew the flush timeout */
14577   if (retval && tree_view->priv->typeselect_flush_timeout
14578       && !tree_view->priv->search_custom_entry_set)
14579     {
14580       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14581       tree_view->priv->typeselect_flush_timeout =
14582         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14583                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14584                        tree_view);
14585     }
14586
14587   return retval;
14588 }
14589
14590 /*  this function returns FALSE if there is a search string but
14591  *  nothing was found, and TRUE otherwise.
14592  */
14593 static gboolean
14594 gtk_tree_view_search_move (GtkWidget   *window,
14595                            GtkTreeView *tree_view,
14596                            gboolean     up)
14597 {
14598   gboolean ret;
14599   gint len;
14600   gint count = 0;
14601   const gchar *text;
14602   GtkTreeIter iter;
14603   GtkTreeModel *model;
14604   GtkTreeSelection *selection;
14605
14606   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14607
14608   g_return_val_if_fail (text != NULL, FALSE);
14609
14610   len = strlen (text);
14611
14612   if (up && tree_view->priv->selected_iter == 1)
14613     return strlen (text) < 1;
14614
14615   len = strlen (text);
14616
14617   if (len < 1)
14618     return TRUE;
14619
14620   model = gtk_tree_view_get_model (tree_view);
14621   selection = gtk_tree_view_get_selection (tree_view);
14622
14623   /* search */
14624   gtk_tree_selection_unselect_all (selection);
14625   if (!gtk_tree_model_get_iter_first (model, &iter))
14626     return TRUE;
14627
14628   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14629                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14630
14631   if (ret)
14632     {
14633       /* found */
14634       tree_view->priv->selected_iter += up?(-1):(1);
14635       return TRUE;
14636     }
14637   else
14638     {
14639       /* return to old iter */
14640       count = 0;
14641       gtk_tree_model_get_iter_first (model, &iter);
14642       gtk_tree_view_search_iter (model, selection,
14643                                  &iter, text,
14644                                  &count, tree_view->priv->selected_iter);
14645       return FALSE;
14646     }
14647 }
14648
14649 static gboolean
14650 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14651                                  gint          column,
14652                                  const gchar  *key,
14653                                  GtkTreeIter  *iter,
14654                                  gpointer      search_data)
14655 {
14656   gboolean retval = TRUE;
14657   const gchar *str;
14658   gchar *normalized_string;
14659   gchar *normalized_key;
14660   gchar *case_normalized_string = NULL;
14661   gchar *case_normalized_key = NULL;
14662   GValue value = {0,};
14663   GValue transformed = {0,};
14664
14665   gtk_tree_model_get_value (model, iter, column, &value);
14666
14667   g_value_init (&transformed, G_TYPE_STRING);
14668
14669   if (!g_value_transform (&value, &transformed))
14670     {
14671       g_value_unset (&value);
14672       return TRUE;
14673     }
14674
14675   g_value_unset (&value);
14676
14677   str = g_value_get_string (&transformed);
14678   if (!str)
14679     {
14680       g_value_unset (&transformed);
14681       return TRUE;
14682     }
14683
14684   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14685   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14686
14687   if (normalized_string && normalized_key)
14688     {
14689       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14690       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14691
14692       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14693         retval = FALSE;
14694     }
14695
14696   g_value_unset (&transformed);
14697   g_free (normalized_key);
14698   g_free (normalized_string);
14699   g_free (case_normalized_key);
14700   g_free (case_normalized_string);
14701
14702   return retval;
14703 }
14704
14705 static gboolean
14706 gtk_tree_view_search_iter (GtkTreeModel     *model,
14707                            GtkTreeSelection *selection,
14708                            GtkTreeIter      *iter,
14709                            const gchar      *text,
14710                            gint             *count,
14711                            gint              n)
14712 {
14713   GtkRBTree *tree = NULL;
14714   GtkRBNode *node = NULL;
14715   GtkTreePath *path;
14716
14717   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14718
14719   path = gtk_tree_model_get_path (model, iter);
14720   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14721
14722   do
14723     {
14724       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14725         {
14726           (*count)++;
14727           if (*count == n)
14728             {
14729               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14730                                             TRUE, 0.5, 0.0);
14731               gtk_tree_selection_select_iter (selection, iter);
14732               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14733
14734               if (path)
14735                 gtk_tree_path_free (path);
14736
14737               return TRUE;
14738             }
14739         }
14740
14741       if (node->children)
14742         {
14743           gboolean has_child;
14744           GtkTreeIter tmp;
14745
14746           tree = node->children;
14747           node = tree->root;
14748
14749           while (node->left != tree->nil)
14750             node = node->left;
14751
14752           tmp = *iter;
14753           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14754           gtk_tree_path_down (path);
14755
14756           /* sanity check */
14757           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14758         }
14759       else
14760         {
14761           gboolean done = FALSE;
14762
14763           do
14764             {
14765               node = _gtk_rbtree_next (tree, node);
14766
14767               if (node)
14768                 {
14769                   gboolean has_next;
14770
14771                   has_next = gtk_tree_model_iter_next (model, iter);
14772
14773                   done = TRUE;
14774                   gtk_tree_path_next (path);
14775
14776                   /* sanity check */
14777                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14778                 }
14779               else
14780                 {
14781                   gboolean has_parent;
14782                   GtkTreeIter tmp_iter = *iter;
14783
14784                   node = tree->parent_node;
14785                   tree = tree->parent_tree;
14786
14787                   if (!tree)
14788                     {
14789                       if (path)
14790                         gtk_tree_path_free (path);
14791
14792                       /* we've run out of tree, done with this func */
14793                       return FALSE;
14794                     }
14795
14796                   has_parent = gtk_tree_model_iter_parent (model,
14797                                                            iter,
14798                                                            &tmp_iter);
14799                   gtk_tree_path_up (path);
14800
14801                   /* sanity check */
14802                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14803                 }
14804             }
14805           while (!done);
14806         }
14807     }
14808   while (1);
14809
14810   return FALSE;
14811 }
14812
14813 static void
14814 gtk_tree_view_search_init (GtkWidget   *entry,
14815                            GtkTreeView *tree_view)
14816 {
14817   gint ret;
14818   gint count = 0;
14819   const gchar *text;
14820   GtkTreeIter iter;
14821   GtkTreeModel *model;
14822   GtkTreeSelection *selection;
14823
14824   g_return_if_fail (GTK_IS_ENTRY (entry));
14825   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14826
14827   text = gtk_entry_get_text (GTK_ENTRY (entry));
14828
14829   model = gtk_tree_view_get_model (tree_view);
14830   selection = gtk_tree_view_get_selection (tree_view);
14831
14832   /* search */
14833   gtk_tree_selection_unselect_all (selection);
14834   if (tree_view->priv->typeselect_flush_timeout
14835       && !tree_view->priv->search_custom_entry_set)
14836     {
14837       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14838       tree_view->priv->typeselect_flush_timeout =
14839         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14840                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14841                        tree_view);
14842     }
14843
14844   if (*text == '\0')
14845     return;
14846
14847   if (!gtk_tree_model_get_iter_first (model, &iter))
14848     return;
14849
14850   ret = gtk_tree_view_search_iter (model, selection,
14851                                    &iter, text,
14852                                    &count, 1);
14853
14854   if (ret)
14855     tree_view->priv->selected_iter = 1;
14856 }
14857
14858 static void
14859 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14860                              GtkTreeView     *tree_view)
14861 {
14862   if (tree_view->priv->edited_column == NULL)
14863     return;
14864
14865   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14866   tree_view->priv->edited_column = NULL;
14867
14868   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
14869     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14870
14871   g_signal_handlers_disconnect_by_func (cell_editable,
14872                                         gtk_tree_view_remove_widget,
14873                                         tree_view);
14874
14875   gtk_container_remove (GTK_CONTAINER (tree_view),
14876                         GTK_WIDGET (cell_editable));  
14877
14878   /* FIXME should only redraw a single node */
14879   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14880 }
14881
14882 static gboolean
14883 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14884                              GtkTreePath *cursor_path)
14885 {
14886   GtkTreeIter iter;
14887   GdkRectangle background_area;
14888   GdkRectangle cell_area;
14889   GtkCellEditable *editable_widget = NULL;
14890   gchar *path_string;
14891   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14892   gint retval = FALSE;
14893   GtkRBTree *cursor_tree;
14894   GtkRBNode *cursor_node;
14895
14896   g_assert (tree_view->priv->focus_column);
14897
14898   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
14899     return FALSE;
14900
14901   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14902       cursor_node == NULL)
14903     return FALSE;
14904
14905   path_string = gtk_tree_path_to_string (cursor_path);
14906   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14907
14908   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14909
14910   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14911                                            tree_view->priv->model,
14912                                            &iter,
14913                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14914                                            cursor_node->children?TRUE:FALSE);
14915   gtk_tree_view_get_background_area (tree_view,
14916                                      cursor_path,
14917                                      tree_view->priv->focus_column,
14918                                      &background_area);
14919   gtk_tree_view_get_cell_area (tree_view,
14920                                cursor_path,
14921                                tree_view->priv->focus_column,
14922                                &cell_area);
14923
14924   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14925                                         &editable_widget,
14926                                         NULL,
14927                                         path_string,
14928                                         &background_area,
14929                                         &cell_area,
14930                                         flags))
14931     {
14932       retval = TRUE;
14933       if (editable_widget != NULL)
14934         {
14935           gint left, right;
14936           GdkRectangle area;
14937           GtkCellRenderer *cell;
14938
14939           area = cell_area;
14940           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14941
14942           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14943
14944           area.x += left;
14945           area.width -= right + left;
14946
14947           gtk_tree_view_real_start_editing (tree_view,
14948                                             tree_view->priv->focus_column,
14949                                             cursor_path,
14950                                             editable_widget,
14951                                             &area,
14952                                             NULL,
14953                                             flags);
14954         }
14955
14956     }
14957   g_free (path_string);
14958   return retval;
14959 }
14960
14961 static void
14962 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14963                                   GtkTreeViewColumn *column,
14964                                   GtkTreePath       *path,
14965                                   GtkCellEditable   *cell_editable,
14966                                   GdkRectangle      *cell_area,
14967                                   GdkEvent          *event,
14968                                   guint              flags)
14969 {
14970   gint pre_val = tree_view->priv->vadjustment->value;
14971   GtkRequisition requisition;
14972
14973   tree_view->priv->edited_column = column;
14974   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14975
14976   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14977   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14978
14979   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
14980                                  &requisition, NULL);
14981
14982   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14983
14984   if (requisition.height < cell_area->height)
14985     {
14986       gint diff = cell_area->height - requisition.height;
14987       gtk_tree_view_put (tree_view,
14988                          GTK_WIDGET (cell_editable),
14989                          cell_area->x, cell_area->y + diff/2,
14990                          cell_area->width, requisition.height);
14991     }
14992   else
14993     {
14994       gtk_tree_view_put (tree_view,
14995                          GTK_WIDGET (cell_editable),
14996                          cell_area->x, cell_area->y,
14997                          cell_area->width, cell_area->height);
14998     }
14999
15000   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
15001                                    (GdkEvent *)event);
15002
15003   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
15004   g_signal_connect (cell_editable, "remove-widget",
15005                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
15006 }
15007
15008 static void
15009 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15010                             gboolean     cancel_editing)
15011 {
15012   GtkTreeViewColumn *column;
15013   GtkCellRenderer *cell;
15014
15015   if (tree_view->priv->edited_column == NULL)
15016     return;
15017
15018   /*
15019    * This is very evil. We need to do this, because
15020    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15021    * later on. If gtk_tree_view_row_changed notices
15022    * tree_view->priv->edited_column != NULL, it'll call
15023    * gtk_tree_view_stop_editing again. Bad things will happen then.
15024    *
15025    * Please read that again if you intend to modify anything here.
15026    */
15027
15028   column = tree_view->priv->edited_column;
15029   tree_view->priv->edited_column = NULL;
15030
15031   cell = _gtk_tree_view_column_get_edited_cell (column);
15032   gtk_cell_renderer_stop_editing (cell, cancel_editing);
15033
15034   if (!cancel_editing)
15035     gtk_cell_editable_editing_done (column->editable_widget);
15036
15037   tree_view->priv->edited_column = column;
15038
15039   gtk_cell_editable_remove_widget (column->editable_widget);
15040 }
15041
15042
15043 /**
15044  * gtk_tree_view_set_hover_selection:
15045  * @tree_view: a #GtkTreeView
15046  * @hover: %TRUE to enable hover selection mode
15047  *
15048  * Enables of disables the hover selection mode of @tree_view.
15049  * Hover selection makes the selected row follow the pointer.
15050  * Currently, this works only for the selection modes 
15051  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15052  * 
15053  * Since: 2.6
15054  **/
15055 void     
15056 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15057                                    gboolean     hover)
15058 {
15059   hover = hover != FALSE;
15060
15061   if (hover != tree_view->priv->hover_selection)
15062     {
15063       tree_view->priv->hover_selection = hover;
15064
15065       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15066     }
15067 }
15068
15069 /**
15070  * gtk_tree_view_get_hover_selection:
15071  * @tree_view: a #GtkTreeView
15072  * 
15073  * Returns whether hover selection mode is turned on for @tree_view.
15074  * 
15075  * Return value: %TRUE if @tree_view is in hover selection mode
15076  *
15077  * Since: 2.6 
15078  **/
15079 gboolean 
15080 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15081 {
15082   return tree_view->priv->hover_selection;
15083 }
15084
15085 /**
15086  * gtk_tree_view_set_hover_expand:
15087  * @tree_view: a #GtkTreeView
15088  * @expand: %TRUE to enable hover selection mode
15089  *
15090  * Enables of disables the hover expansion mode of @tree_view.
15091  * Hover expansion makes rows expand or collapse if the pointer 
15092  * moves over them.
15093  * 
15094  * Since: 2.6
15095  **/
15096 void     
15097 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15098                                 gboolean     expand)
15099 {
15100   expand = expand != FALSE;
15101
15102   if (expand != tree_view->priv->hover_expand)
15103     {
15104       tree_view->priv->hover_expand = expand;
15105
15106       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15107     }
15108 }
15109
15110 /**
15111  * gtk_tree_view_get_hover_expand:
15112  * @tree_view: a #GtkTreeView
15113  * 
15114  * Returns whether hover expansion mode is turned on for @tree_view.
15115  * 
15116  * Return value: %TRUE if @tree_view is in hover expansion mode
15117  *
15118  * Since: 2.6 
15119  **/
15120 gboolean 
15121 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15122 {
15123   return tree_view->priv->hover_expand;
15124 }
15125
15126 /**
15127  * gtk_tree_view_set_rubber_banding:
15128  * @tree_view: a #GtkTreeView
15129  * @enable: %TRUE to enable rubber banding
15130  *
15131  * Enables or disables rubber banding in @tree_view.  If the selection mode
15132  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15133  * multiple rows by dragging the mouse.
15134  * 
15135  * Since: 2.10
15136  **/
15137 void
15138 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15139                                   gboolean     enable)
15140 {
15141   enable = enable != FALSE;
15142
15143   if (enable != tree_view->priv->rubber_banding_enable)
15144     {
15145       tree_view->priv->rubber_banding_enable = enable;
15146
15147       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15148     }
15149 }
15150
15151 /**
15152  * gtk_tree_view_get_rubber_banding:
15153  * @tree_view: a #GtkTreeView
15154  * 
15155  * Returns whether rubber banding is turned on for @tree_view.  If the
15156  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15157  * user to select multiple rows by dragging the mouse.
15158  * 
15159  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15160  *
15161  * Since: 2.10
15162  **/
15163 gboolean
15164 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15165 {
15166   return tree_view->priv->rubber_banding_enable;
15167 }
15168
15169 /**
15170  * gtk_tree_view_is_rubber_banding_active:
15171  * @tree_view: a #GtkTreeView
15172  * 
15173  * Returns whether a rubber banding operation is currently being done
15174  * in @tree_view.
15175  *
15176  * Return value: %TRUE if a rubber banding operation is currently being
15177  * done in @tree_view.
15178  *
15179  * Since: 2.12
15180  **/
15181 gboolean
15182 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15183 {
15184   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15185
15186   if (tree_view->priv->rubber_banding_enable
15187       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15188     return TRUE;
15189
15190   return FALSE;
15191 }
15192
15193 /**
15194  * gtk_tree_view_get_row_separator_func:
15195  * @tree_view: a #GtkTreeView
15196  * 
15197  * Returns the current row separator function.
15198  * 
15199  * Return value: the current row separator function.
15200  *
15201  * Since: 2.6
15202  **/
15203 GtkTreeViewRowSeparatorFunc 
15204 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15205 {
15206   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15207
15208   return tree_view->priv->row_separator_func;
15209 }
15210
15211 /**
15212  * gtk_tree_view_set_row_separator_func:
15213  * @tree_view: a #GtkTreeView
15214  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15215  * @data: (allow-none): user data to pass to @func, or %NULL
15216  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15217  * 
15218  * Sets the row separator function, which is used to determine
15219  * whether a row should be drawn as a separator. If the row separator
15220  * function is %NULL, no separators are drawn. This is the default value.
15221  *
15222  * Since: 2.6
15223  **/
15224 void
15225 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15226                                       GtkTreeViewRowSeparatorFunc  func,
15227                                       gpointer                     data,
15228                                       GDestroyNotify               destroy)
15229 {
15230   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15231
15232   if (tree_view->priv->row_separator_destroy)
15233     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15234
15235   tree_view->priv->row_separator_func = func;
15236   tree_view->priv->row_separator_data = data;
15237   tree_view->priv->row_separator_destroy = destroy;
15238
15239   /* Have the tree recalculate heights */
15240   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15241   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15242 }
15243
15244   
15245 static void
15246 gtk_tree_view_grab_notify (GtkWidget *widget,
15247                            gboolean   was_grabbed)
15248 {
15249   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15250
15251   tree_view->priv->in_grab = !was_grabbed;
15252
15253   if (!was_grabbed)
15254     {
15255       tree_view->priv->pressed_button = -1;
15256
15257       if (tree_view->priv->rubber_band_status)
15258         gtk_tree_view_stop_rubber_band (tree_view);
15259     }
15260 }
15261
15262 static void
15263 gtk_tree_view_state_changed (GtkWidget      *widget,
15264                              GtkStateType    previous_state)
15265 {
15266   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15267
15268   if (gtk_widget_get_realized (widget))
15269     {
15270       gdk_window_set_background (tree_view->priv->bin_window,
15271                                  &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
15272     }
15273
15274   gtk_widget_queue_draw (widget);
15275 }
15276
15277 /**
15278  * gtk_tree_view_get_grid_lines:
15279  * @tree_view: a #GtkTreeView
15280  *
15281  * Returns which grid lines are enabled in @tree_view.
15282  *
15283  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15284  * are enabled.
15285  *
15286  * Since: 2.10
15287  */
15288 GtkTreeViewGridLines
15289 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15290 {
15291   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15292
15293   return tree_view->priv->grid_lines;
15294 }
15295
15296 /**
15297  * gtk_tree_view_set_grid_lines:
15298  * @tree_view: a #GtkTreeView
15299  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15300  * enable.
15301  *
15302  * Sets which grid lines to draw in @tree_view.
15303  *
15304  * Since: 2.10
15305  */
15306 void
15307 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15308                               GtkTreeViewGridLines   grid_lines)
15309 {
15310   GtkTreeViewPrivate *priv;
15311   GtkWidget *widget;
15312   GtkTreeViewGridLines old_grid_lines;
15313
15314   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15315
15316   priv = tree_view->priv;
15317   widget = GTK_WIDGET (tree_view);
15318
15319   old_grid_lines = priv->grid_lines;
15320   priv->grid_lines = grid_lines;
15321   
15322   if (gtk_widget_get_realized (widget))
15323     {
15324       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15325           priv->grid_line_width)
15326         {
15327           priv->grid_line_width = 0;
15328         }
15329       
15330       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15331           !priv->grid_line_width)
15332         {
15333           gint8 *dash_list;
15334
15335           gtk_widget_style_get (widget,
15336                                 "grid-line-width", &priv->grid_line_width,
15337                                 "grid-line-pattern", (gchar *)&dash_list,
15338                                 NULL);
15339       
15340           if (dash_list)
15341             {
15342               priv->grid_line_dashes[0] = dash_list[0];
15343               if (dash_list[0])
15344                 priv->grid_line_dashes[1] = dash_list[1];
15345               
15346               g_free (dash_list);
15347             }
15348           else
15349             {
15350               priv->grid_line_dashes[0] = 1;
15351               priv->grid_line_dashes[1] = 1;
15352             }
15353         }      
15354     }
15355
15356   if (old_grid_lines != grid_lines)
15357     {
15358       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15359       
15360       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15361     }
15362 }
15363
15364 /**
15365  * gtk_tree_view_get_enable_tree_lines:
15366  * @tree_view: a #GtkTreeView.
15367  *
15368  * Returns whether or not tree lines are drawn in @tree_view.
15369  *
15370  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15371  * otherwise.
15372  *
15373  * Since: 2.10
15374  */
15375 gboolean
15376 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15377 {
15378   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15379
15380   return tree_view->priv->tree_lines_enabled;
15381 }
15382
15383 /**
15384  * gtk_tree_view_set_enable_tree_lines:
15385  * @tree_view: a #GtkTreeView
15386  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15387  *
15388  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15389  * This does not have any visible effects for lists.
15390  *
15391  * Since: 2.10
15392  */
15393 void
15394 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15395                                      gboolean     enabled)
15396 {
15397   GtkTreeViewPrivate *priv;
15398   GtkWidget *widget;
15399   gboolean was_enabled;
15400
15401   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15402
15403   enabled = enabled != FALSE;
15404
15405   priv = tree_view->priv;
15406   widget = GTK_WIDGET (tree_view);
15407
15408   was_enabled = priv->tree_lines_enabled;
15409
15410   priv->tree_lines_enabled = enabled;
15411
15412   if (gtk_widget_get_realized (widget))
15413     {
15414       if (!enabled && priv->tree_line_width)
15415         {
15416           priv->tree_line_width = 0;
15417         }
15418       
15419       if (enabled && !priv->tree_line_width)
15420         {
15421           gint8 *dash_list;
15422           gtk_widget_style_get (widget,
15423                                 "tree-line-width", &priv->tree_line_width,
15424                                 "tree-line-pattern", (gchar *)&dash_list,
15425                                 NULL);
15426           
15427           if (dash_list)
15428             {
15429               priv->tree_line_dashes[0] = dash_list[0];
15430               if (dash_list[0])
15431                 priv->tree_line_dashes[1] = dash_list[1];
15432               
15433               g_free (dash_list);
15434             }
15435           else
15436             {
15437               priv->tree_line_dashes[0] = 1;
15438               priv->tree_line_dashes[1] = 1;
15439             }
15440         }
15441     }
15442
15443   if (was_enabled != enabled)
15444     {
15445       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15446
15447       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15448     }
15449 }
15450
15451
15452 /**
15453  * gtk_tree_view_set_show_expanders:
15454  * @tree_view: a #GtkTreeView
15455  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15456  *
15457  * Sets whether to draw and enable expanders and indent child rows in
15458  * @tree_view.  When disabled there will be no expanders visible in trees
15459  * and there will be no way to expand and collapse rows by default.  Also
15460  * note that hiding the expanders will disable the default indentation.  You
15461  * can set a custom indentation in this case using
15462  * gtk_tree_view_set_level_indentation().
15463  * This does not have any visible effects for lists.
15464  *
15465  * Since: 2.12
15466  */
15467 void
15468 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15469                                   gboolean     enabled)
15470 {
15471   gboolean was_enabled;
15472
15473   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15474
15475   enabled = enabled != FALSE;
15476   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15477
15478   if (enabled)
15479     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15480   else
15481     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15482
15483   if (enabled != was_enabled)
15484     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15485 }
15486
15487 /**
15488  * gtk_tree_view_get_show_expanders:
15489  * @tree_view: a #GtkTreeView.
15490  *
15491  * Returns whether or not expanders are drawn in @tree_view.
15492  *
15493  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15494  * otherwise.
15495  *
15496  * Since: 2.12
15497  */
15498 gboolean
15499 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15500 {
15501   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15502
15503   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15504 }
15505
15506 /**
15507  * gtk_tree_view_set_level_indentation:
15508  * @tree_view: a #GtkTreeView
15509  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15510  *
15511  * Sets the amount of extra indentation for child levels to use in @tree_view
15512  * in addition to the default indentation.  The value should be specified in
15513  * pixels, a value of 0 disables this feature and in this case only the default
15514  * indentation will be used.
15515  * This does not have any visible effects for lists.
15516  *
15517  * Since: 2.12
15518  */
15519 void
15520 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15521                                      gint         indentation)
15522 {
15523   tree_view->priv->level_indentation = indentation;
15524
15525   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15526 }
15527
15528 /**
15529  * gtk_tree_view_get_level_indentation:
15530  * @tree_view: a #GtkTreeView.
15531  *
15532  * Returns the amount, in pixels, of extra indentation for child levels
15533  * in @tree_view.
15534  *
15535  * Return value: the amount of extra indentation for child levels in
15536  * @tree_view.  A return value of 0 means that this feature is disabled.
15537  *
15538  * Since: 2.12
15539  */
15540 gint
15541 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15542 {
15543   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15544
15545   return tree_view->priv->level_indentation;
15546 }
15547
15548 /**
15549  * gtk_tree_view_set_tooltip_row:
15550  * @tree_view: a #GtkTreeView
15551  * @tooltip: a #GtkTooltip
15552  * @path: a #GtkTreePath
15553  *
15554  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15555  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15556  * See also gtk_tooltip_set_tip_area().
15557  *
15558  * Since: 2.12
15559  */
15560 void
15561 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15562                                GtkTooltip  *tooltip,
15563                                GtkTreePath *path)
15564 {
15565   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15566   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15567
15568   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15569 }
15570
15571 /**
15572  * gtk_tree_view_set_tooltip_cell:
15573  * @tree_view: a #GtkTreeView
15574  * @tooltip: a #GtkTooltip
15575  * @path: (allow-none): a #GtkTreePath or %NULL
15576  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
15577  * @cell: (allow-none): a #GtkCellRenderer or %NULL
15578  *
15579  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15580  * in common.  For example if @path is %NULL and @column is set, the tip
15581  * area will be set to the full area covered by @column.  See also
15582  * gtk_tooltip_set_tip_area().
15583  *
15584  * Note that if @path is not specified and @cell is set and part of a column
15585  * containing the expander, the tooltip might not show and hide at the correct
15586  * position.  In such cases @path must be set to the current node under the
15587  * mouse cursor for this function to operate correctly.
15588  *
15589  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15590  *
15591  * Since: 2.12
15592  */
15593 void
15594 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15595                                 GtkTooltip        *tooltip,
15596                                 GtkTreePath       *path,
15597                                 GtkTreeViewColumn *column,
15598                                 GtkCellRenderer   *cell)
15599 {
15600   GtkAllocation allocation;
15601   GdkRectangle rect;
15602
15603   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15604   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15605   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15606   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15607
15608   /* Determine x values. */
15609   if (column && cell)
15610     {
15611       GdkRectangle tmp;
15612       gint start, width;
15613
15614       /* We always pass in path here, whether it is NULL or not.
15615        * For cells in expander columns path must be specified so that
15616        * we can correctly account for the indentation.  This also means
15617        * that the tooltip is constrained vertically by the "Determine y
15618        * values" code below; this is not a real problem since cells actually
15619        * don't stretch vertically in constrast to columns.
15620        */
15621       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15622       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15623
15624       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15625                                                          tmp.x + start, 0,
15626                                                          &rect.x, NULL);
15627       rect.width = width;
15628     }
15629   else if (column)
15630     {
15631       GdkRectangle tmp;
15632
15633       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15634       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15635                                                          tmp.x, 0,
15636                                                          &rect.x, NULL);
15637       rect.width = tmp.width;
15638     }
15639   else
15640     {
15641       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
15642       rect.x = 0;
15643       rect.width = allocation.width;
15644     }
15645
15646   /* Determine y values. */
15647   if (path)
15648     {
15649       GdkRectangle tmp;
15650
15651       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15652       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15653                                                          0, tmp.y,
15654                                                          NULL, &rect.y);
15655       rect.height = tmp.height;
15656     }
15657   else
15658     {
15659       rect.y = 0;
15660       rect.height = tree_view->priv->vadjustment->page_size;
15661     }
15662
15663   gtk_tooltip_set_tip_area (tooltip, &rect);
15664 }
15665
15666 /**
15667  * gtk_tree_view_get_tooltip_context:
15668  * @tree_view: a #GtkTreeView
15669  * @x: the x coordinate (relative to widget coordinates)
15670  * @y: the y coordinate (relative to widget coordinates)
15671  * @keyboard_tip: whether this is a keyboard tooltip or not
15672  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
15673  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
15674  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
15675  *
15676  * This function is supposed to be used in a #GtkWidget::query-tooltip
15677  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15678  * which are received in the signal handler, should be passed to this
15679  * function without modification.
15680  *
15681  * The return value indicates whether there is a tree view row at the given
15682  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15683  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15684  * @model, @path and @iter which have been provided will be set to point to
15685  * that row and the corresponding model.  @x and @y will always be converted
15686  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15687  *
15688  * Return value: whether or not the given tooltip context points to a row.
15689  *
15690  * Since: 2.12
15691  */
15692 gboolean
15693 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15694                                    gint          *x,
15695                                    gint          *y,
15696                                    gboolean       keyboard_tip,
15697                                    GtkTreeModel **model,
15698                                    GtkTreePath  **path,
15699                                    GtkTreeIter   *iter)
15700 {
15701   GtkTreePath *tmppath = NULL;
15702
15703   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15704   g_return_val_if_fail (x != NULL, FALSE);
15705   g_return_val_if_fail (y != NULL, FALSE);
15706
15707   if (keyboard_tip)
15708     {
15709       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15710
15711       if (!tmppath)
15712         return FALSE;
15713     }
15714   else
15715     {
15716       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15717                                                          x, y);
15718
15719       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15720                                           &tmppath, NULL, NULL, NULL))
15721         return FALSE;
15722     }
15723
15724   if (model)
15725     *model = gtk_tree_view_get_model (tree_view);
15726
15727   if (iter)
15728     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15729                              iter, tmppath);
15730
15731   if (path)
15732     *path = tmppath;
15733   else
15734     gtk_tree_path_free (tmppath);
15735
15736   return TRUE;
15737 }
15738
15739 static gboolean
15740 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15741                                     gint        x,
15742                                     gint        y,
15743                                     gboolean    keyboard_tip,
15744                                     GtkTooltip *tooltip,
15745                                     gpointer    data)
15746 {
15747   GValue value = { 0, };
15748   GValue transformed = { 0, };
15749   GtkTreeIter iter;
15750   GtkTreePath *path;
15751   GtkTreeModel *model;
15752   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15753
15754   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15755                                           &x, &y,
15756                                           keyboard_tip,
15757                                           &model, &path, &iter))
15758     return FALSE;
15759
15760   gtk_tree_model_get_value (model, &iter,
15761                             tree_view->priv->tooltip_column, &value);
15762
15763   g_value_init (&transformed, G_TYPE_STRING);
15764
15765   if (!g_value_transform (&value, &transformed))
15766     {
15767       g_value_unset (&value);
15768       gtk_tree_path_free (path);
15769
15770       return FALSE;
15771     }
15772
15773   g_value_unset (&value);
15774
15775   if (!g_value_get_string (&transformed))
15776     {
15777       g_value_unset (&transformed);
15778       gtk_tree_path_free (path);
15779
15780       return FALSE;
15781     }
15782
15783   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15784   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15785
15786   gtk_tree_path_free (path);
15787   g_value_unset (&transformed);
15788
15789   return TRUE;
15790 }
15791
15792 /**
15793  * gtk_tree_view_set_tooltip_column:
15794  * @tree_view: a #GtkTreeView
15795  * @column: an integer, which is a valid column number for @tree_view's model
15796  *
15797  * If you only plan to have simple (text-only) tooltips on full rows, you
15798  * can use this function to have #GtkTreeView handle these automatically
15799  * for you. @column should be set to the column in @tree_view's model
15800  * containing the tooltip texts, or -1 to disable this feature.
15801  *
15802  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15803  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15804  *
15805  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15806  * so &amp;, &lt;, etc have to be escaped in the text.
15807  *
15808  * Since: 2.12
15809  */
15810 void
15811 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15812                                   gint         column)
15813 {
15814   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15815
15816   if (column == tree_view->priv->tooltip_column)
15817     return;
15818
15819   if (column == -1)
15820     {
15821       g_signal_handlers_disconnect_by_func (tree_view,
15822                                             gtk_tree_view_set_tooltip_query_cb,
15823                                             NULL);
15824       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15825     }
15826   else
15827     {
15828       if (tree_view->priv->tooltip_column == -1)
15829         {
15830           g_signal_connect (tree_view, "query-tooltip",
15831                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15832           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15833         }
15834     }
15835
15836   tree_view->priv->tooltip_column = column;
15837   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15838 }
15839
15840 /**
15841  * gtk_tree_view_get_tooltip_column:
15842  * @tree_view: a #GtkTreeView
15843  *
15844  * Returns the column of @tree_view's model which is being used for
15845  * displaying tooltips on @tree_view's rows.
15846  *
15847  * Return value: the index of the tooltip column that is currently being
15848  * used, or -1 if this is disabled.
15849  *
15850  * Since: 2.12
15851  */
15852 gint
15853 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15854 {
15855   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15856
15857   return tree_view->priv->tooltip_column;
15858 }