]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
4a48d3c48c8e9070001d6bb8dfe1be7b928a1d63
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include "config.h"
22 #include <math.h>
23 #include <string.h>
24 #include <gdk/gdkkeysyms.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmain.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtkalignment.h"
36 #include "gtklabel.h"
37 #include "gtkhbox.h"
38 #include "gtkvbox.h"
39 #include "gtkarrow.h"
40 #include "gtkintl.h"
41 #include "gtkbindings.h"
42 #include "gtkcontainer.h"
43 #include "gtkentry.h"
44 #include "gtkframe.h"
45 #include "gtktreemodelsort.h"
46 #include "gtktooltip.h"
47 #include "gtkscrollable.h"
48 #include "gtkprivate.h"
49 #include "gtkwidgetprivate.h"
50
51 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
52 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
53 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
54 #define SCROLL_EDGE_SIZE 15
55 #define EXPANDER_EXTRA_PADDING 4
56 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
57 #define AUTO_EXPAND_TIMEOUT 500
58
59 /* The "background" areas of all rows/cells add up to cover the entire tree.
60  * The background includes all inter-row and inter-cell spacing.
61  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
62  * i.e. just the cells, no spacing.
63  */
64
65 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
66 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
67
68 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
69  * vice versa.
70  */
71 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
72 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
73
74 /* This is in bin_window coordinates */
75 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
76 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
77
78 #define ROW_HEIGHT(tree_view,height) \
79   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
80
81
82 typedef struct _GtkTreeViewChild GtkTreeViewChild;
83 struct _GtkTreeViewChild
84 {
85   GtkWidget *widget;
86   gint x;
87   gint y;
88   gint width;
89   gint height;
90 };
91
92
93 typedef struct _TreeViewDragInfo TreeViewDragInfo;
94 struct _TreeViewDragInfo
95 {
96   GdkModifierType start_button_mask;
97   GtkTargetList *_unused_source_target_list;
98   GdkDragAction source_actions;
99
100   GtkTargetList *_unused_dest_target_list;
101
102   guint source_set : 1;
103   guint dest_set : 1;
104 };
105
106
107 /* Signals */
108 enum
109 {
110   ROW_ACTIVATED,
111   TEST_EXPAND_ROW,
112   TEST_COLLAPSE_ROW,
113   ROW_EXPANDED,
114   ROW_COLLAPSED,
115   COLUMNS_CHANGED,
116   CURSOR_CHANGED,
117   MOVE_CURSOR,
118   SELECT_ALL,
119   UNSELECT_ALL,
120   SELECT_CURSOR_ROW,
121   TOGGLE_CURSOR_ROW,
122   EXPAND_COLLAPSE_CURSOR_ROW,
123   SELECT_CURSOR_PARENT,
124   START_INTERACTIVE_SEARCH,
125   LAST_SIGNAL
126 };
127
128 /* Properties */
129 enum {
130   PROP_0,
131   PROP_MODEL,
132   PROP_HADJUSTMENT,
133   PROP_VADJUSTMENT,
134   PROP_HSCROLL_POLICY,
135   PROP_VSCROLL_POLICY,
136   PROP_HEADERS_VISIBLE,
137   PROP_HEADERS_CLICKABLE,
138   PROP_EXPANDER_COLUMN,
139   PROP_REORDERABLE,
140   PROP_RULES_HINT,
141   PROP_ENABLE_SEARCH,
142   PROP_SEARCH_COLUMN,
143   PROP_FIXED_HEIGHT_MODE,
144   PROP_HOVER_SELECTION,
145   PROP_HOVER_EXPAND,
146   PROP_SHOW_EXPANDERS,
147   PROP_LEVEL_INDENTATION,
148   PROP_RUBBER_BANDING,
149   PROP_ENABLE_GRID_LINES,
150   PROP_ENABLE_TREE_LINES,
151   PROP_TOOLTIP_COLUMN
152 };
153
154 /* object signals */
155 static void     gtk_tree_view_finalize             (GObject          *object);
156 static void     gtk_tree_view_set_property         (GObject         *object,
157                                                     guint            prop_id,
158                                                     const GValue    *value,
159                                                     GParamSpec      *pspec);
160 static void     gtk_tree_view_get_property         (GObject         *object,
161                                                     guint            prop_id,
162                                                     GValue          *value,
163                                                     GParamSpec      *pspec);
164
165 /* gtkwidget signals */
166 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
167 static void     gtk_tree_view_realize              (GtkWidget        *widget);
168 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
169 static void     gtk_tree_view_map                  (GtkWidget        *widget);
170 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
171                                                     gint             *minimum,
172                                                     gint             *natural);
173 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
174                                                     gint             *minimum,
175                                                     gint             *natural);
176 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
177                                                     GtkRequisition   *requisition);
178 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
179                                                     GtkAllocation    *allocation);
180 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
181                                                     cairo_t          *cr);
182 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
183                                                     GdkEventKey      *event);
184 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
185                                                     GdkEventKey      *event);
186 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
187                                                     GdkEventMotion   *event);
188 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
189                                                     GdkEventCrossing *event);
190 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
191                                                     GdkEventCrossing *event);
192 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
193                                                     GdkEventButton   *event);
194 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
195                                                     GdkEventButton   *event);
196 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
197                                                     GdkEventGrabBroken *event);
198 #if 0
199 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
200                                                     GdkEventConfigure *event);
201 #endif
202
203 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
204                                                     GtkWidget        *child);
205 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
206                                                     GdkEventFocus    *event);
207 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
208                                                     GtkDirectionType  direction);
209 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
210 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
211                                                     GtkStyle         *previous_style);
212 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
213                                                     gboolean          was_grabbed);
214 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
215                                                     GtkStateType      previous_state);
216
217 /* container signals */
218 static void     gtk_tree_view_remove               (GtkContainer     *container,
219                                                     GtkWidget        *widget);
220 static void     gtk_tree_view_forall               (GtkContainer     *container,
221                                                     gboolean          include_internals,
222                                                     GtkCallback       callback,
223                                                     gpointer          callback_data);
224
225 /* Source side drag signals */
226 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
227                                             GdkDragContext   *context);
228 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
229                                             GdkDragContext   *context);
230 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
231                                             GdkDragContext   *context,
232                                             GtkSelectionData *selection_data,
233                                             guint             info,
234                                             guint             time);
235 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
236                                             GdkDragContext   *context);
237
238 /* Target side drag signals */
239 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
240                                                   GdkDragContext   *context,
241                                                   guint             time);
242 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
243                                                   GdkDragContext   *context,
244                                                   gint              x,
245                                                   gint              y,
246                                                   guint             time);
247 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
248                                                   GdkDragContext   *context,
249                                                   gint              x,
250                                                   gint              y,
251                                                   guint             time);
252 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
253                                                   GdkDragContext   *context,
254                                                   gint              x,
255                                                   gint              y,
256                                                   GtkSelectionData *selection_data,
257                                                   guint             info,
258                                                   guint             time);
259
260 /* tree_model signals */
261 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
262                                                            GtkAdjustment   *adjustment);
263 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
264                                                            GtkAdjustment   *adjustment);
265 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
266                                                            GtkMovementStep  step,
267                                                            gint             count);
268 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
269 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
270 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
271                                                            gboolean         start_editing);
272 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
273 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
274                                                                gboolean         logical,
275                                                                gboolean         expand,
276                                                                gboolean         open_all);
277 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
278 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
279                                                            GtkTreePath     *path,
280                                                            GtkTreeIter     *iter,
281                                                            gpointer         data);
282 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
283                                                            GtkTreePath     *path,
284                                                            GtkTreeIter     *iter,
285                                                            gpointer         data);
286 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
287                                                            GtkTreePath     *path,
288                                                            GtkTreeIter     *iter,
289                                                            gpointer         data);
290 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
291                                                            GtkTreePath     *path,
292                                                            gpointer         data);
293 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
294                                                            GtkTreePath     *parent,
295                                                            GtkTreeIter     *iter,
296                                                            gint            *new_order,
297                                                            gpointer         data);
298
299 /* Incremental reflow */
300 static gboolean validate_row             (GtkTreeView *tree_view,
301                                           GtkRBTree   *tree,
302                                           GtkRBNode   *node,
303                                           GtkTreeIter *iter,
304                                           GtkTreePath *path);
305 static void     validate_visible_area    (GtkTreeView *tree_view);
306 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
307 static gboolean do_validate_rows         (GtkTreeView *tree_view,
308                                           gboolean     size_request);
309 static gboolean validate_rows            (GtkTreeView *tree_view);
310 static gboolean presize_handler_callback (gpointer     data);
311 static void     install_presize_handler  (GtkTreeView *tree_view);
312 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
313 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
314                                              GtkTreePath *path,
315                                              gint         offset);
316 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
317 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
318 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
319
320 /* Internal functions */
321 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
322                                                               GtkTreeViewColumn  *column);
323 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
324                                                               guint               keyval,
325                                                               guint               modmask,
326                                                               gboolean            add_shifted_binding,
327                                                               GtkMovementStep     step,
328                                                               gint                count);
329 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
330                                                               GtkRBTree          *tree);
331 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
332                                                               GtkTreePath        *path,
333                                                               const GdkRectangle *clip_rect);
334 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
335                                                               GtkRBTree          *tree,
336                                                               GtkRBNode          *node);
337 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
338                                                               cairo_t            *cr,
339                                                               GtkRBTree          *tree,
340                                                               GtkRBNode          *node,
341                                                               gint                x,
342                                                               gint                y);
343 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
344                                                               GtkRBTree          *tree,
345                                                               gint               *x1,
346                                                               gint               *x2);
347 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
348                                                               gint                i,
349                                                               gint               *x);
350 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
351                                                               GtkTreeView        *tree_view);
352 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
353                                                               GtkRBTree          *tree,
354                                                               GtkTreeIter        *iter,
355                                                               gint                depth,
356                                                               gboolean            recurse);
357 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
358                                                               GtkRBTree          *tree,
359                                                               GtkRBNode          *node);
360 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
361                                                               GtkTreeViewColumn  *column,
362                                                               gboolean            focus_to_cell);
363 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
364                                                               GdkEventMotion     *event);
365 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
366 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
367                                                               gint                count);
368 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
369                                                               gint                count);
370 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
371                                                               gint                count);
372 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
373                                                               gint                count);
374 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
375                                                               GtkTreePath        *path,
376                                                               GtkRBTree          *tree,
377                                                               GtkRBNode          *node,
378                                                               gboolean            animate);
379 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
380                                                               GtkTreePath        *path,
381                                                               GtkRBTree          *tree,
382                                                               GtkRBNode          *node,
383                                                               gboolean            open_all,
384                                                               gboolean            animate);
385 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
386                                                               GtkTreePath        *path,
387                                                               gboolean            clear_and_select,
388                                                               gboolean            clamp_node);
389 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
390 static void     column_sizing_notify                         (GObject            *object,
391                                                               GParamSpec         *pspec,
392                                                               gpointer            data);
393 static gboolean expand_collapse_timeout                      (gpointer            data);
394 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
395                                                               GtkRBTree          *tree,
396                                                               GtkRBNode          *node,
397                                                               gboolean            expand);
398 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
399 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
400 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
401 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
402 static void     update_prelight                              (GtkTreeView        *tree_view,
403                                                               int                 x,
404                                                               int                 y);
405
406 /* interactive search */
407 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
408 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
409                                                          GtkTreeView      *tree_view,
410                                                          GdkDevice        *device);
411 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
412                                                          GtkWidget        *search_dialog,
413                                                          gpointer          user_data);
414 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
415                                                          GtkMenu          *menu,
416                                                          gpointer          data);
417 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
418                                                          GtkTreeView      *tree_view);
419 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
420                                                          GtkTreeView      *tree_view);
421 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
422 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
423                                                          gpointer          data);
424 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
425                                                          GdkEventAny      *event,
426                                                          GtkTreeView      *tree_view);
427 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
428                                                          GdkEventButton   *event,
429                                                          GtkTreeView      *tree_view);
430 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
431                                                          GdkEventScroll   *event,
432                                                          GtkTreeView      *tree_view);
433 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
434                                                          GdkEventKey      *event,
435                                                          GtkTreeView      *tree_view);
436 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
437                                                          GtkTreeView      *tree_view,
438                                                          gboolean          up);
439 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
440                                                          gint              column,
441                                                          const gchar      *key,
442                                                          GtkTreeIter      *iter,
443                                                          gpointer          search_data);
444 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
445                                                          GtkTreeSelection *selection,
446                                                          GtkTreeIter      *iter,
447                                                          const gchar      *text,
448                                                          gint             *count,
449                                                          gint              n);
450 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
451                                                          GtkTreeView      *tree_view);
452 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
453                                                          GtkWidget        *child_widget,
454                                                          gint              x,
455                                                          gint              y,
456                                                          gint              width,
457                                                          gint              height);
458 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
459                                                          GtkTreePath      *cursor_path);
460 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
461                                               GtkTreeViewColumn *column,
462                                               GtkTreePath       *path,
463                                               GtkCellEditable   *cell_editable,
464                                               GdkRectangle      *cell_area,
465                                               GdkEvent          *event,
466                                               guint              flags);
467 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
468                                                          gboolean     cancel_editing);
469 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
470                                                              GdkDevice   *device,
471                                                              gboolean     keybinding);
472 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
473 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
474                                                          GtkTreeViewColumn *column,
475                                                          gint               drop_position);
476
477 /* GtkBuildable */
478 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
479                                                             GtkBuilder        *builder,
480                                                             GObject           *child,
481                                                             const gchar       *type);
482 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
483                                                             GtkBuilder        *builder,
484                                                             const gchar       *childname);
485 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
486
487
488 static gboolean scroll_row_timeout                   (gpointer     data);
489 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
490 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
491
492 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
493
494 \f
495
496 /* GType Methods
497  */
498
499 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
500                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
501                                                 gtk_tree_view_buildable_init)
502                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
503
504 static void
505 gtk_tree_view_class_init (GtkTreeViewClass *class)
506 {
507   GObjectClass *o_class;
508   GtkWidgetClass *widget_class;
509   GtkContainerClass *container_class;
510   GtkBindingSet *binding_set;
511
512   binding_set = gtk_binding_set_by_class (class);
513
514   o_class = (GObjectClass *) class;
515   widget_class = (GtkWidgetClass *) class;
516   container_class = (GtkContainerClass *) class;
517
518   /* GObject signals */
519   o_class->set_property = gtk_tree_view_set_property;
520   o_class->get_property = gtk_tree_view_get_property;
521   o_class->finalize = gtk_tree_view_finalize;
522
523   /* GtkWidget signals */
524   widget_class->destroy = gtk_tree_view_destroy;
525   widget_class->map = gtk_tree_view_map;
526   widget_class->realize = gtk_tree_view_realize;
527   widget_class->unrealize = gtk_tree_view_unrealize;
528   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
529   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
530   widget_class->size_allocate = gtk_tree_view_size_allocate;
531   widget_class->button_press_event = gtk_tree_view_button_press;
532   widget_class->button_release_event = gtk_tree_view_button_release;
533   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
534   /*widget_class->configure_event = gtk_tree_view_configure;*/
535   widget_class->motion_notify_event = gtk_tree_view_motion;
536   widget_class->draw = gtk_tree_view_draw;
537   widget_class->key_press_event = gtk_tree_view_key_press;
538   widget_class->key_release_event = gtk_tree_view_key_release;
539   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
540   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
541   widget_class->focus_out_event = gtk_tree_view_focus_out;
542   widget_class->drag_begin = gtk_tree_view_drag_begin;
543   widget_class->drag_end = gtk_tree_view_drag_end;
544   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
545   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
546   widget_class->drag_leave = gtk_tree_view_drag_leave;
547   widget_class->drag_motion = gtk_tree_view_drag_motion;
548   widget_class->drag_drop = gtk_tree_view_drag_drop;
549   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
550   widget_class->focus = gtk_tree_view_focus;
551   widget_class->grab_focus = gtk_tree_view_grab_focus;
552   widget_class->style_set = gtk_tree_view_style_set;
553   widget_class->grab_notify = gtk_tree_view_grab_notify;
554   widget_class->state_changed = gtk_tree_view_state_changed;
555
556   /* GtkContainer signals */
557   container_class->remove = gtk_tree_view_remove;
558   container_class->forall = gtk_tree_view_forall;
559   container_class->set_focus_child = gtk_tree_view_set_focus_child;
560
561   class->move_cursor = gtk_tree_view_real_move_cursor;
562   class->select_all = gtk_tree_view_real_select_all;
563   class->unselect_all = gtk_tree_view_real_unselect_all;
564   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
565   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
566   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
567   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
568   class->start_interactive_search = gtk_tree_view_start_interactive_search;
569
570   /* Properties */
571
572   g_object_class_install_property (o_class,
573                                    PROP_MODEL,
574                                    g_param_spec_object ("model",
575                                                         P_("TreeView Model"),
576                                                         P_("The model for the tree view"),
577                                                         GTK_TYPE_TREE_MODEL,
578                                                         GTK_PARAM_READWRITE));
579
580   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
581   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
582   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
583   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
584
585   g_object_class_install_property (o_class,
586                                    PROP_HEADERS_VISIBLE,
587                                    g_param_spec_boolean ("headers-visible",
588                                                          P_("Headers Visible"),
589                                                          P_("Show the column header buttons"),
590                                                          TRUE,
591                                                          GTK_PARAM_READWRITE));
592
593   g_object_class_install_property (o_class,
594                                    PROP_HEADERS_CLICKABLE,
595                                    g_param_spec_boolean ("headers-clickable",
596                                                          P_("Headers Clickable"),
597                                                          P_("Column headers respond to click events"),
598                                                          TRUE,
599                                                          GTK_PARAM_READWRITE));
600
601   g_object_class_install_property (o_class,
602                                    PROP_EXPANDER_COLUMN,
603                                    g_param_spec_object ("expander-column",
604                                                         P_("Expander Column"),
605                                                         P_("Set the column for the expander column"),
606                                                         GTK_TYPE_TREE_VIEW_COLUMN,
607                                                         GTK_PARAM_READWRITE));
608
609   g_object_class_install_property (o_class,
610                                    PROP_REORDERABLE,
611                                    g_param_spec_boolean ("reorderable",
612                                                          P_("Reorderable"),
613                                                          P_("View is reorderable"),
614                                                          FALSE,
615                                                          GTK_PARAM_READWRITE));
616
617   g_object_class_install_property (o_class,
618                                    PROP_RULES_HINT,
619                                    g_param_spec_boolean ("rules-hint",
620                                                          P_("Rules Hint"),
621                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
622                                                          FALSE,
623                                                          GTK_PARAM_READWRITE));
624
625     g_object_class_install_property (o_class,
626                                      PROP_ENABLE_SEARCH,
627                                      g_param_spec_boolean ("enable-search",
628                                                            P_("Enable Search"),
629                                                            P_("View allows user to search through columns interactively"),
630                                                            TRUE,
631                                                            GTK_PARAM_READWRITE));
632
633     g_object_class_install_property (o_class,
634                                      PROP_SEARCH_COLUMN,
635                                      g_param_spec_int ("search-column",
636                                                        P_("Search Column"),
637                                                        P_("Model column to search through during interactive search"),
638                                                        -1,
639                                                        G_MAXINT,
640                                                        -1,
641                                                        GTK_PARAM_READWRITE));
642
643     /**
644      * GtkTreeView:fixed-height-mode:
645      *
646      * Setting the ::fixed-height-mode property to %TRUE speeds up 
647      * #GtkTreeView by assuming that all rows have the same height. 
648      * Only enable this option if all rows are the same height.  
649      * Please see gtk_tree_view_set_fixed_height_mode() for more 
650      * information on this option.
651      *
652      * Since: 2.4
653      **/
654     g_object_class_install_property (o_class,
655                                      PROP_FIXED_HEIGHT_MODE,
656                                      g_param_spec_boolean ("fixed-height-mode",
657                                                            P_("Fixed Height Mode"),
658                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
659                                                            FALSE,
660                                                            GTK_PARAM_READWRITE));
661     
662     /**
663      * GtkTreeView:hover-selection:
664      * 
665      * Enables or disables the hover selection mode of @tree_view.
666      * Hover selection makes the selected row follow the pointer.
667      * Currently, this works only for the selection modes 
668      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
669      *
670      * This mode is primarily intended for treeviews in popups, e.g.
671      * in #GtkComboBox or #GtkEntryCompletion.
672      *
673      * Since: 2.6
674      */
675     g_object_class_install_property (o_class,
676                                      PROP_HOVER_SELECTION,
677                                      g_param_spec_boolean ("hover-selection",
678                                                            P_("Hover Selection"),
679                                                            P_("Whether the selection should follow the pointer"),
680                                                            FALSE,
681                                                            GTK_PARAM_READWRITE));
682
683     /**
684      * GtkTreeView:hover-expand:
685      * 
686      * Enables or disables the hover expansion mode of @tree_view.
687      * Hover expansion makes rows expand or collapse if the pointer moves 
688      * over them.
689      *
690      * This mode is primarily intended for treeviews in popups, e.g.
691      * in #GtkComboBox or #GtkEntryCompletion.
692      *
693      * Since: 2.6
694      */
695     g_object_class_install_property (o_class,
696                                      PROP_HOVER_EXPAND,
697                                      g_param_spec_boolean ("hover-expand",
698                                                            P_("Hover Expand"),
699                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
700                                                            FALSE,
701                                                            GTK_PARAM_READWRITE));
702
703     /**
704      * GtkTreeView:show-expanders:
705      *
706      * %TRUE if the view has expanders.
707      *
708      * Since: 2.12
709      */
710     g_object_class_install_property (o_class,
711                                      PROP_SHOW_EXPANDERS,
712                                      g_param_spec_boolean ("show-expanders",
713                                                            P_("Show Expanders"),
714                                                            P_("View has expanders"),
715                                                            TRUE,
716                                                            GTK_PARAM_READWRITE));
717
718     /**
719      * GtkTreeView:level-indentation:
720      *
721      * Extra indentation for each level.
722      *
723      * Since: 2.12
724      */
725     g_object_class_install_property (o_class,
726                                      PROP_LEVEL_INDENTATION,
727                                      g_param_spec_int ("level-indentation",
728                                                        P_("Level Indentation"),
729                                                        P_("Extra indentation for each level"),
730                                                        0,
731                                                        G_MAXINT,
732                                                        0,
733                                                        GTK_PARAM_READWRITE));
734
735     g_object_class_install_property (o_class,
736                                      PROP_RUBBER_BANDING,
737                                      g_param_spec_boolean ("rubber-banding",
738                                                            P_("Rubber Banding"),
739                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
740                                                            FALSE,
741                                                            GTK_PARAM_READWRITE));
742
743     g_object_class_install_property (o_class,
744                                      PROP_ENABLE_GRID_LINES,
745                                      g_param_spec_enum ("enable-grid-lines",
746                                                         P_("Enable Grid Lines"),
747                                                         P_("Whether grid lines should be drawn in the tree view"),
748                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
749                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
750                                                         GTK_PARAM_READWRITE));
751
752     g_object_class_install_property (o_class,
753                                      PROP_ENABLE_TREE_LINES,
754                                      g_param_spec_boolean ("enable-tree-lines",
755                                                            P_("Enable Tree Lines"),
756                                                            P_("Whether tree lines should be drawn in the tree view"),
757                                                            FALSE,
758                                                            GTK_PARAM_READWRITE));
759
760     g_object_class_install_property (o_class,
761                                      PROP_TOOLTIP_COLUMN,
762                                      g_param_spec_int ("tooltip-column",
763                                                        P_("Tooltip Column"),
764                                                        P_("The column in the model containing the tooltip texts for the rows"),
765                                                        -1,
766                                                        G_MAXINT,
767                                                        -1,
768                                                        GTK_PARAM_READWRITE));
769
770   /* Style properties */
771 #define _TREE_VIEW_EXPANDER_SIZE 12
772 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
773 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
774
775   gtk_widget_class_install_style_property (widget_class,
776                                            g_param_spec_int ("expander-size",
777                                                              P_("Expander Size"),
778                                                              P_("Size of the expander arrow"),
779                                                              0,
780                                                              G_MAXINT,
781                                                              _TREE_VIEW_EXPANDER_SIZE,
782                                                              GTK_PARAM_READABLE));
783
784   gtk_widget_class_install_style_property (widget_class,
785                                            g_param_spec_int ("vertical-separator",
786                                                              P_("Vertical Separator Width"),
787                                                              P_("Vertical space between cells.  Must be an even number"),
788                                                              0,
789                                                              G_MAXINT,
790                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
791                                                              GTK_PARAM_READABLE));
792
793   gtk_widget_class_install_style_property (widget_class,
794                                            g_param_spec_int ("horizontal-separator",
795                                                              P_("Horizontal Separator Width"),
796                                                              P_("Horizontal space between cells.  Must be an even number"),
797                                                              0,
798                                                              G_MAXINT,
799                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
800                                                              GTK_PARAM_READABLE));
801
802   gtk_widget_class_install_style_property (widget_class,
803                                            g_param_spec_boolean ("allow-rules",
804                                                                  P_("Allow Rules"),
805                                                                  P_("Allow drawing of alternating color rows"),
806                                                                  TRUE,
807                                                                  GTK_PARAM_READABLE));
808
809   gtk_widget_class_install_style_property (widget_class,
810                                            g_param_spec_boolean ("indent-expanders",
811                                                                  P_("Indent Expanders"),
812                                                                  P_("Make the expanders indented"),
813                                                                  TRUE,
814                                                                  GTK_PARAM_READABLE));
815
816   gtk_widget_class_install_style_property (widget_class,
817                                            g_param_spec_boxed ("even-row-color",
818                                                                P_("Even Row Color"),
819                                                                P_("Color to use for even rows"),
820                                                                GDK_TYPE_COLOR,
821                                                                GTK_PARAM_READABLE));
822
823   gtk_widget_class_install_style_property (widget_class,
824                                            g_param_spec_boxed ("odd-row-color",
825                                                                P_("Odd Row Color"),
826                                                                P_("Color to use for odd rows"),
827                                                                GDK_TYPE_COLOR,
828                                                                GTK_PARAM_READABLE));
829
830   gtk_widget_class_install_style_property (widget_class,
831                                            g_param_spec_int ("grid-line-width",
832                                                              P_("Grid line width"),
833                                                              P_("Width, in pixels, of the tree view grid lines"),
834                                                              0, G_MAXINT, 1,
835                                                              GTK_PARAM_READABLE));
836
837   gtk_widget_class_install_style_property (widget_class,
838                                            g_param_spec_int ("tree-line-width",
839                                                              P_("Tree line width"),
840                                                              P_("Width, in pixels, of the tree view lines"),
841                                                              0, G_MAXINT, 1,
842                                                              GTK_PARAM_READABLE));
843
844   gtk_widget_class_install_style_property (widget_class,
845                                            g_param_spec_string ("grid-line-pattern",
846                                                                 P_("Grid line pattern"),
847                                                                 P_("Dash pattern used to draw the tree view grid lines"),
848                                                                 "\1\1",
849                                                                 GTK_PARAM_READABLE));
850
851   gtk_widget_class_install_style_property (widget_class,
852                                            g_param_spec_string ("tree-line-pattern",
853                                                                 P_("Tree line pattern"),
854                                                                 P_("Dash pattern used to draw the tree view lines"),
855                                                                 "\1\1",
856                                                                 GTK_PARAM_READABLE));
857
858   /* Signals */
859   /**
860    * GtkTreeView::row-activated:
861    * @tree_view: the object on which the signal is emitted
862    * @path: the #GtkTreePath for the activated row
863    * @column: the #GtkTreeViewColumn in which the activation occurred
864    *
865    * The "row-activated" signal is emitted when the method
866    * gtk_tree_view_row_activated() is called or the user double clicks 
867    * a treeview row. It is also emitted when a non-editable row is 
868    * selected and one of the keys: Space, Shift+Space, Return or 
869    * Enter is pressed.
870    * 
871    * For selection handling refer to the <link linkend="TreeWidget">tree 
872    * widget conceptual overview</link> as well as #GtkTreeSelection.
873    */
874   tree_view_signals[ROW_ACTIVATED] =
875     g_signal_new (I_("row-activated"),
876                   G_TYPE_FROM_CLASS (o_class),
877                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
878                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
879                   NULL, NULL,
880                   _gtk_marshal_VOID__BOXED_OBJECT,
881                   G_TYPE_NONE, 2,
882                   GTK_TYPE_TREE_PATH,
883                   GTK_TYPE_TREE_VIEW_COLUMN);
884
885   /**
886    * GtkTreeView::test-expand-row:
887    * @tree_view: the object on which the signal is emitted
888    * @iter: the tree iter of the row to expand
889    * @path: a tree path that points to the row 
890    * 
891    * The given row is about to be expanded (show its children nodes). Use this
892    * signal if you need to control the expandability of individual rows.
893    *
894    * Returns: %FALSE to allow expansion, %TRUE to reject
895    */
896   tree_view_signals[TEST_EXPAND_ROW] =
897     g_signal_new (I_("test-expand-row"),
898                   G_TYPE_FROM_CLASS (o_class),
899                   G_SIGNAL_RUN_LAST,
900                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
901                   _gtk_boolean_handled_accumulator, NULL,
902                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
903                   G_TYPE_BOOLEAN, 2,
904                   GTK_TYPE_TREE_ITER,
905                   GTK_TYPE_TREE_PATH);
906
907   /**
908    * GtkTreeView::test-collapse-row:
909    * @tree_view: the object on which the signal is emitted
910    * @iter: the tree iter of the row to collapse
911    * @path: a tree path that points to the row 
912    * 
913    * The given row is about to be collapsed (hide its children nodes). Use this
914    * signal if you need to control the collapsibility of individual rows.
915    *
916    * Returns: %FALSE to allow collapsing, %TRUE to reject
917    */
918   tree_view_signals[TEST_COLLAPSE_ROW] =
919     g_signal_new (I_("test-collapse-row"),
920                   G_TYPE_FROM_CLASS (o_class),
921                   G_SIGNAL_RUN_LAST,
922                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
923                   _gtk_boolean_handled_accumulator, NULL,
924                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
925                   G_TYPE_BOOLEAN, 2,
926                   GTK_TYPE_TREE_ITER,
927                   GTK_TYPE_TREE_PATH);
928
929   /**
930    * GtkTreeView::row-expanded:
931    * @tree_view: the object on which the signal is emitted
932    * @iter: the tree iter of the expanded row
933    * @path: a tree path that points to the row 
934    * 
935    * The given row has been expanded (child nodes are shown).
936    */
937   tree_view_signals[ROW_EXPANDED] =
938     g_signal_new (I_("row-expanded"),
939                   G_TYPE_FROM_CLASS (o_class),
940                   G_SIGNAL_RUN_LAST,
941                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
942                   NULL, NULL,
943                   _gtk_marshal_VOID__BOXED_BOXED,
944                   G_TYPE_NONE, 2,
945                   GTK_TYPE_TREE_ITER,
946                   GTK_TYPE_TREE_PATH);
947
948   /**
949    * GtkTreeView::row-collapsed:
950    * @tree_view: the object on which the signal is emitted
951    * @iter: the tree iter of the collapsed row
952    * @path: a tree path that points to the row 
953    * 
954    * The given row has been collapsed (child nodes are hidden).
955    */
956   tree_view_signals[ROW_COLLAPSED] =
957     g_signal_new (I_("row-collapsed"),
958                   G_TYPE_FROM_CLASS (o_class),
959                   G_SIGNAL_RUN_LAST,
960                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
961                   NULL, NULL,
962                   _gtk_marshal_VOID__BOXED_BOXED,
963                   G_TYPE_NONE, 2,
964                   GTK_TYPE_TREE_ITER,
965                   GTK_TYPE_TREE_PATH);
966
967   /**
968    * GtkTreeView::columns-changed:
969    * @tree_view: the object on which the signal is emitted 
970    * 
971    * The number of columns of the treeview has changed.
972    */
973   tree_view_signals[COLUMNS_CHANGED] =
974     g_signal_new (I_("columns-changed"),
975                   G_TYPE_FROM_CLASS (o_class),
976                   G_SIGNAL_RUN_LAST,
977                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
978                   NULL, NULL,
979                   _gtk_marshal_VOID__VOID,
980                   G_TYPE_NONE, 0);
981
982   /**
983    * GtkTreeView::cursor-changed:
984    * @tree_view: the object on which the signal is emitted
985    * 
986    * The position of the cursor (focused cell) has changed.
987    */
988   tree_view_signals[CURSOR_CHANGED] =
989     g_signal_new (I_("cursor-changed"),
990                   G_TYPE_FROM_CLASS (o_class),
991                   G_SIGNAL_RUN_LAST,
992                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
993                   NULL, NULL,
994                   _gtk_marshal_VOID__VOID,
995                   G_TYPE_NONE, 0);
996
997   tree_view_signals[MOVE_CURSOR] =
998     g_signal_new (I_("move-cursor"),
999                   G_TYPE_FROM_CLASS (o_class),
1000                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1001                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1002                   NULL, NULL,
1003                   _gtk_marshal_BOOLEAN__ENUM_INT,
1004                   G_TYPE_BOOLEAN, 2,
1005                   GTK_TYPE_MOVEMENT_STEP,
1006                   G_TYPE_INT);
1007
1008   tree_view_signals[SELECT_ALL] =
1009     g_signal_new (I_("select-all"),
1010                   G_TYPE_FROM_CLASS (o_class),
1011                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1012                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1013                   NULL, NULL,
1014                   _gtk_marshal_BOOLEAN__VOID,
1015                   G_TYPE_BOOLEAN, 0);
1016
1017   tree_view_signals[UNSELECT_ALL] =
1018     g_signal_new (I_("unselect-all"),
1019                   G_TYPE_FROM_CLASS (o_class),
1020                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1021                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1022                   NULL, NULL,
1023                   _gtk_marshal_BOOLEAN__VOID,
1024                   G_TYPE_BOOLEAN, 0);
1025
1026   tree_view_signals[SELECT_CURSOR_ROW] =
1027     g_signal_new (I_("select-cursor-row"),
1028                   G_TYPE_FROM_CLASS (o_class),
1029                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1030                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1031                   NULL, NULL,
1032                   _gtk_marshal_BOOLEAN__BOOLEAN,
1033                   G_TYPE_BOOLEAN, 1,
1034                   G_TYPE_BOOLEAN);
1035
1036   tree_view_signals[TOGGLE_CURSOR_ROW] =
1037     g_signal_new (I_("toggle-cursor-row"),
1038                   G_TYPE_FROM_CLASS (o_class),
1039                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1040                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1041                   NULL, NULL,
1042                   _gtk_marshal_BOOLEAN__VOID,
1043                   G_TYPE_BOOLEAN, 0);
1044
1045   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1046     g_signal_new (I_("expand-collapse-cursor-row"),
1047                   G_TYPE_FROM_CLASS (o_class),
1048                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1049                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1050                   NULL, NULL,
1051                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1052                   G_TYPE_BOOLEAN, 3,
1053                   G_TYPE_BOOLEAN,
1054                   G_TYPE_BOOLEAN,
1055                   G_TYPE_BOOLEAN);
1056
1057   tree_view_signals[SELECT_CURSOR_PARENT] =
1058     g_signal_new (I_("select-cursor-parent"),
1059                   G_TYPE_FROM_CLASS (o_class),
1060                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1061                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1062                   NULL, NULL,
1063                   _gtk_marshal_BOOLEAN__VOID,
1064                   G_TYPE_BOOLEAN, 0);
1065
1066   tree_view_signals[START_INTERACTIVE_SEARCH] =
1067     g_signal_new (I_("start-interactive-search"),
1068                   G_TYPE_FROM_CLASS (o_class),
1069                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1070                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1071                   NULL, NULL,
1072                   _gtk_marshal_BOOLEAN__VOID,
1073                   G_TYPE_BOOLEAN, 0);
1074
1075   /* Key bindings */
1076   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1077                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1078   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1079                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1080
1081   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1082                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1083   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1084                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1085
1086   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1087                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1088
1089   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1090                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1091
1092   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1093                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1094   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1095                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1096
1097   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1098                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1099   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1100                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1101
1102   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1103                                   GTK_MOVEMENT_PAGES, -1);
1104   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1105                                   GTK_MOVEMENT_PAGES, -1);
1106
1107   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1108                                   GTK_MOVEMENT_PAGES, 1);
1109   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1110                                   GTK_MOVEMENT_PAGES, 1);
1111
1112
1113   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1114                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1115                                 G_TYPE_INT, 1);
1116
1117   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1118                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1119                                 G_TYPE_INT, -1);
1120
1121   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1122                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1123                                 G_TYPE_INT, 1);
1124
1125   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1126                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1127                                 G_TYPE_INT, -1);
1128
1129   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1130                                 "move-cursor", 2,
1131                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1132                                 G_TYPE_INT, 1);
1133
1134   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1135                                 "move-cursor", 2,
1136                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1137                                 G_TYPE_INT, -1);
1138
1139   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1140                                 "move-cursor", 2,
1141                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1142                                 G_TYPE_INT, 1);
1143
1144   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1145                                 "move-cursor", 2,
1146                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1147                                 G_TYPE_INT, -1);
1148
1149   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1150   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1151
1152   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1153   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1154
1155   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1156   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1157
1158   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1159                                 G_TYPE_BOOLEAN, TRUE);
1160   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1161                                 G_TYPE_BOOLEAN, TRUE);
1162
1163   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1164                                 G_TYPE_BOOLEAN, TRUE);
1165   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1166                                 G_TYPE_BOOLEAN, TRUE);
1167   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1168                                 G_TYPE_BOOLEAN, TRUE);
1169   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1170                                 G_TYPE_BOOLEAN, TRUE);
1171   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1172                                 G_TYPE_BOOLEAN, TRUE);
1173
1174   /* expand and collapse rows */
1175   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1176                                 G_TYPE_BOOLEAN, TRUE,
1177                                 G_TYPE_BOOLEAN, TRUE,
1178                                 G_TYPE_BOOLEAN, FALSE);
1179
1180   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1181                                 "expand-collapse-cursor-row", 3,
1182                                 G_TYPE_BOOLEAN, TRUE,
1183                                 G_TYPE_BOOLEAN, TRUE,
1184                                 G_TYPE_BOOLEAN, TRUE);
1185   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1186                                 "expand-collapse-cursor-row", 3,
1187                                 G_TYPE_BOOLEAN, TRUE,
1188                                 G_TYPE_BOOLEAN, TRUE,
1189                                 G_TYPE_BOOLEAN, TRUE);
1190
1191   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1192                                 "expand-collapse-cursor-row", 3,
1193                                 G_TYPE_BOOLEAN, TRUE,
1194                                 G_TYPE_BOOLEAN, FALSE,
1195                                 G_TYPE_BOOLEAN, FALSE);
1196   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1197                                 "expand-collapse-cursor-row", 3,
1198                                 G_TYPE_BOOLEAN, TRUE,
1199                                 G_TYPE_BOOLEAN, FALSE,
1200                                 G_TYPE_BOOLEAN, FALSE);
1201
1202   /* Not doable on US keyboards */
1203   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1204                                 G_TYPE_BOOLEAN, TRUE,
1205                                 G_TYPE_BOOLEAN, TRUE,
1206                                 G_TYPE_BOOLEAN, TRUE);
1207   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1208                                 G_TYPE_BOOLEAN, TRUE,
1209                                 G_TYPE_BOOLEAN, TRUE,
1210                                 G_TYPE_BOOLEAN, FALSE);
1211   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1212                                 G_TYPE_BOOLEAN, TRUE,
1213                                 G_TYPE_BOOLEAN, TRUE,
1214                                 G_TYPE_BOOLEAN, TRUE);
1215   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1216                                 G_TYPE_BOOLEAN, TRUE,
1217                                 G_TYPE_BOOLEAN, TRUE,
1218                                 G_TYPE_BOOLEAN, TRUE);
1219   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1220                                 "expand-collapse-cursor-row", 3,
1221                                 G_TYPE_BOOLEAN, FALSE,
1222                                 G_TYPE_BOOLEAN, TRUE,
1223                                 G_TYPE_BOOLEAN, TRUE);
1224   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1225                                 "expand-collapse-cursor-row", 3,
1226                                 G_TYPE_BOOLEAN, FALSE,
1227                                 G_TYPE_BOOLEAN, TRUE,
1228                                 G_TYPE_BOOLEAN, TRUE);
1229   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1230                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1231                                 "expand-collapse-cursor-row", 3,
1232                                 G_TYPE_BOOLEAN, FALSE,
1233                                 G_TYPE_BOOLEAN, TRUE,
1234                                 G_TYPE_BOOLEAN, TRUE);
1235   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1236                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1237                                 "expand-collapse-cursor-row", 3,
1238                                 G_TYPE_BOOLEAN, FALSE,
1239                                 G_TYPE_BOOLEAN, TRUE,
1240                                 G_TYPE_BOOLEAN, TRUE);
1241
1242   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1243                                 G_TYPE_BOOLEAN, TRUE,
1244                                 G_TYPE_BOOLEAN, FALSE,
1245                                 G_TYPE_BOOLEAN, FALSE);
1246   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1247                                 G_TYPE_BOOLEAN, TRUE,
1248                                 G_TYPE_BOOLEAN, FALSE,
1249                                 G_TYPE_BOOLEAN, TRUE);
1250   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1251                                 G_TYPE_BOOLEAN, TRUE,
1252                                 G_TYPE_BOOLEAN, FALSE,
1253                                 G_TYPE_BOOLEAN, FALSE);
1254   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1255                                 G_TYPE_BOOLEAN, TRUE,
1256                                 G_TYPE_BOOLEAN, FALSE,
1257                                 G_TYPE_BOOLEAN, TRUE);
1258   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1259                                 "expand-collapse-cursor-row", 3,
1260                                 G_TYPE_BOOLEAN, FALSE,
1261                                 G_TYPE_BOOLEAN, FALSE,
1262                                 G_TYPE_BOOLEAN, TRUE);
1263   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1264                                 "expand-collapse-cursor-row", 3,
1265                                 G_TYPE_BOOLEAN, FALSE,
1266                                 G_TYPE_BOOLEAN, FALSE,
1267                                 G_TYPE_BOOLEAN, TRUE);
1268   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1269                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1270                                 "expand-collapse-cursor-row", 3,
1271                                 G_TYPE_BOOLEAN, FALSE,
1272                                 G_TYPE_BOOLEAN, FALSE,
1273                                 G_TYPE_BOOLEAN, TRUE);
1274   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1275                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1276                                 "expand-collapse-cursor-row", 3,
1277                                 G_TYPE_BOOLEAN, FALSE,
1278                                 G_TYPE_BOOLEAN, FALSE,
1279                                 G_TYPE_BOOLEAN, TRUE);
1280
1281   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1282   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1283
1284   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1285
1286   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1287
1288   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1289 }
1290
1291 static void
1292 gtk_tree_view_init (GtkTreeView *tree_view)
1293 {
1294   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1295
1296   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1297   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1298
1299   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1300                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1301                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1302
1303   /* We need some padding */
1304   tree_view->priv->dy = 0;
1305   tree_view->priv->cursor_offset = 0;
1306   tree_view->priv->n_columns = 0;
1307   tree_view->priv->header_height = 1;
1308   tree_view->priv->x_drag = 0;
1309   tree_view->priv->drag_pos = -1;
1310   tree_view->priv->header_has_focus = FALSE;
1311   tree_view->priv->pressed_button = -1;
1312   tree_view->priv->press_start_x = -1;
1313   tree_view->priv->press_start_y = -1;
1314   tree_view->priv->reorderable = FALSE;
1315   tree_view->priv->presize_handler_timer = 0;
1316   tree_view->priv->scroll_sync_timer = 0;
1317   tree_view->priv->fixed_height = -1;
1318   tree_view->priv->fixed_height_mode = FALSE;
1319   tree_view->priv->fixed_height_check = 0;
1320   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1321   tree_view->priv->enable_search = TRUE;
1322   tree_view->priv->search_column = -1;
1323   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1324   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1325   tree_view->priv->search_custom_entry_set = FALSE;
1326   tree_view->priv->typeselect_flush_timeout = 0;
1327   tree_view->priv->init_hadjust_value = TRUE;    
1328   tree_view->priv->width = 0;
1329           
1330   tree_view->priv->hover_selection = FALSE;
1331   tree_view->priv->hover_expand = FALSE;
1332
1333   tree_view->priv->level_indentation = 0;
1334
1335   tree_view->priv->rubber_banding_enable = FALSE;
1336
1337   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1338   tree_view->priv->tree_lines_enabled = FALSE;
1339
1340   tree_view->priv->tooltip_column = -1;
1341
1342   tree_view->priv->post_validation_flag = FALSE;
1343
1344   tree_view->priv->last_button_x = -1;
1345   tree_view->priv->last_button_y = -1;
1346
1347   tree_view->priv->event_last_x = -10000;
1348   tree_view->priv->event_last_y = -10000;
1349
1350   gtk_tree_view_set_vadjustment (tree_view, NULL);
1351   gtk_tree_view_set_hadjustment (tree_view, NULL);
1352 }
1353
1354 \f
1355
1356 /* GObject Methods
1357  */
1358
1359 static void
1360 gtk_tree_view_set_property (GObject         *object,
1361                             guint            prop_id,
1362                             const GValue    *value,
1363                             GParamSpec      *pspec)
1364 {
1365   GtkTreeView *tree_view;
1366
1367   tree_view = GTK_TREE_VIEW (object);
1368
1369   switch (prop_id)
1370     {
1371     case PROP_MODEL:
1372       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1373       break;
1374     case PROP_HADJUSTMENT:
1375       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1376       break;
1377     case PROP_VADJUSTMENT:
1378       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1379       break;
1380     case PROP_HSCROLL_POLICY:
1381       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1382       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1383       break;
1384     case PROP_VSCROLL_POLICY:
1385       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1386       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1387       break;
1388     case PROP_HEADERS_VISIBLE:
1389       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1390       break;
1391     case PROP_HEADERS_CLICKABLE:
1392       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1393       break;
1394     case PROP_EXPANDER_COLUMN:
1395       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1396       break;
1397     case PROP_REORDERABLE:
1398       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1399       break;
1400     case PROP_RULES_HINT:
1401       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1402       break;
1403     case PROP_ENABLE_SEARCH:
1404       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1405       break;
1406     case PROP_SEARCH_COLUMN:
1407       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1408       break;
1409     case PROP_FIXED_HEIGHT_MODE:
1410       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1411       break;
1412     case PROP_HOVER_SELECTION:
1413       tree_view->priv->hover_selection = g_value_get_boolean (value);
1414       break;
1415     case PROP_HOVER_EXPAND:
1416       tree_view->priv->hover_expand = g_value_get_boolean (value);
1417       break;
1418     case PROP_SHOW_EXPANDERS:
1419       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1420       break;
1421     case PROP_LEVEL_INDENTATION:
1422       tree_view->priv->level_indentation = g_value_get_int (value);
1423       break;
1424     case PROP_RUBBER_BANDING:
1425       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1426       break;
1427     case PROP_ENABLE_GRID_LINES:
1428       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1429       break;
1430     case PROP_ENABLE_TREE_LINES:
1431       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1432       break;
1433     case PROP_TOOLTIP_COLUMN:
1434       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1435       break;
1436     default:
1437       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1438       break;
1439     }
1440 }
1441
1442 static void
1443 gtk_tree_view_get_property (GObject    *object,
1444                             guint       prop_id,
1445                             GValue     *value,
1446                             GParamSpec *pspec)
1447 {
1448   GtkTreeView *tree_view;
1449
1450   tree_view = GTK_TREE_VIEW (object);
1451
1452   switch (prop_id)
1453     {
1454     case PROP_MODEL:
1455       g_value_set_object (value, tree_view->priv->model);
1456       break;
1457     case PROP_HADJUSTMENT:
1458       g_value_set_object (value, tree_view->priv->hadjustment);
1459       break;
1460     case PROP_VADJUSTMENT:
1461       g_value_set_object (value, tree_view->priv->vadjustment);
1462       break;
1463     case PROP_HSCROLL_POLICY:
1464       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1465       break;
1466     case PROP_VSCROLL_POLICY:
1467       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1468       break;
1469     case PROP_HEADERS_VISIBLE:
1470       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1471       break;
1472     case PROP_HEADERS_CLICKABLE:
1473       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1474       break;
1475     case PROP_EXPANDER_COLUMN:
1476       g_value_set_object (value, tree_view->priv->expander_column);
1477       break;
1478     case PROP_REORDERABLE:
1479       g_value_set_boolean (value, tree_view->priv->reorderable);
1480       break;
1481     case PROP_RULES_HINT:
1482       g_value_set_boolean (value, tree_view->priv->has_rules);
1483       break;
1484     case PROP_ENABLE_SEARCH:
1485       g_value_set_boolean (value, tree_view->priv->enable_search);
1486       break;
1487     case PROP_SEARCH_COLUMN:
1488       g_value_set_int (value, tree_view->priv->search_column);
1489       break;
1490     case PROP_FIXED_HEIGHT_MODE:
1491       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1492       break;
1493     case PROP_HOVER_SELECTION:
1494       g_value_set_boolean (value, tree_view->priv->hover_selection);
1495       break;
1496     case PROP_HOVER_EXPAND:
1497       g_value_set_boolean (value, tree_view->priv->hover_expand);
1498       break;
1499     case PROP_SHOW_EXPANDERS:
1500       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1501       break;
1502     case PROP_LEVEL_INDENTATION:
1503       g_value_set_int (value, tree_view->priv->level_indentation);
1504       break;
1505     case PROP_RUBBER_BANDING:
1506       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1507       break;
1508     case PROP_ENABLE_GRID_LINES:
1509       g_value_set_enum (value, tree_view->priv->grid_lines);
1510       break;
1511     case PROP_ENABLE_TREE_LINES:
1512       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1513       break;
1514     case PROP_TOOLTIP_COLUMN:
1515       g_value_set_int (value, tree_view->priv->tooltip_column);
1516       break;
1517     default:
1518       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1519       break;
1520     }
1521 }
1522
1523 static void
1524 gtk_tree_view_finalize (GObject *object)
1525 {
1526   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1527 }
1528
1529
1530 static GtkBuildableIface *parent_buildable_iface;
1531
1532 static void
1533 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1534 {
1535   parent_buildable_iface = g_type_interface_peek_parent (iface);
1536   iface->add_child = gtk_tree_view_buildable_add_child;
1537   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1538 }
1539
1540 static void
1541 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1542                                    GtkBuilder  *builder,
1543                                    GObject     *child,
1544                                    const gchar *type)
1545 {
1546   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1547 }
1548
1549 static GObject *
1550 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1551                                             GtkBuilder        *builder,
1552                                             const gchar       *childname)
1553 {
1554     if (strcmp (childname, "selection") == 0)
1555       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1556     
1557     return parent_buildable_iface->get_internal_child (buildable,
1558                                                        builder,
1559                                                        childname);
1560 }
1561
1562 /* GtkWidget Methods
1563  */
1564
1565 static void
1566 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1567 {
1568   _gtk_rbtree_free (tree_view->priv->tree);
1569   
1570   tree_view->priv->tree = NULL;
1571   tree_view->priv->button_pressed_node = NULL;
1572   tree_view->priv->button_pressed_tree = NULL;
1573   tree_view->priv->prelight_tree = NULL;
1574   tree_view->priv->prelight_node = NULL;
1575   tree_view->priv->expanded_collapsed_node = NULL;
1576   tree_view->priv->expanded_collapsed_tree = NULL;
1577 }
1578
1579 static void
1580 gtk_tree_view_destroy (GtkWidget *widget)
1581 {
1582   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1583   GList *list;
1584
1585   gtk_tree_view_stop_editing (tree_view, TRUE);
1586
1587   if (tree_view->priv->columns != NULL)
1588     {
1589       list = tree_view->priv->columns;
1590       while (list)
1591         {
1592           GtkTreeViewColumn *column;
1593           column = GTK_TREE_VIEW_COLUMN (list->data);
1594           list = list->next;
1595           gtk_tree_view_remove_column (tree_view, column);
1596         }
1597       tree_view->priv->columns = NULL;
1598     }
1599
1600   if (tree_view->priv->tree != NULL)
1601     {
1602       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1603
1604       gtk_tree_view_free_rbtree (tree_view);
1605     }
1606
1607   if (tree_view->priv->selection != NULL)
1608     {
1609       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1610       g_object_unref (tree_view->priv->selection);
1611       tree_view->priv->selection = NULL;
1612     }
1613
1614   if (tree_view->priv->scroll_to_path != NULL)
1615     {
1616       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1617       tree_view->priv->scroll_to_path = NULL;
1618     }
1619
1620   if (tree_view->priv->drag_dest_row != NULL)
1621     {
1622       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1623       tree_view->priv->drag_dest_row = NULL;
1624     }
1625
1626   if (tree_view->priv->top_row != NULL)
1627     {
1628       gtk_tree_row_reference_free (tree_view->priv->top_row);
1629       tree_view->priv->top_row = NULL;
1630     }
1631
1632   if (tree_view->priv->column_drop_func_data &&
1633       tree_view->priv->column_drop_func_data_destroy)
1634     {
1635       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1636       tree_view->priv->column_drop_func_data = NULL;
1637     }
1638
1639   if (tree_view->priv->destroy_count_destroy &&
1640       tree_view->priv->destroy_count_data)
1641     {
1642       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1643       tree_view->priv->destroy_count_data = NULL;
1644     }
1645
1646   gtk_tree_row_reference_free (tree_view->priv->cursor);
1647   tree_view->priv->cursor = NULL;
1648
1649   gtk_tree_row_reference_free (tree_view->priv->anchor);
1650   tree_view->priv->anchor = NULL;
1651
1652   /* destroy interactive search dialog */
1653   if (tree_view->priv->search_window)
1654     {
1655       gtk_widget_destroy (tree_view->priv->search_window);
1656       tree_view->priv->search_window = NULL;
1657       tree_view->priv->search_entry = NULL;
1658       if (tree_view->priv->typeselect_flush_timeout)
1659         {
1660           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1661           tree_view->priv->typeselect_flush_timeout = 0;
1662         }
1663     }
1664
1665   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1666     {
1667       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1668       tree_view->priv->search_user_data = NULL;
1669     }
1670
1671   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1672     {
1673       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1674       tree_view->priv->search_position_user_data = NULL;
1675     }
1676
1677   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1678     {
1679       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1680       tree_view->priv->row_separator_data = NULL;
1681     }
1682   
1683   gtk_tree_view_set_model (tree_view, NULL);
1684
1685   if (tree_view->priv->hadjustment)
1686     {
1687       g_object_unref (tree_view->priv->hadjustment);
1688       tree_view->priv->hadjustment = NULL;
1689     }
1690   if (tree_view->priv->vadjustment)
1691     {
1692       g_object_unref (tree_view->priv->vadjustment);
1693       tree_view->priv->vadjustment = NULL;
1694     }
1695
1696   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
1697 }
1698
1699 /* GtkWidget::map helper */
1700 static void
1701 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1702 {
1703   GList *list;
1704
1705   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
1706
1707   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1708     {
1709       GtkTreeViewColumn *column;
1710
1711       for (list = tree_view->priv->columns; list; list = list->next)
1712         {
1713           column = list->data;
1714           if (gtk_widget_get_visible (column->button) &&
1715               !gtk_widget_get_mapped (column->button))
1716             gtk_widget_map (column->button);
1717         }
1718       for (list = tree_view->priv->columns; list; list = list->next)
1719         {
1720           column = list->data;
1721           if (column->visible == FALSE)
1722             continue;
1723           if (column->resizable)
1724             {
1725               gdk_window_raise (column->window);
1726               gdk_window_show (column->window);
1727             }
1728           else
1729             gdk_window_hide (column->window);
1730         }
1731       gdk_window_show (tree_view->priv->header_window);
1732     }
1733 }
1734
1735 static void
1736 gtk_tree_view_map (GtkWidget *widget)
1737 {
1738   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1739   GList *tmp_list;
1740
1741   gtk_widget_set_mapped (widget, TRUE);
1742
1743   tmp_list = tree_view->priv->children;
1744   while (tmp_list)
1745     {
1746       GtkTreeViewChild *child = tmp_list->data;
1747       tmp_list = tmp_list->next;
1748
1749       if (gtk_widget_get_visible (child->widget))
1750         {
1751           if (!gtk_widget_get_mapped (child->widget))
1752             gtk_widget_map (child->widget);
1753         }
1754     }
1755   gdk_window_show (tree_view->priv->bin_window);
1756
1757   gtk_tree_view_map_buttons (tree_view);
1758
1759   gdk_window_show (gtk_widget_get_window (widget));
1760 }
1761
1762 static void
1763 gtk_tree_view_realize (GtkWidget *widget)
1764 {
1765   GtkAllocation allocation;
1766   GtkStyle *style;
1767   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1768   GdkWindow *window;
1769   GdkWindowAttr attributes;
1770   GList *tmp_list;
1771   gint attributes_mask;
1772
1773   gtk_widget_set_realized (widget, TRUE);
1774
1775   gtk_widget_get_allocation (widget, &allocation);
1776
1777   /* Make the main, clipping window */
1778   attributes.window_type = GDK_WINDOW_CHILD;
1779   attributes.x = allocation.x;
1780   attributes.y = allocation.y;
1781   attributes.width = allocation.width;
1782   attributes.height = allocation.height;
1783   attributes.wclass = GDK_INPUT_OUTPUT;
1784   attributes.visual = gtk_widget_get_visual (widget);
1785   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1786
1787   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1788
1789   window = gdk_window_new (gtk_widget_get_parent_window (widget),
1790                            &attributes, attributes_mask);
1791   gtk_widget_set_window (widget, window);
1792   gdk_window_set_user_data (window, widget);
1793
1794   gtk_widget_get_allocation (widget, &allocation);
1795
1796   /* Make the window for the tree */
1797   attributes.x = 0;
1798   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1799   attributes.width = MAX (tree_view->priv->width, allocation.width);
1800   attributes.height = allocation.height;
1801   attributes.event_mask = (GDK_EXPOSURE_MASK |
1802                            GDK_SCROLL_MASK |
1803                            GDK_POINTER_MOTION_MASK |
1804                            GDK_ENTER_NOTIFY_MASK |
1805                            GDK_LEAVE_NOTIFY_MASK |
1806                            GDK_BUTTON_PRESS_MASK |
1807                            GDK_BUTTON_RELEASE_MASK |
1808                            gtk_widget_get_events (widget));
1809
1810   tree_view->priv->bin_window = gdk_window_new (window,
1811                                                 &attributes, attributes_mask);
1812   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1813
1814   gtk_widget_get_allocation (widget, &allocation);
1815
1816   /* Make the column header window */
1817   attributes.x = 0;
1818   attributes.y = 0;
1819   attributes.width = MAX (tree_view->priv->width, allocation.width);
1820   attributes.height = tree_view->priv->header_height;
1821   attributes.event_mask = (GDK_EXPOSURE_MASK |
1822                            GDK_SCROLL_MASK |
1823                            GDK_ENTER_NOTIFY_MASK |
1824                            GDK_LEAVE_NOTIFY_MASK |
1825                            GDK_BUTTON_PRESS_MASK |
1826                            GDK_BUTTON_RELEASE_MASK |
1827                            GDK_KEY_PRESS_MASK |
1828                            GDK_KEY_RELEASE_MASK |
1829                            gtk_widget_get_events (widget));
1830
1831   tree_view->priv->header_window = gdk_window_new (window,
1832                                                    &attributes, attributes_mask);
1833   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1834
1835   /* Add them all up. */
1836   gtk_widget_style_attach (widget);
1837   style = gtk_widget_get_style (widget);
1838   gdk_window_set_background (tree_view->priv->bin_window,
1839                              &style->base[gtk_widget_get_state (widget)]);
1840   gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1841
1842   tmp_list = tree_view->priv->children;
1843   while (tmp_list)
1844     {
1845       GtkTreeViewChild *child = tmp_list->data;
1846       tmp_list = tmp_list->next;
1847
1848       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1849     }
1850
1851   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1852     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1853
1854   /* Need to call those here, since they create GCs */
1855   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1856   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1857
1858   install_presize_handler (tree_view); 
1859 }
1860
1861 static void
1862 gtk_tree_view_unrealize (GtkWidget *widget)
1863 {
1864   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1865   GtkTreeViewPrivate *priv = tree_view->priv;
1866   GList *list;
1867
1868   if (priv->scroll_timeout != 0)
1869     {
1870       g_source_remove (priv->scroll_timeout);
1871       priv->scroll_timeout = 0;
1872     }
1873
1874   if (priv->auto_expand_timeout != 0)
1875     {
1876       g_source_remove (priv->auto_expand_timeout);
1877       priv->auto_expand_timeout = 0;
1878     }
1879
1880   if (priv->open_dest_timeout != 0)
1881     {
1882       g_source_remove (priv->open_dest_timeout);
1883       priv->open_dest_timeout = 0;
1884     }
1885
1886   remove_expand_collapse_timeout (tree_view);
1887   
1888   if (priv->presize_handler_timer != 0)
1889     {
1890       g_source_remove (priv->presize_handler_timer);
1891       priv->presize_handler_timer = 0;
1892     }
1893
1894   if (priv->validate_rows_timer != 0)
1895     {
1896       g_source_remove (priv->validate_rows_timer);
1897       priv->validate_rows_timer = 0;
1898     }
1899
1900   if (priv->scroll_sync_timer != 0)
1901     {
1902       g_source_remove (priv->scroll_sync_timer);
1903       priv->scroll_sync_timer = 0;
1904     }
1905
1906   if (priv->typeselect_flush_timeout)
1907     {
1908       g_source_remove (priv->typeselect_flush_timeout);
1909       priv->typeselect_flush_timeout = 0;
1910     }
1911   
1912   for (list = priv->columns; list; list = list->next)
1913     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1914
1915   gdk_window_set_user_data (priv->bin_window, NULL);
1916   gdk_window_destroy (priv->bin_window);
1917   priv->bin_window = NULL;
1918
1919   gdk_window_set_user_data (priv->header_window, NULL);
1920   gdk_window_destroy (priv->header_window);
1921   priv->header_window = NULL;
1922
1923   if (priv->drag_window)
1924     {
1925       gdk_window_set_user_data (priv->drag_window, NULL);
1926       gdk_window_destroy (priv->drag_window);
1927       priv->drag_window = NULL;
1928     }
1929
1930   if (priv->drag_highlight_window)
1931     {
1932       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1933       gdk_window_destroy (priv->drag_highlight_window);
1934       priv->drag_highlight_window = NULL;
1935     }
1936
1937   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1938 }
1939
1940 /* GtkWidget::size_request helper */
1941 static void
1942 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1943 {
1944   GList *list;
1945
1946   tree_view->priv->header_height = 0;
1947
1948   if (tree_view->priv->model)
1949     {
1950       for (list = tree_view->priv->columns; list; list = list->next)
1951         {
1952           GtkRequisition requisition;
1953           GtkTreeViewColumn *column = list->data;
1954
1955           if (column->button == NULL)
1956             continue;
1957
1958           column = list->data;
1959
1960           gtk_widget_get_preferred_size (column->button, &requisition, NULL);
1961           column->button_request = requisition.width;
1962           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1963         }
1964     }
1965 }
1966
1967
1968 /* Called only by ::size_request */
1969 static void
1970 gtk_tree_view_update_size (GtkTreeView *tree_view)
1971 {
1972   GList *list;
1973   GtkTreeViewColumn *column;
1974   gint i;
1975
1976   if (tree_view->priv->model == NULL)
1977     {
1978       tree_view->priv->width = 0;
1979       tree_view->priv->prev_width = 0;                   
1980       tree_view->priv->height = 0;
1981       return;
1982     }
1983
1984   tree_view->priv->prev_width = tree_view->priv->width;  
1985   tree_view->priv->width = 0;
1986
1987   /* keep this in sync with size_allocate below */
1988   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1989     {
1990       gint real_requested_width = 0;
1991       column = list->data;
1992       if (!column->visible)
1993         continue;
1994
1995       if (column->use_resized_width)
1996         {
1997           real_requested_width = column->resized_width;
1998         }
1999       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2000         {
2001           real_requested_width = column->fixed_width;
2002         }
2003       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2004         {
2005           real_requested_width = MAX (column->requested_width, column->button_request);
2006         }
2007       else
2008         {
2009           real_requested_width = column->requested_width;
2010         }
2011
2012       if (column->min_width != -1)
2013         real_requested_width = MAX (real_requested_width, column->min_width);
2014       if (column->max_width != -1)
2015         real_requested_width = MIN (real_requested_width, column->max_width);
2016
2017       tree_view->priv->width += real_requested_width;
2018     }
2019
2020   if (tree_view->priv->tree == NULL)
2021     tree_view->priv->height = 0;
2022   else
2023     tree_view->priv->height = tree_view->priv->tree->root->offset;
2024 }
2025
2026 static void
2027 gtk_tree_view_size_request (GtkWidget      *widget,
2028                             GtkRequisition *requisition)
2029 {
2030   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2031   GList *tmp_list;
2032
2033   /* we validate some rows initially just to make sure we have some size. 
2034    * In practice, with a lot of static lists, this should get a good width.
2035    */
2036   do_validate_rows (tree_view, FALSE);
2037   gtk_tree_view_size_request_columns (tree_view);
2038   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2039
2040   requisition->width = tree_view->priv->width;
2041   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2042
2043   tmp_list = tree_view->priv->children;
2044 }
2045
2046 static void
2047 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2048                                    gint      *minimum,
2049                                    gint      *natural)
2050 {
2051   GtkRequisition requisition;
2052
2053   gtk_tree_view_size_request (widget, &requisition);
2054
2055   *minimum = *natural = requisition.width;
2056 }
2057
2058 static void
2059 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2060                                     gint      *minimum,
2061                                     gint      *natural)
2062 {
2063   GtkRequisition requisition;
2064
2065   gtk_tree_view_size_request (widget, &requisition);
2066
2067   *minimum = *natural = requisition.height;
2068 }
2069
2070 static int
2071 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2072 {
2073   int width = 0;
2074   GList *list;
2075   gboolean rtl;
2076
2077   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2078   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2079        list->data != tree_view->priv->expander_column;
2080        list = (rtl ? list->prev : list->next))
2081     {
2082       GtkTreeViewColumn *column = list->data;
2083
2084       width += column->width;
2085     }
2086
2087   return width;
2088 }
2089
2090 static void
2091 invalidate_column (GtkTreeView       *tree_view,
2092                    GtkTreeViewColumn *column)
2093 {
2094   gint column_offset = 0;
2095   GList *list;
2096   GtkWidget *widget = GTK_WIDGET (tree_view);
2097   gboolean rtl;
2098
2099   if (!gtk_widget_get_realized (widget))
2100     return;
2101
2102   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2103   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2104        list;
2105        list = (rtl ? list->prev : list->next))
2106     {
2107       GtkTreeViewColumn *tmpcolumn = list->data;
2108       if (tmpcolumn == column)
2109         {
2110           GtkAllocation allocation;
2111           GdkRectangle invalid_rect;
2112
2113           gtk_widget_get_allocation (widget, &allocation);
2114           invalid_rect.x = column_offset;
2115           invalid_rect.y = 0;
2116           invalid_rect.width = column->width;
2117           invalid_rect.height = allocation.height;
2118
2119           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2120           break;
2121         }
2122       
2123       column_offset += tmpcolumn->width;
2124     }
2125 }
2126
2127 static void
2128 invalidate_last_column (GtkTreeView *tree_view)
2129 {
2130   GList *last_column;
2131   gboolean rtl;
2132
2133   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2134
2135   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2136        last_column;
2137        last_column = (rtl ? last_column->next : last_column->prev))
2138     {
2139       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2140         {
2141           invalidate_column (tree_view, last_column->data);
2142           return;
2143         }
2144     }
2145 }
2146
2147 static gint
2148 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2149                                                     GtkTreeViewColumn *column)
2150 {
2151   gint real_requested_width;
2152
2153   if (column->use_resized_width)
2154     {
2155       real_requested_width = column->resized_width;
2156     }
2157   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2158     {
2159       real_requested_width = column->fixed_width;
2160     }
2161   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2162     {
2163       real_requested_width = MAX (column->requested_width, column->button_request);
2164     }
2165   else
2166     {
2167       real_requested_width = column->requested_width;
2168       if (real_requested_width < 0)
2169         real_requested_width = 0;
2170     }
2171
2172   if (column->min_width != -1)
2173     real_requested_width = MAX (real_requested_width, column->min_width);
2174   if (column->max_width != -1)
2175     real_requested_width = MIN (real_requested_width, column->max_width);
2176
2177   return real_requested_width;
2178 }
2179
2180 /* GtkWidget::size_allocate helper */
2181 static void
2182 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2183                                      gboolean  *width_changed)
2184 {
2185   GtkTreeView *tree_view;
2186   GList *list, *first_column, *last_column;
2187   GtkTreeViewColumn *column;
2188   GtkAllocation allocation;
2189   GtkAllocation widget_allocation;
2190   gint width = 0;
2191   gint extra, extra_per_column, extra_for_last;
2192   gint full_requested_width = 0;
2193   gint number_of_expand_columns = 0;
2194   gboolean column_changed = FALSE;
2195   gboolean rtl;
2196   gboolean update_expand;
2197   
2198   tree_view = GTK_TREE_VIEW (widget);
2199
2200   for (last_column = g_list_last (tree_view->priv->columns);
2201        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2202        last_column = last_column->prev)
2203     ;
2204   if (last_column == NULL)
2205     return;
2206
2207   for (first_column = g_list_first (tree_view->priv->columns);
2208        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2209        first_column = first_column->next)
2210     ;
2211
2212   allocation.y = 0;
2213   allocation.height = tree_view->priv->header_height;
2214
2215   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2216
2217   /* find out how many extra space and expandable columns we have */
2218   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2219     {
2220       column = (GtkTreeViewColumn *)list->data;
2221
2222       if (!column->visible)
2223         continue;
2224
2225       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2226
2227       if (column->expand)
2228         number_of_expand_columns++;
2229     }
2230
2231   /* Only update the expand value if the width of the widget has changed,
2232    * or the number of expand columns has changed, or if there are no expand
2233    * columns, or if we didn't have an size-allocation yet after the
2234    * last validated node.
2235    */
2236   update_expand = (width_changed && *width_changed == TRUE)
2237       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2238       || number_of_expand_columns == 0
2239       || tree_view->priv->post_validation_flag == TRUE;
2240
2241   tree_view->priv->post_validation_flag = FALSE;
2242
2243   gtk_widget_get_allocation (widget, &widget_allocation);
2244   if (!update_expand)
2245     {
2246       extra = tree_view->priv->last_extra_space;
2247       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2248     }
2249   else
2250     {
2251       extra = MAX (widget_allocation.width - full_requested_width, 0);
2252       extra_for_last = 0;
2253
2254       tree_view->priv->last_extra_space = extra;
2255     }
2256
2257   if (number_of_expand_columns > 0)
2258     extra_per_column = extra/number_of_expand_columns;
2259   else
2260     extra_per_column = 0;
2261
2262   if (update_expand)
2263     {
2264       tree_view->priv->last_extra_space_per_column = extra_per_column;
2265       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2266     }
2267
2268   for (list = (rtl ? last_column : first_column); 
2269        list != (rtl ? first_column->prev : last_column->next);
2270        list = (rtl ? list->prev : list->next)) 
2271     {
2272       gint real_requested_width = 0;
2273       gint old_width;
2274
2275       column = list->data;
2276       old_width = column->width;
2277
2278       if (!column->visible)
2279         continue;
2280
2281       /* We need to handle the dragged button specially.
2282        */
2283       if (column == tree_view->priv->drag_column)
2284         {
2285           GtkAllocation drag_allocation;
2286
2287           drag_allocation.x = 0;
2288           drag_allocation.y = 0;
2289           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2290           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2291           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2292                                     &drag_allocation);
2293           width += drag_allocation.width;
2294           continue;
2295         }
2296
2297       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2298
2299       allocation.x = width;
2300       column->width = real_requested_width;
2301
2302       if (column->expand)
2303         {
2304           if (number_of_expand_columns == 1)
2305             {
2306               /* We add the remander to the last column as
2307                * */
2308               column->width += extra;
2309             }
2310           else
2311             {
2312               column->width += extra_per_column;
2313               extra -= extra_per_column;
2314               number_of_expand_columns --;
2315             }
2316         }
2317       else if (number_of_expand_columns == 0 &&
2318                list == last_column)
2319         {
2320           column->width += extra;
2321         }
2322
2323       /* In addition to expand, the last column can get even more
2324        * extra space so all available space is filled up.
2325        */
2326       if (extra_for_last > 0 && list == last_column)
2327         column->width += extra_for_last;
2328
2329       g_object_notify (G_OBJECT (column), "width");
2330
2331       allocation.width = column->width;
2332       width += column->width;
2333
2334       if (column->width > old_width)
2335         column_changed = TRUE;
2336
2337       gtk_widget_size_allocate (column->button, &allocation);
2338
2339       if (column->window)
2340         gdk_window_move_resize (column->window,
2341                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2342                                 allocation.y,
2343                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2344     }
2345
2346   /* We change the width here.  The user might have been resizing columns,
2347    * so the total width of the tree view changes.
2348    */
2349   tree_view->priv->width = width;
2350   if (width_changed)
2351     *width_changed = TRUE;
2352
2353   if (column_changed)
2354     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2355 }
2356
2357
2358 static void
2359 gtk_tree_view_size_allocate (GtkWidget     *widget,
2360                              GtkAllocation *allocation)
2361 {
2362   GtkAllocation widget_allocation;
2363   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2364   GList *tmp_list;
2365   gboolean width_changed = FALSE;
2366   gint old_width;
2367
2368   gtk_widget_get_allocation (widget, &widget_allocation);
2369   old_width = widget_allocation.width;
2370   if (allocation->width != widget_allocation.width)
2371     width_changed = TRUE;
2372
2373   gtk_widget_set_allocation (widget, allocation);
2374
2375   tmp_list = tree_view->priv->children;
2376
2377   while (tmp_list)
2378     {
2379       GtkAllocation allocation;
2380
2381       GtkTreeViewChild *child = tmp_list->data;
2382       tmp_list = tmp_list->next;
2383
2384       /* totally ignore our child's requisition */
2385       allocation.x = child->x;
2386       allocation.y = child->y;
2387       allocation.width = child->width;
2388       allocation.height = child->height;
2389       gtk_widget_size_allocate (child->widget, &allocation);
2390     }
2391
2392   /* We size-allocate the columns first because the width of the
2393    * tree view (used in updating the adjustments below) might change.
2394    */
2395   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2396
2397   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2398   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2399                                 allocation->width);
2400   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2401                                      allocation->width * 0.9);
2402   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2403                                      allocation->width * 0.1);
2404   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2405   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2406                             MAX (tree_view->priv->hadjustment->page_size,
2407                                  tree_view->priv->width));
2408   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2409
2410   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2411     {
2412       if (allocation->width < tree_view->priv->width)
2413         {
2414           if (tree_view->priv->init_hadjust_value)
2415             {
2416               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2417                                         MAX (tree_view->priv->width -
2418                                              allocation->width, 0));
2419               tree_view->priv->init_hadjust_value = FALSE;
2420             }
2421           else if (allocation->width != old_width)
2422             {
2423               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2424                                         CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width,
2425                                                0,
2426                                                tree_view->priv->width - allocation->width));
2427             }
2428           else
2429             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2430                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value),
2431                                              0,
2432                                              tree_view->priv->width - allocation->width));
2433         }
2434       else
2435         {
2436           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2437           tree_view->priv->init_hadjust_value = TRUE;
2438         }
2439     }
2440   else
2441     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2442       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2443                                 MAX (tree_view->priv->width -
2444                                      allocation->width, 0));
2445
2446   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2447   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2448                                 allocation->height -
2449                                 TREE_VIEW_HEADER_HEIGHT (tree_view));
2450   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2451                                      tree_view->priv->vadjustment->page_size * 0.1);
2452   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2453                                      tree_view->priv->vadjustment->page_size * 0.9);
2454   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2455   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2456                             MAX (tree_view->priv->vadjustment->page_size,
2457                                  tree_view->priv->height));
2458   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2459
2460   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2461   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2462     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2463   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2464     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2465                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2466   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2467     gtk_tree_view_top_row_to_dy (tree_view);
2468   else
2469     gtk_tree_view_dy_to_top_row (tree_view);
2470   
2471   if (gtk_widget_get_realized (widget))
2472     {
2473       gdk_window_move_resize (gtk_widget_get_window (widget),
2474                               allocation->x, allocation->y,
2475                               allocation->width, allocation->height);
2476       gdk_window_move_resize (tree_view->priv->header_window,
2477                               - (gint) tree_view->priv->hadjustment->value,
2478                               0,
2479                               MAX (tree_view->priv->width, allocation->width),
2480                               tree_view->priv->header_height);
2481       gdk_window_move_resize (tree_view->priv->bin_window,
2482                               - (gint) tree_view->priv->hadjustment->value,
2483                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2484                               MAX (tree_view->priv->width, allocation->width),
2485                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2486     }
2487
2488   if (tree_view->priv->tree == NULL)
2489     invalidate_empty_focus (tree_view);
2490
2491   if (gtk_widget_get_realized (widget))
2492     {
2493       gboolean has_expand_column = FALSE;
2494       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2495         {
2496           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2497             {
2498               has_expand_column = TRUE;
2499               break;
2500             }
2501         }
2502
2503       if (width_changed && tree_view->priv->expander_column)
2504         {
2505           /* Might seem awkward, but is the best heuristic I could come up
2506            * with.  Only if the width of the columns before the expander
2507            * changes, we will update the prelight status.  It is this
2508            * width that makes the expander move vertically.  Always updating
2509            * prelight status causes trouble with hover selections.
2510            */
2511           gint width_before_expander;
2512
2513           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2514
2515           if (tree_view->priv->prev_width_before_expander
2516               != width_before_expander)
2517               update_prelight (tree_view,
2518                                tree_view->priv->event_last_x,
2519                                tree_view->priv->event_last_y);
2520
2521           tree_view->priv->prev_width_before_expander = width_before_expander;
2522         }
2523
2524       /* This little hack only works if we have an LTR locale, and no column has the  */
2525       if (width_changed)
2526         {
2527           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2528               ! has_expand_column)
2529             invalidate_last_column (tree_view);
2530           else
2531             gtk_widget_queue_draw (widget);
2532         }
2533     }
2534 }
2535
2536 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2537 static void
2538 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2539 {
2540   GtkWidget *widget = GTK_WIDGET (tree_view);
2541
2542   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2543     gtk_widget_grab_focus (widget);
2544   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2545 }
2546
2547 static inline gboolean
2548 row_is_separator (GtkTreeView *tree_view,
2549                   GtkTreeIter *iter,
2550                   GtkTreePath *path)
2551 {
2552   gboolean is_separator = FALSE;
2553
2554   if (tree_view->priv->row_separator_func)
2555     {
2556       GtkTreeIter tmpiter;
2557
2558       if (iter)
2559         tmpiter = *iter;
2560       else
2561         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2562
2563       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2564                                                           &tmpiter,
2565                                                           tree_view->priv->row_separator_data);
2566     }
2567
2568   return is_separator;
2569 }
2570
2571 static gboolean
2572 gtk_tree_view_button_press (GtkWidget      *widget,
2573                             GdkEventButton *event)
2574 {
2575   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2576   GList *list;
2577   GtkTreeViewColumn *column = NULL;
2578   gint i;
2579   GdkRectangle background_area;
2580   GdkRectangle cell_area;
2581   gint vertical_separator;
2582   gint horizontal_separator;
2583   gboolean path_is_selectable;
2584   gboolean rtl;
2585
2586   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2587   gtk_tree_view_stop_editing (tree_view, FALSE);
2588   gtk_widget_style_get (widget,
2589                         "vertical-separator", &vertical_separator,
2590                         "horizontal-separator", &horizontal_separator,
2591                         NULL);
2592
2593
2594   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2595    * we're done handling the button press.
2596    */
2597
2598   if (event->window == tree_view->priv->bin_window)
2599     {
2600       GtkRBNode *node;
2601       GtkRBTree *tree;
2602       GtkTreePath *path;
2603       gchar *path_string;
2604       gint depth;
2605       gint new_y;
2606       gint y_offset;
2607       gint dval;
2608       gint pre_val, aft_val;
2609       GtkTreeViewColumn *column = NULL;
2610       GtkCellRenderer *focus_cell = NULL;
2611       gint column_handled_click = FALSE;
2612       gboolean row_double_click = FALSE;
2613       gboolean rtl;
2614       gboolean node_selected;
2615
2616       /* Empty tree? */
2617       if (tree_view->priv->tree == NULL)
2618         {
2619           grab_focus_and_unset_draw_keyfocus (tree_view);
2620           return TRUE;
2621         }
2622
2623       /* are we in an arrow? */
2624       if (tree_view->priv->prelight_node &&
2625           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2626           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2627         {
2628           if (event->button == 1)
2629             {
2630               gtk_grab_add (widget);
2631               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2632               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2633               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2634                                               tree_view->priv->prelight_tree,
2635                                               tree_view->priv->prelight_node);
2636             }
2637
2638           grab_focus_and_unset_draw_keyfocus (tree_view);
2639           return TRUE;
2640         }
2641
2642       /* find the node that was clicked */
2643       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2644       if (new_y < 0)
2645         new_y = 0;
2646       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2647
2648       if (node == NULL)
2649         {
2650           /* We clicked in dead space */
2651           grab_focus_and_unset_draw_keyfocus (tree_view);
2652           return TRUE;
2653         }
2654
2655       /* Get the path and the node */
2656       path = _gtk_tree_view_find_path (tree_view, tree, node);
2657       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2658
2659       if (!path_is_selectable)
2660         {
2661           gtk_tree_path_free (path);
2662           grab_focus_and_unset_draw_keyfocus (tree_view);
2663           return TRUE;
2664         }
2665
2666       depth = gtk_tree_path_get_depth (path);
2667       background_area.y = y_offset + event->y;
2668       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2669       background_area.x = 0;
2670
2671
2672       /* Let the column have a chance at selecting it. */
2673       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2674       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2675            list; list = (rtl ? list->prev : list->next))
2676         {
2677           GtkTreeViewColumn *candidate = list->data;
2678
2679           if (!candidate->visible)
2680             continue;
2681
2682           background_area.width = candidate->width;
2683           if ((background_area.x > (gint) event->x) ||
2684               (background_area.x + background_area.width <= (gint) event->x))
2685             {
2686               background_area.x += background_area.width;
2687               continue;
2688             }
2689
2690           /* we found the focus column */
2691           column = candidate;
2692           cell_area = background_area;
2693           cell_area.width -= horizontal_separator;
2694           cell_area.height -= vertical_separator;
2695           cell_area.x += horizontal_separator/2;
2696           cell_area.y += vertical_separator/2;
2697           if (gtk_tree_view_is_expander_column (tree_view, column))
2698             {
2699               if (!rtl)
2700                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2701               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2702
2703               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2704                 {
2705                   if (!rtl)
2706                     cell_area.x += depth * tree_view->priv->expander_size;
2707                   cell_area.width -= depth * tree_view->priv->expander_size;
2708                 }
2709             }
2710           break;
2711         }
2712
2713       if (column == NULL)
2714         {
2715           gtk_tree_path_free (path);
2716           grab_focus_and_unset_draw_keyfocus (tree_view);
2717           return FALSE;
2718         }
2719
2720       tree_view->priv->focus_column = column;
2721
2722       /* decide if we edit */
2723       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2724           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2725         {
2726           GtkTreePath *anchor;
2727           GtkTreeIter iter;
2728
2729           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2730           gtk_tree_view_column_cell_set_cell_data (column,
2731                                                    tree_view->priv->model,
2732                                                    &iter,
2733                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2734                                                    node->children?TRUE:FALSE);
2735
2736           if (tree_view->priv->anchor)
2737             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2738           else
2739             anchor = NULL;
2740
2741           if ((anchor && !gtk_tree_path_compare (anchor, path))
2742               || !_gtk_tree_view_column_has_editable_cell (column))
2743             {
2744               GtkCellEditable *cell_editable = NULL;
2745
2746               /* FIXME: get the right flags */
2747               guint flags = 0;
2748
2749               path_string = gtk_tree_path_to_string (path);
2750
2751               if (_gtk_tree_view_column_cell_event (column,
2752                                                     &cell_editable,
2753                                                     (GdkEvent *)event,
2754                                                     path_string,
2755                                                     &background_area,
2756                                                     &cell_area, flags))
2757                 {
2758                   if (cell_editable != NULL)
2759                     {
2760                       gint left, right;
2761                       GdkRectangle area;
2762
2763                       area = cell_area;
2764                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2765
2766                       area.x += left;
2767                       area.width -= right + left;
2768
2769                       gtk_tree_view_real_start_editing (tree_view,
2770                                                         column,
2771                                                         path,
2772                                                         cell_editable,
2773                                                         &area,
2774                                                         (GdkEvent *)event,
2775                                                         flags);
2776                       g_free (path_string);
2777                       gtk_tree_path_free (path);
2778                       gtk_tree_path_free (anchor);
2779                       return TRUE;
2780                     }
2781                   column_handled_click = TRUE;
2782                 }
2783               g_free (path_string);
2784             }
2785           if (anchor)
2786             gtk_tree_path_free (anchor);
2787         }
2788
2789       /* select */
2790       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2791       pre_val = tree_view->priv->vadjustment->value;
2792
2793       /* we only handle selection modifications on the first button press
2794        */
2795       if (event->type == GDK_BUTTON_PRESS)
2796         {
2797           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2798             tree_view->priv->ctrl_pressed = TRUE;
2799           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2800             tree_view->priv->shift_pressed = TRUE;
2801
2802           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2803           if (focus_cell)
2804             gtk_tree_view_column_focus_cell (column, focus_cell);
2805
2806           if (event->state & GDK_CONTROL_MASK)
2807             {
2808               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2809               gtk_tree_view_real_toggle_cursor_row (tree_view);
2810             }
2811           else if (event->state & GDK_SHIFT_MASK)
2812             {
2813               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2814               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2815             }
2816           else
2817             {
2818               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2819             }
2820
2821           tree_view->priv->ctrl_pressed = FALSE;
2822           tree_view->priv->shift_pressed = FALSE;
2823         }
2824
2825       /* the treeview may have been scrolled because of _set_cursor,
2826        * correct here
2827        */
2828
2829       aft_val = tree_view->priv->vadjustment->value;
2830       dval = pre_val - aft_val;
2831
2832       cell_area.y += dval;
2833       background_area.y += dval;
2834
2835       /* Save press to possibly begin a drag
2836        */
2837       if (!column_handled_click &&
2838           !tree_view->priv->in_grab &&
2839           tree_view->priv->pressed_button < 0)
2840         {
2841           tree_view->priv->pressed_button = event->button;
2842           tree_view->priv->press_start_x = event->x;
2843           tree_view->priv->press_start_y = event->y;
2844
2845           if (tree_view->priv->rubber_banding_enable
2846               && !node_selected
2847               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2848             {
2849               tree_view->priv->press_start_y += tree_view->priv->dy;
2850               tree_view->priv->rubber_band_x = event->x;
2851               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2852               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2853
2854               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2855                 tree_view->priv->rubber_band_ctrl = TRUE;
2856               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2857                 tree_view->priv->rubber_band_shift = TRUE;
2858             }
2859         }
2860
2861       /* Test if a double click happened on the same row. */
2862       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2863         {
2864           int double_click_time, double_click_distance;
2865
2866           g_object_get (gtk_settings_get_default (),
2867                         "gtk-double-click-time", &double_click_time,
2868                         "gtk-double-click-distance", &double_click_distance,
2869                         NULL);
2870
2871           /* Same conditions as _gdk_event_button_generate */
2872           if (tree_view->priv->last_button_x != -1 &&
2873               (event->time < tree_view->priv->last_button_time + double_click_time) &&
2874               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2875               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2876             {
2877               /* We do no longer compare paths of this row and the
2878                * row clicked previously.  We use the double click
2879                * distance to decide whether this is a valid click,
2880                * allowing the mouse to slightly move over another row.
2881                */
2882               row_double_click = TRUE;
2883
2884               tree_view->priv->last_button_time = 0;
2885               tree_view->priv->last_button_x = -1;
2886               tree_view->priv->last_button_y = -1;
2887             }
2888           else
2889             {
2890               tree_view->priv->last_button_time = event->time;
2891               tree_view->priv->last_button_x = event->x;
2892               tree_view->priv->last_button_y = event->y;
2893             }
2894         }
2895
2896       if (row_double_click)
2897         {
2898           gtk_grab_remove (widget);
2899           gtk_tree_view_row_activated (tree_view, path, column);
2900
2901           if (tree_view->priv->pressed_button == event->button)
2902             tree_view->priv->pressed_button = -1;
2903         }
2904
2905       gtk_tree_path_free (path);
2906
2907       /* If we activated the row through a double click we don't want to grab
2908        * focus back, as moving focus to another widget is pretty common.
2909        */
2910       if (!row_double_click)
2911         grab_focus_and_unset_draw_keyfocus (tree_view);
2912
2913       return TRUE;
2914     }
2915
2916   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2917    */
2918   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2919     {
2920       column = list->data;
2921       if (event->window == column->window &&
2922           column->resizable &&
2923           column->window)
2924         {
2925           GtkAllocation button_allocation;
2926           gpointer drag_data;
2927
2928           if (event->type == GDK_2BUTTON_PRESS &&
2929               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2930             {
2931               column->use_resized_width = FALSE;
2932               _gtk_tree_view_column_autosize (tree_view, column);
2933               return TRUE;
2934             }
2935
2936           if (gdk_pointer_grab (column->window, FALSE,
2937                                 GDK_POINTER_MOTION_HINT_MASK |
2938                                 GDK_BUTTON1_MOTION_MASK |
2939                                 GDK_BUTTON_RELEASE_MASK,
2940                                 NULL, NULL, event->time))
2941             return FALSE;
2942
2943           gtk_grab_add (widget);
2944           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2945           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2946
2947           /* block attached dnd signal handler */
2948           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2949           if (drag_data)
2950             g_signal_handlers_block_matched (widget,
2951                                              G_SIGNAL_MATCH_DATA,
2952                                              0, 0, NULL, NULL,
2953                                              drag_data);
2954
2955           gtk_widget_get_allocation (column->button, &button_allocation);
2956           tree_view->priv->drag_pos = i;
2957           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
2958
2959           if (!gtk_widget_has_focus (widget))
2960             gtk_widget_grab_focus (widget);
2961
2962           return TRUE;
2963         }
2964     }
2965   return FALSE;
2966 }
2967
2968 /* GtkWidget::button_release_event helper */
2969 static gboolean
2970 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2971                                           GdkEventButton *event)
2972 {
2973   GtkTreeView *tree_view;
2974   GList *l;
2975   gboolean rtl;
2976
2977   tree_view = GTK_TREE_VIEW (widget);
2978
2979   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2980   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2981   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2982
2983   /* Move the button back */
2984   g_object_ref (tree_view->priv->drag_column->button);
2985   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2986   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2987   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2988   g_object_unref (tree_view->priv->drag_column->button);
2989   gtk_widget_queue_resize (widget);
2990   if (tree_view->priv->drag_column->resizable)
2991     {
2992       gdk_window_raise (tree_view->priv->drag_column->window);
2993       gdk_window_show (tree_view->priv->drag_column->window);
2994     }
2995   else
2996     gdk_window_hide (tree_view->priv->drag_column->window);
2997
2998   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2999
3000   if (rtl)
3001     {
3002       if (tree_view->priv->cur_reorder &&
3003           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3004         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3005                                          tree_view->priv->cur_reorder->right_column);
3006     }
3007   else
3008     {
3009       if (tree_view->priv->cur_reorder &&
3010           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3011         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3012                                          tree_view->priv->cur_reorder->left_column);
3013     }
3014   tree_view->priv->drag_column = NULL;
3015   gdk_window_hide (tree_view->priv->drag_window);
3016
3017   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3018     g_slice_free (GtkTreeViewColumnReorder, l->data);
3019   g_list_free (tree_view->priv->column_drag_info);
3020   tree_view->priv->column_drag_info = NULL;
3021   tree_view->priv->cur_reorder = NULL;
3022
3023   if (tree_view->priv->drag_highlight_window)
3024     gdk_window_hide (tree_view->priv->drag_highlight_window);
3025
3026   /* Reset our flags */
3027   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3028   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
3029
3030   return TRUE;
3031 }
3032
3033 /* GtkWidget::button_release_event helper */
3034 static gboolean
3035 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3036                                             GdkEventButton *event)
3037 {
3038   GtkTreeView *tree_view;
3039   gpointer drag_data;
3040
3041   tree_view = GTK_TREE_VIEW (widget);
3042
3043   tree_view->priv->drag_pos = -1;
3044
3045   /* unblock attached dnd signal handler */
3046   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3047   if (drag_data)
3048     g_signal_handlers_unblock_matched (widget,
3049                                        G_SIGNAL_MATCH_DATA,
3050                                        0, 0, NULL, NULL,
3051                                        drag_data);
3052
3053   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3054   gtk_grab_remove (widget);
3055   gdk_display_pointer_ungrab (gdk_window_get_display (event->window),
3056                               event->time);
3057   return TRUE;
3058 }
3059
3060 static gboolean
3061 gtk_tree_view_button_release (GtkWidget      *widget,
3062                               GdkEventButton *event)
3063 {
3064   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3065
3066   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3067     return gtk_tree_view_button_release_drag_column (widget, event);
3068
3069   if (tree_view->priv->rubber_band_status)
3070     gtk_tree_view_stop_rubber_band (tree_view);
3071
3072   if (tree_view->priv->pressed_button == event->button)
3073     tree_view->priv->pressed_button = -1;
3074
3075   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3076     return gtk_tree_view_button_release_column_resize (widget, event);
3077
3078   if (tree_view->priv->button_pressed_node == NULL)
3079     return FALSE;
3080
3081   if (event->button == 1)
3082     {
3083       gtk_grab_remove (widget);
3084       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3085           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3086         {
3087           GtkTreePath *path = NULL;
3088
3089           path = _gtk_tree_view_find_path (tree_view,
3090                                            tree_view->priv->button_pressed_tree,
3091                                            tree_view->priv->button_pressed_node);
3092           /* Actually activate the node */
3093           if (tree_view->priv->button_pressed_node->children == NULL)
3094             gtk_tree_view_real_expand_row (tree_view, path,
3095                                            tree_view->priv->button_pressed_tree,
3096                                            tree_view->priv->button_pressed_node,
3097                                            FALSE, TRUE);
3098           else
3099             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3100                                              tree_view->priv->button_pressed_tree,
3101                                              tree_view->priv->button_pressed_node, TRUE);
3102           gtk_tree_path_free (path);
3103         }
3104
3105       tree_view->priv->button_pressed_tree = NULL;
3106       tree_view->priv->button_pressed_node = NULL;
3107     }
3108
3109   return TRUE;
3110 }
3111
3112 static gboolean
3113 gtk_tree_view_grab_broken (GtkWidget          *widget,
3114                            GdkEventGrabBroken *event)
3115 {
3116   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3117
3118   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3119     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3120
3121   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3122     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3123
3124   return TRUE;
3125 }
3126
3127 #if 0
3128 static gboolean
3129 gtk_tree_view_configure (GtkWidget *widget,
3130                          GdkEventConfigure *event)
3131 {
3132   GtkTreeView *tree_view;
3133
3134   tree_view = GTK_TREE_VIEW (widget);
3135   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3136
3137   return FALSE;
3138 }
3139 #endif
3140
3141 /* GtkWidget::motion_event function set.
3142  */
3143
3144 static gboolean
3145 coords_are_over_arrow (GtkTreeView *tree_view,
3146                        GtkRBTree   *tree,
3147                        GtkRBNode   *node,
3148                        /* these are in bin window coords */
3149                        gint         x,
3150                        gint         y)
3151 {
3152   GdkRectangle arrow;
3153   gint x2;
3154
3155   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3156     return FALSE;
3157
3158   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3159     return FALSE;
3160
3161   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3162
3163   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3164
3165   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3166
3167   arrow.width = x2 - arrow.x;
3168
3169   return (x >= arrow.x &&
3170           x < (arrow.x + arrow.width) &&
3171           y >= arrow.y &&
3172           y < (arrow.y + arrow.height));
3173 }
3174
3175 static gboolean
3176 auto_expand_timeout (gpointer data)
3177 {
3178   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3179   GtkTreePath *path;
3180
3181   if (tree_view->priv->prelight_node)
3182     {
3183       path = _gtk_tree_view_find_path (tree_view,
3184                                        tree_view->priv->prelight_tree,
3185                                        tree_view->priv->prelight_node);   
3186
3187       if (tree_view->priv->prelight_node->children)
3188         gtk_tree_view_collapse_row (tree_view, path);
3189       else
3190         gtk_tree_view_expand_row (tree_view, path, FALSE);
3191
3192       gtk_tree_path_free (path);
3193     }
3194
3195   tree_view->priv->auto_expand_timeout = 0;
3196
3197   return FALSE;
3198 }
3199
3200 static void
3201 remove_auto_expand_timeout (GtkTreeView *tree_view)
3202 {
3203   if (tree_view->priv->auto_expand_timeout != 0)
3204     {
3205       g_source_remove (tree_view->priv->auto_expand_timeout);
3206       tree_view->priv->auto_expand_timeout = 0;
3207     }
3208 }
3209
3210 static void
3211 do_prelight (GtkTreeView *tree_view,
3212              GtkRBTree   *tree,
3213              GtkRBNode   *node,
3214              /* these are in bin_window coords */
3215              gint         x,
3216              gint         y)
3217 {
3218   if (tree_view->priv->prelight_tree == tree &&
3219       tree_view->priv->prelight_node == node)
3220     {
3221       /*  We are still on the same node,
3222           but we might need to take care of the arrow  */
3223
3224       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3225         {
3226           gboolean over_arrow;
3227           gboolean flag_set;
3228
3229           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3230           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3231                                              GTK_TREE_VIEW_ARROW_PRELIT);
3232
3233           if (over_arrow != flag_set)
3234             {
3235               if (over_arrow)
3236                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3237                                         GTK_TREE_VIEW_ARROW_PRELIT);
3238               else
3239                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3240                                           GTK_TREE_VIEW_ARROW_PRELIT);
3241
3242               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3243             }
3244         }
3245
3246       return;
3247     }
3248
3249   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3250     {
3251       /*  Unprelight the old node and arrow  */
3252
3253       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3254                              GTK_RBNODE_IS_PRELIT);
3255
3256       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3257           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3258         {
3259           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3260           
3261           gtk_tree_view_queue_draw_arrow (tree_view,
3262                                           tree_view->priv->prelight_tree,
3263                                           tree_view->priv->prelight_node);
3264         }
3265
3266       _gtk_tree_view_queue_draw_node (tree_view,
3267                                       tree_view->priv->prelight_tree,
3268                                       tree_view->priv->prelight_node,
3269                                       NULL);
3270     }
3271
3272
3273   if (tree_view->priv->hover_expand)
3274     remove_auto_expand_timeout (tree_view);
3275
3276   /*  Set the new prelight values  */
3277   tree_view->priv->prelight_node = node;
3278   tree_view->priv->prelight_tree = tree;
3279
3280   if (!node || !tree)
3281     return;
3282
3283   /*  Prelight the new node and arrow  */
3284
3285   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3286       && coords_are_over_arrow (tree_view, tree, node, x, y))
3287     {
3288       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3289
3290       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3291     }
3292
3293   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3294
3295   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3296
3297   if (tree_view->priv->hover_expand)
3298     {
3299       tree_view->priv->auto_expand_timeout = 
3300         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3301     }
3302 }
3303
3304 static void
3305 prelight_or_select (GtkTreeView *tree_view,
3306                     GtkRBTree   *tree,
3307                     GtkRBNode   *node,
3308                     /* these are in bin_window coords */
3309                     gint         x,
3310                     gint         y)
3311 {
3312   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3313   
3314   if (tree_view->priv->hover_selection &&
3315       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3316       !(tree_view->priv->edited_column &&
3317         tree_view->priv->edited_column->editable_widget))
3318     {
3319       if (node)
3320         {
3321           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3322             {
3323               GtkTreePath *path;
3324               
3325               path = _gtk_tree_view_find_path (tree_view, tree, node);
3326               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3327               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3328                 {
3329                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3330                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3331                 }
3332               gtk_tree_path_free (path);
3333             }
3334         }
3335
3336       else if (mode == GTK_SELECTION_SINGLE)
3337         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3338     }
3339
3340     do_prelight (tree_view, tree, node, x, y);
3341 }
3342
3343 static void
3344 ensure_unprelighted (GtkTreeView *tree_view)
3345 {
3346   do_prelight (tree_view,
3347                NULL, NULL,
3348                -1000, -1000); /* coords not possibly over an arrow */
3349
3350   g_assert (tree_view->priv->prelight_node == NULL);
3351 }
3352
3353 static void
3354 update_prelight (GtkTreeView *tree_view,
3355                  gint         x,
3356                  gint         y)
3357 {
3358   int new_y;
3359   GtkRBTree *tree;
3360   GtkRBNode *node;
3361
3362   if (tree_view->priv->tree == NULL)
3363     return;
3364
3365   if (x == -10000)
3366     {
3367       ensure_unprelighted (tree_view);
3368       return;
3369     }
3370
3371   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3372   if (new_y < 0)
3373     new_y = 0;
3374
3375   _gtk_rbtree_find_offset (tree_view->priv->tree,
3376                            new_y, &tree, &node);
3377
3378   if (node)
3379     prelight_or_select (tree_view, tree, node, x, y);
3380 }
3381
3382
3383
3384
3385 /* Our motion arrow is either a box (in the case of the original spot)
3386  * or an arrow.  It is expander_size wide.
3387  */
3388 /*
3389  * 11111111111111
3390  * 01111111111110
3391  * 00111111111100
3392  * 00011111111000
3393  * 00001111110000
3394  * 00000111100000
3395  * 00000111100000
3396  * 00000111100000
3397  * ~ ~ ~ ~ ~ ~ ~
3398  * 00000111100000
3399  * 00000111100000
3400  * 00000111100000
3401  * 00001111110000
3402  * 00011111111000
3403  * 00111111111100
3404  * 01111111111110
3405  * 11111111111111
3406  */
3407
3408 static void
3409 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3410 {
3411   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3412   GtkWidget *widget = GTK_WIDGET (tree_view);
3413   cairo_surface_t *mask_image;
3414   cairo_region_t *mask_region;
3415   gint x;
3416   gint y;
3417   gint width;
3418   gint height;
3419   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3420   GdkWindowAttr attributes;
3421   guint attributes_mask;
3422   cairo_t *cr;
3423
3424   if (!reorder ||
3425       reorder->left_column == tree_view->priv->drag_column ||
3426       reorder->right_column == tree_view->priv->drag_column)
3427     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3428   else if (reorder->left_column || reorder->right_column)
3429     {
3430       GtkAllocation left_allocation, right_allocation;
3431       GdkRectangle visible_rect;
3432
3433       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3434       if (reorder->left_column)
3435         {
3436           gtk_widget_get_allocation (reorder->left_column->button, &left_allocation);
3437           x = left_allocation.x + left_allocation.width;
3438         }
3439       else
3440         {
3441           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
3442           x = right_allocation.x;
3443         }
3444
3445       if (x < visible_rect.x)
3446         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3447       else if (x > visible_rect.x + visible_rect.width)
3448         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3449       else
3450         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3451     }
3452
3453   /* We want to draw the rectangle over the initial location. */
3454   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3455     {
3456       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3457         {
3458           GtkAllocation drag_allocation;
3459
3460           if (tree_view->priv->drag_highlight_window)
3461             {
3462               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3463                                         NULL);
3464               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3465             }
3466
3467           attributes.window_type = GDK_WINDOW_CHILD;
3468           attributes.wclass = GDK_INPUT_OUTPUT;
3469           attributes.x = tree_view->priv->drag_column_x;
3470           attributes.y = 0;
3471           gtk_widget_get_allocation (tree_view->priv->drag_column->button, &drag_allocation);
3472           width = attributes.width = drag_allocation.width;
3473           height = attributes.height = drag_allocation.height;
3474           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3475           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3476           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3477           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3478           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3479
3480           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3481           cr = cairo_create (mask_image);
3482
3483           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3484           cairo_stroke (cr);
3485           cairo_destroy (cr);
3486
3487           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3488           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3489                                            mask_region, 0, 0);
3490
3491           cairo_region_destroy (mask_region);
3492           cairo_surface_destroy (mask_image);
3493
3494           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3495         }
3496     }
3497   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3498     {
3499       GtkAllocation button_allocation;
3500
3501       width = tree_view->priv->expander_size;
3502
3503       /* Get x, y, width, height of arrow */
3504       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3505       if (reorder->left_column)
3506         {
3507           gtk_widget_get_allocation (reorder->left_column->button, &button_allocation);
3508           x += button_allocation.x + button_allocation.width - width/2;
3509           height = button_allocation.height;
3510         }
3511       else
3512         {
3513           gtk_widget_get_allocation (reorder->right_column->button, &button_allocation);
3514           x += button_allocation.x - width/2;
3515           height = button_allocation.height;
3516         }
3517       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3518       height += tree_view->priv->expander_size;
3519
3520       /* Create the new window */
3521       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3522         {
3523           if (tree_view->priv->drag_highlight_window)
3524             {
3525               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3526                                         NULL);
3527               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3528             }
3529
3530           attributes.window_type = GDK_WINDOW_TEMP;
3531           attributes.wclass = GDK_INPUT_OUTPUT;
3532           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3533           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3534           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3535           attributes.x = x;
3536           attributes.y = y;
3537           attributes.width = width;
3538           attributes.height = height;
3539           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3540                                                                    &attributes, attributes_mask);
3541           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3542
3543           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3544
3545           cr = cairo_create (mask_image);
3546           cairo_move_to (cr, 0, 0);
3547           cairo_line_to (cr, width, 0);
3548           cairo_line_to (cr, width / 2., width / 2);
3549           cairo_move_to (cr, 0, height);
3550           cairo_line_to (cr, width, height);
3551           cairo_line_to (cr, width / 2., height - width / 2.);
3552           cairo_fill (cr);
3553           cairo_destroy (cr);
3554
3555           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3556           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3557                                            mask_region, 0, 0);
3558
3559           cairo_region_destroy (mask_region);
3560           cairo_surface_destroy (mask_image);
3561         }
3562
3563       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3564       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3565     }
3566   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3567            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3568     {
3569       GtkAllocation allocation;
3570
3571       width = tree_view->priv->expander_size;
3572
3573       /* Get x, y, width, height of arrow */
3574       width = width/2; /* remember, the arrow only takes half the available width */
3575       gdk_window_get_origin (gtk_widget_get_window (widget),
3576                              &x, &y);
3577       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3578         {
3579           gtk_widget_get_allocation (widget, &allocation);
3580           x += allocation.width - width;
3581         }
3582
3583       if (reorder->left_column)
3584         {
3585           gtk_widget_get_allocation (reorder->left_column->button, &allocation);
3586           height = allocation.height;
3587         }
3588       else
3589         {
3590           gtk_widget_get_allocation (reorder->right_column->button, &allocation);
3591           height = allocation.height;
3592         }
3593
3594       y -= tree_view->priv->expander_size;
3595       height += 2*tree_view->priv->expander_size;
3596
3597       /* Create the new window */
3598       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3599           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3600         {
3601           if (tree_view->priv->drag_highlight_window)
3602             {
3603               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3604                                         NULL);
3605               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3606             }
3607
3608           attributes.window_type = GDK_WINDOW_TEMP;
3609           attributes.wclass = GDK_INPUT_OUTPUT;
3610           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3611           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3612           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3613           attributes.x = x;
3614           attributes.y = y;
3615           attributes.width = width;
3616           attributes.height = height;
3617           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3618           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3619
3620           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3621
3622           cr = cairo_create (mask_image);
3623           /* mirror if we're on the left */
3624           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3625             {
3626               cairo_translate (cr, width, 0);
3627               cairo_scale (cr, -1, 1);
3628             }
3629           cairo_move_to (cr, 0, 0);
3630           cairo_line_to (cr, width, width);
3631           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3632           cairo_move_to (cr, 0, height);
3633           cairo_line_to (cr, width, height - width);
3634           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3635           cairo_fill (cr);
3636           cairo_destroy (cr);
3637
3638           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3639           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3640                                            mask_region, 0, 0);
3641
3642           cairo_region_destroy (mask_region);
3643           cairo_surface_destroy (mask_image);
3644         }
3645
3646       tree_view->priv->drag_column_window_state = arrow_type;
3647       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3648    }
3649   else
3650     {
3651       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3652       gdk_window_hide (tree_view->priv->drag_highlight_window);
3653       return;
3654     }
3655
3656   gdk_window_show (tree_view->priv->drag_highlight_window);
3657   gdk_window_raise (tree_view->priv->drag_highlight_window);
3658 }
3659
3660 static gboolean
3661 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3662                                     GdkEventMotion *event)
3663 {
3664   gint x;
3665   gint new_width;
3666   GtkTreeViewColumn *column;
3667   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3668
3669   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3670
3671   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3672     gtk_widget_get_pointer (widget, &x, NULL);
3673   else
3674     x = event->x;
3675
3676   if (tree_view->priv->hadjustment)
3677     x += tree_view->priv->hadjustment->value;
3678
3679   new_width = gtk_tree_view_new_column_width (tree_view,
3680                                               tree_view->priv->drag_pos, &x);
3681   if (x != tree_view->priv->x_drag &&
3682       (new_width != column->fixed_width))
3683     {
3684       column->use_resized_width = TRUE;
3685       column->resized_width = new_width;
3686       if (column->expand)
3687         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3688       gtk_widget_queue_resize (widget);
3689     }
3690
3691   return FALSE;
3692 }
3693
3694
3695 static void
3696 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3697 {
3698   GtkTreeViewColumnReorder *reorder = NULL;
3699   GList *list;
3700   gint mouse_x;
3701
3702   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3703   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3704     {
3705       reorder = (GtkTreeViewColumnReorder *) list->data;
3706       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3707         break;
3708       reorder = NULL;
3709     }
3710
3711   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3712       return;*/
3713
3714   tree_view->priv->cur_reorder = reorder;
3715   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3716 }
3717
3718 static void
3719 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3720 {
3721   GdkRectangle visible_rect;
3722   gint y;
3723   gint offset;
3724
3725   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3726   y += tree_view->priv->dy;
3727
3728   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3729
3730   /* see if we are near the edge. */
3731   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3732   if (offset > 0)
3733     {
3734       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3735       if (offset < 0)
3736         return;
3737     }
3738
3739   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3740                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3741 }
3742
3743 static gboolean
3744 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3745 {
3746   GdkRectangle visible_rect;
3747   gint x;
3748   gint offset;
3749
3750   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3751
3752   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3753
3754   /* See if we are near the edge. */
3755   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3756   if (offset > 0)
3757     {
3758       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3759       if (offset < 0)
3760         return TRUE;
3761     }
3762   offset = offset/3;
3763
3764   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3765                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3766
3767   return TRUE;
3768
3769 }
3770
3771 static gboolean
3772 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3773                                   GdkEventMotion *event)
3774 {
3775   GtkAllocation allocation, button_allocation;
3776   GtkTreeView *tree_view = (GtkTreeView *) widget;
3777   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3778   gint x, y;
3779
3780   /* Sanity Check */
3781   if ((column == NULL) ||
3782       (event->window != tree_view->priv->drag_window))
3783     return FALSE;
3784
3785   /* Handle moving the header */
3786   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3787   gtk_widget_get_allocation (widget, &allocation);
3788   gtk_widget_get_allocation (column->button, &button_allocation);
3789   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3790              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
3791   gdk_window_move (tree_view->priv->drag_window, x, y);
3792   
3793   /* autoscroll, if needed */
3794   gtk_tree_view_horizontal_autoscroll (tree_view);
3795   /* Update the current reorder position and arrow; */
3796   gtk_tree_view_update_current_reorder (tree_view);
3797
3798   return TRUE;
3799 }
3800
3801 static void
3802 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3803 {
3804   remove_scroll_timeout (tree_view);
3805   gtk_grab_remove (GTK_WIDGET (tree_view));
3806
3807   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3808     {
3809       GtkTreePath *tmp_path;
3810
3811       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3812
3813       /* The anchor path should be set to the start path */
3814       tmp_path = _gtk_tree_view_find_path (tree_view,
3815                                            tree_view->priv->rubber_band_start_tree,
3816                                            tree_view->priv->rubber_band_start_node);
3817
3818       if (tree_view->priv->anchor)
3819         gtk_tree_row_reference_free (tree_view->priv->anchor);
3820
3821       tree_view->priv->anchor =
3822         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3823                                           tree_view->priv->model,
3824                                           tmp_path);
3825
3826       gtk_tree_path_free (tmp_path);
3827
3828       /* ... and the cursor to the end path */
3829       tmp_path = _gtk_tree_view_find_path (tree_view,
3830                                            tree_view->priv->rubber_band_end_tree,
3831                                            tree_view->priv->rubber_band_end_node);
3832       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3833       gtk_tree_path_free (tmp_path);
3834
3835       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3836     }
3837
3838   /* Clear status variables */
3839   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3840   tree_view->priv->rubber_band_shift = 0;
3841   tree_view->priv->rubber_band_ctrl = 0;
3842
3843   tree_view->priv->rubber_band_start_node = NULL;
3844   tree_view->priv->rubber_band_start_tree = NULL;
3845   tree_view->priv->rubber_band_end_node = NULL;
3846   tree_view->priv->rubber_band_end_tree = NULL;
3847 }
3848
3849 static void
3850 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3851                                                  GtkRBTree   *start_tree,
3852                                                  GtkRBNode   *start_node,
3853                                                  GtkRBTree   *end_tree,
3854                                                  GtkRBNode   *end_node,
3855                                                  gboolean     select,
3856                                                  gboolean     skip_start,
3857                                                  gboolean     skip_end)
3858 {
3859   if (start_node == end_node)
3860     return;
3861
3862   /* We skip the first node and jump inside the loop */
3863   if (skip_start)
3864     goto skip_first;
3865
3866   do
3867     {
3868       /* Small optimization by assuming insensitive nodes are never
3869        * selected.
3870        */
3871       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3872         {
3873           GtkTreePath *path;
3874           gboolean selectable;
3875
3876           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3877           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3878           gtk_tree_path_free (path);
3879
3880           if (!selectable)
3881             goto node_not_selectable;
3882         }
3883
3884       if (select)
3885         {
3886           if (tree_view->priv->rubber_band_shift)
3887             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3888           else if (tree_view->priv->rubber_band_ctrl)
3889             {
3890               /* Toggle the selection state */
3891               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3892                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3893               else
3894                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3895             }
3896           else
3897             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3898         }
3899       else
3900         {
3901           /* Mirror the above */
3902           if (tree_view->priv->rubber_band_shift)
3903             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3904           else if (tree_view->priv->rubber_band_ctrl)
3905             {
3906               /* Toggle the selection state */
3907               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3908                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3909               else
3910                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3911             }
3912           else
3913             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3914         }
3915
3916       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3917
3918 node_not_selectable:
3919       if (start_node == end_node)
3920         break;
3921
3922 skip_first:
3923
3924       if (start_node->children)
3925         {
3926           start_tree = start_node->children;
3927           start_node = start_tree->root;
3928           while (start_node->left != start_tree->nil)
3929             start_node = start_node->left;
3930         }
3931       else
3932         {
3933           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3934
3935           if (!start_tree)
3936             /* Ran out of tree */
3937             break;
3938         }
3939
3940       if (skip_end && start_node == end_node)
3941         break;
3942     }
3943   while (TRUE);
3944 }
3945
3946 static void
3947 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3948 {
3949   GtkRBTree *start_tree, *end_tree;
3950   GtkRBNode *start_node, *end_node;
3951
3952   _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);
3953   _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);
3954
3955   /* Handle the start area first */
3956   if (!tree_view->priv->rubber_band_start_node)
3957     {
3958       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3959                                                        start_tree,
3960                                                        start_node,
3961                                                        end_tree,
3962                                                        end_node,
3963                                                        TRUE,
3964                                                        FALSE,
3965                                                        FALSE);
3966     }
3967   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3968            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3969     {
3970       /* New node is above the old one; selection became bigger */
3971       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3972                                                        start_tree,
3973                                                        start_node,
3974                                                        tree_view->priv->rubber_band_start_tree,
3975                                                        tree_view->priv->rubber_band_start_node,
3976                                                        TRUE,
3977                                                        FALSE,
3978                                                        TRUE);
3979     }
3980   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3981            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3982     {
3983       /* New node is below the old one; selection became smaller */
3984       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3985                                                        tree_view->priv->rubber_band_start_tree,
3986                                                        tree_view->priv->rubber_band_start_node,
3987                                                        start_tree,
3988                                                        start_node,
3989                                                        FALSE,
3990                                                        FALSE,
3991                                                        TRUE);
3992     }
3993
3994   tree_view->priv->rubber_band_start_tree = start_tree;
3995   tree_view->priv->rubber_band_start_node = start_node;
3996
3997   /* Next, handle the end area */
3998   if (!tree_view->priv->rubber_band_end_node)
3999     {
4000       /* In the event this happens, start_node was also NULL; this case is
4001        * handled above.
4002        */
4003     }
4004   else if (!end_node)
4005     {
4006       /* Find the last node in the tree */
4007       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4008                                &end_tree, &end_node);
4009
4010       /* Selection reached end of the tree */
4011       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4012                                                        tree_view->priv->rubber_band_end_tree,
4013                                                        tree_view->priv->rubber_band_end_node,
4014                                                        end_tree,
4015                                                        end_node,
4016                                                        TRUE,
4017                                                        TRUE,
4018                                                        FALSE);
4019     }
4020   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4021            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4022     {
4023       /* New node is below the old one; selection became bigger */
4024       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4025                                                        tree_view->priv->rubber_band_end_tree,
4026                                                        tree_view->priv->rubber_band_end_node,
4027                                                        end_tree,
4028                                                        end_node,
4029                                                        TRUE,
4030                                                        TRUE,
4031                                                        FALSE);
4032     }
4033   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4034            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4035     {
4036       /* New node is above the old one; selection became smaller */
4037       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4038                                                        end_tree,
4039                                                        end_node,
4040                                                        tree_view->priv->rubber_band_end_tree,
4041                                                        tree_view->priv->rubber_band_end_node,
4042                                                        FALSE,
4043                                                        TRUE,
4044                                                        FALSE);
4045     }
4046
4047   tree_view->priv->rubber_band_end_tree = end_tree;
4048   tree_view->priv->rubber_band_end_node = end_node;
4049 }
4050
4051 static void
4052 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4053 {
4054   gint x, y;
4055   GdkRectangle old_area;
4056   GdkRectangle new_area;
4057   GdkRectangle common;
4058   cairo_region_t *invalid_region;
4059
4060   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4061   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4062   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4063   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4064
4065   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4066
4067   x = MAX (x, 0);
4068   y = MAX (y, 0) + tree_view->priv->dy;
4069
4070   new_area.x = MIN (tree_view->priv->press_start_x, x);
4071   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4072   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4073   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4074
4075   invalid_region = cairo_region_create_rectangle (&old_area);
4076   cairo_region_union_rectangle (invalid_region, &new_area);
4077
4078   gdk_rectangle_intersect (&old_area, &new_area, &common);
4079   if (common.width > 2 && common.height > 2)
4080     {
4081       cairo_region_t *common_region;
4082
4083       /* make sure the border is invalidated */
4084       common.x += 1;
4085       common.y += 1;
4086       common.width -= 2;
4087       common.height -= 2;
4088
4089       common_region = cairo_region_create_rectangle (&common);
4090
4091       cairo_region_subtract (invalid_region, common_region);
4092       cairo_region_destroy (common_region);
4093     }
4094
4095   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4096
4097   cairo_region_destroy (invalid_region);
4098
4099   tree_view->priv->rubber_band_x = x;
4100   tree_view->priv->rubber_band_y = y;
4101
4102   gtk_tree_view_update_rubber_band_selection (tree_view);
4103 }
4104
4105 static void
4106 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4107                                  cairo_t      *cr)
4108 {
4109   GdkRectangle rect;
4110   GtkStyle *style;
4111
4112   cairo_save (cr);
4113
4114   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4115   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4116   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4117   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4118
4119   cairo_set_line_width (cr, 1.0);
4120
4121   style = gtk_widget_get_style (GTK_WIDGET (tree_view));
4122
4123   gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
4124
4125   gdk_cairo_rectangle (cr, &rect);
4126   cairo_clip (cr);
4127   cairo_paint_with_alpha (cr, 0.25);
4128
4129   cairo_rectangle (cr,
4130                    rect.x + 0.5, rect.y + 0.5,
4131                    rect.width - 1, rect.height - 1);
4132   cairo_stroke (cr);
4133
4134   cairo_restore (cr);
4135 }
4136
4137 static gboolean
4138 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4139                                  GdkEventMotion *event)
4140 {
4141   GtkTreeView *tree_view;
4142   GtkRBTree *tree;
4143   GtkRBNode *node;
4144   gint new_y;
4145
4146   tree_view = (GtkTreeView *) widget;
4147
4148   if (tree_view->priv->tree == NULL)
4149     return FALSE;
4150
4151   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4152     {
4153       gtk_grab_add (GTK_WIDGET (tree_view));
4154       gtk_tree_view_update_rubber_band (tree_view);
4155
4156       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4157     }
4158   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4159     {
4160       gtk_tree_view_update_rubber_band (tree_view);
4161
4162       add_scroll_timeout (tree_view);
4163     }
4164
4165   /* only check for an initiated drag when a button is pressed */
4166   if (tree_view->priv->pressed_button >= 0
4167       && !tree_view->priv->rubber_band_status)
4168     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4169
4170   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4171   if (new_y < 0)
4172     new_y = 0;
4173
4174   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4175
4176   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4177   if ((tree_view->priv->button_pressed_node != NULL) &&
4178       (tree_view->priv->button_pressed_node != node))
4179     node = NULL;
4180
4181   tree_view->priv->event_last_x = event->x;
4182   tree_view->priv->event_last_y = event->y;
4183
4184   prelight_or_select (tree_view, tree, node, event->x, event->y);
4185
4186   return TRUE;
4187 }
4188
4189 static gboolean
4190 gtk_tree_view_motion (GtkWidget      *widget,
4191                       GdkEventMotion *event)
4192 {
4193   GtkTreeView *tree_view;
4194
4195   tree_view = (GtkTreeView *) widget;
4196
4197   /* Resizing a column */
4198   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4199     return gtk_tree_view_motion_resize_column (widget, event);
4200
4201   /* Drag column */
4202   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4203     return gtk_tree_view_motion_drag_column (widget, event);
4204
4205   /* Sanity check it */
4206   if (event->window == tree_view->priv->bin_window)
4207     return gtk_tree_view_motion_bin_window (widget, event);
4208
4209   return FALSE;
4210 }
4211
4212 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4213  * the tree is empty.
4214  */
4215 static void
4216 invalidate_empty_focus (GtkTreeView *tree_view)
4217 {
4218   GdkRectangle area;
4219
4220   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4221     return;
4222
4223   area.x = 0;
4224   area.y = 0;
4225   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4226   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4227   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4228 }
4229
4230 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4231  * is empty.
4232  */
4233 static void
4234 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4235 {
4236   GtkWidget *widget = GTK_WIDGET (tree_view);
4237   gint w, h;
4238
4239   if (!gtk_widget_has_focus (widget))
4240     return;
4241
4242   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4243   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4244
4245   if (w > 0 && h > 0)
4246     gtk_paint_focus (gtk_widget_get_style (widget),
4247                      cr,
4248                      gtk_widget_get_state (widget),
4249                      widget,
4250                      NULL,
4251                      1, 1, w, h);
4252 }
4253
4254 typedef enum {
4255   GTK_TREE_VIEW_GRID_LINE,
4256   GTK_TREE_VIEW_TREE_LINE,
4257   GTK_TREE_VIEW_FOREGROUND_LINE
4258 } GtkTreeViewLineType;
4259
4260 static void
4261 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4262                          cairo_t             *cr,
4263                          GtkTreeViewLineType  type,
4264                          int                  x1,
4265                          int                  y1,
4266                          int                  x2,
4267                          int                  y2)
4268 {
4269   cairo_save (cr);
4270
4271   switch (type)
4272     {
4273     case GTK_TREE_VIEW_TREE_LINE:
4274       cairo_set_source_rgb (cr, 0, 0, 0);
4275       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4276       if (tree_view->priv->tree_line_dashes[0])
4277         cairo_set_dash (cr, 
4278                         tree_view->priv->tree_line_dashes,
4279                         2, 0.5);
4280       break;
4281     case GTK_TREE_VIEW_GRID_LINE:
4282       cairo_set_source_rgb (cr, 0, 0, 0);
4283       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4284       if (tree_view->priv->grid_line_dashes[0])
4285         cairo_set_dash (cr, 
4286                         tree_view->priv->grid_line_dashes,
4287                         2, 0.5);
4288       break;
4289     default:
4290       g_assert_not_reached ();
4291       /* fall through */
4292     case GTK_TREE_VIEW_FOREGROUND_LINE:
4293       cairo_set_line_width (cr, 1.0);
4294       gdk_cairo_set_source_color (cr,
4295                                   &gtk_widget_get_style (GTK_WIDGET (tree_view))->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4296       break;
4297     }
4298
4299   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4300   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4301   cairo_stroke (cr);
4302
4303   cairo_restore (cr);
4304 }
4305                          
4306 static void
4307 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4308                                cairo_t        *cr,
4309                                gint            n_visible_columns)
4310 {
4311   GList *list = tree_view->priv->columns;
4312   gint i = 0;
4313   gint current_x = 0;
4314
4315   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4316       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4317     return;
4318
4319   /* Only draw the lines for visible rows and columns */
4320   for (list = tree_view->priv->columns; list; list = list->next, i++)
4321     {
4322       GtkTreeViewColumn *column = list->data;
4323
4324       /* We don't want a line for the last column */
4325       if (i == n_visible_columns - 1)
4326         break;
4327
4328       if (! column->visible)
4329         continue;
4330
4331       current_x += column->width;
4332
4333       gtk_tree_view_draw_line (tree_view, cr,
4334                                GTK_TREE_VIEW_GRID_LINE,
4335                                current_x - 1, 0,
4336                                current_x - 1, tree_view->priv->height);
4337     }
4338 }
4339
4340 /* Warning: Very scary function.
4341  * Modify at your own risk
4342  *
4343  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4344  * FIXME: It's not...
4345  */
4346 static gboolean
4347 gtk_tree_view_bin_draw (GtkWidget      *widget,
4348                         cairo_t        *cr)
4349 {
4350   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4351   GtkTreePath *path;
4352   GtkStyle *style;
4353   GtkRBTree *tree;
4354   GList *list;
4355   GtkRBNode *node;
4356   GtkRBNode *cursor = NULL;
4357   GtkRBTree *cursor_tree = NULL;
4358   GtkRBNode *drag_highlight = NULL;
4359   GtkRBTree *drag_highlight_tree = NULL;
4360   GtkTreeIter iter;
4361   gint new_y;
4362   gint y_offset, cell_offset;
4363   gint max_height;
4364   gint depth;
4365   GdkRectangle background_area;
4366   GdkRectangle cell_area;
4367   GdkRectangle clip;
4368   guint flags;
4369   gint highlight_x;
4370   gint expander_cell_width;
4371   gint bin_window_width;
4372   gint bin_window_height;
4373   GtkTreePath *cursor_path;
4374   GtkTreePath *drag_dest_path;
4375   GList *first_column, *last_column;
4376   gint vertical_separator;
4377   gint horizontal_separator;
4378   gint focus_line_width;
4379   gboolean allow_rules;
4380   gboolean has_special_cell;
4381   gboolean rtl;
4382   gint n_visible_columns;
4383   gint pointer_x, pointer_y;
4384   gint grid_line_width;
4385   gboolean got_pointer = FALSE;
4386   gboolean draw_vgrid_lines, draw_hgrid_lines;
4387
4388   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4389
4390   gtk_widget_style_get (widget,
4391                         "horizontal-separator", &horizontal_separator,
4392                         "vertical-separator", &vertical_separator,
4393                         "allow-rules", &allow_rules,
4394                         "focus-line-width", &focus_line_width,
4395                         NULL);
4396
4397   if (tree_view->priv->tree == NULL)
4398     {
4399       draw_empty_focus (tree_view, cr);
4400       return TRUE;
4401     }
4402
4403   style = gtk_widget_get_style (widget);
4404
4405   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4406   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4407   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4408   cairo_clip (cr);
4409   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4410     return TRUE;
4411
4412   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4413
4414   if (new_y < 0)
4415     new_y = 0;
4416   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4417
4418   if (tree_view->priv->height < bin_window_height)
4419     {
4420       gtk_paint_flat_box (style,
4421                           cr,
4422                           gtk_widget_get_state (widget),
4423                           GTK_SHADOW_NONE,
4424                           widget,
4425                           "cell_even",
4426                           0, tree_view->priv->height,
4427                           bin_window_width,
4428                           bin_window_height - tree_view->priv->height);
4429     }
4430
4431   if (node == NULL)
4432     return TRUE;
4433
4434   /* find the path for the node */
4435   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4436                                    tree,
4437                                    node);
4438   gtk_tree_model_get_iter (tree_view->priv->model,
4439                            &iter,
4440                            path);
4441   depth = gtk_tree_path_get_depth (path);
4442   gtk_tree_path_free (path);
4443   
4444   cursor_path = NULL;
4445   drag_dest_path = NULL;
4446
4447   if (tree_view->priv->cursor)
4448     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4449
4450   if (cursor_path)
4451     _gtk_tree_view_find_node (tree_view, cursor_path,
4452                               &cursor_tree, &cursor);
4453
4454   if (tree_view->priv->drag_dest_row)
4455     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4456
4457   if (drag_dest_path)
4458     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4459                               &drag_highlight_tree, &drag_highlight);
4460
4461   draw_vgrid_lines =
4462     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4463     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4464   draw_hgrid_lines =
4465     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4466     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4467
4468   if (draw_vgrid_lines || draw_hgrid_lines)
4469     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4470   
4471   n_visible_columns = 0;
4472   for (list = tree_view->priv->columns; list; list = list->next)
4473     {
4474       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4475         continue;
4476       n_visible_columns ++;
4477     }
4478
4479   /* Find the last column */
4480   for (last_column = g_list_last (tree_view->priv->columns);
4481        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4482        last_column = last_column->prev)
4483     ;
4484
4485   /* and the first */
4486   for (first_column = g_list_first (tree_view->priv->columns);
4487        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4488        first_column = first_column->next)
4489     ;
4490
4491   /* Actually process the expose event.  To do this, we want to
4492    * start at the first node of the event, and walk the tree in
4493    * order, drawing each successive node.
4494    */
4495
4496   do
4497     {
4498       gboolean parity;
4499       gboolean is_separator = FALSE;
4500       gboolean is_first = FALSE;
4501       gboolean is_last = FALSE;
4502       
4503       is_separator = row_is_separator (tree_view, &iter, NULL);
4504
4505       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4506
4507       cell_offset = 0;
4508       highlight_x = 0; /* should match x coord of first cell */
4509       expander_cell_width = 0;
4510
4511       background_area.y = y_offset + clip.y;
4512       background_area.height = max_height;
4513
4514       flags = 0;
4515
4516       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4517         flags |= GTK_CELL_RENDERER_PRELIT;
4518
4519       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4520         flags |= GTK_CELL_RENDERER_SELECTED;
4521
4522       parity = _gtk_rbtree_node_find_parity (tree, node);
4523
4524       /* we *need* to set cell data on all cells before the call
4525        * to _has_special_cell, else _has_special_cell() does not
4526        * return a correct value.
4527        */
4528       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4529            list;
4530            list = (rtl ? list->prev : list->next))
4531         {
4532           GtkTreeViewColumn *column = list->data;
4533           gtk_tree_view_column_cell_set_cell_data (column,
4534                                                    tree_view->priv->model,
4535                                                    &iter,
4536                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4537                                                    node->children?TRUE:FALSE);
4538         }
4539
4540       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4541
4542       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4543            list;
4544            list = (rtl ? list->prev : list->next))
4545         {
4546           GtkTreeViewColumn *column = list->data;
4547           const gchar *detail = NULL;
4548           gchar new_detail[128];
4549           GtkStateType state;
4550
4551           if (!column->visible)
4552             continue;
4553
4554           if (cell_offset > clip.x + clip.width ||
4555               cell_offset + column->width < clip.x)
4556             {
4557               cell_offset += column->width;
4558               continue;
4559             }
4560
4561           if (column->show_sort_indicator)
4562             flags |= GTK_CELL_RENDERER_SORTED;
4563           else
4564             flags &= ~GTK_CELL_RENDERER_SORTED;
4565
4566           if (cursor == node)
4567             flags |= GTK_CELL_RENDERER_FOCUSED;
4568           else
4569             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4570
4571           background_area.x = cell_offset;
4572           background_area.width = column->width;
4573
4574           cell_area = background_area;
4575           cell_area.y += vertical_separator / 2;
4576           cell_area.x += horizontal_separator / 2;
4577           cell_area.height -= vertical_separator;
4578           cell_area.width -= horizontal_separator;
4579
4580           if (draw_vgrid_lines)
4581             {
4582               if (list == first_column)
4583                 {
4584                   cell_area.width -= grid_line_width / 2;
4585                 }
4586               else if (list == last_column)
4587                 {
4588                   cell_area.x += grid_line_width / 2;
4589                   cell_area.width -= grid_line_width / 2;
4590                 }
4591               else
4592                 {
4593                   cell_area.x += grid_line_width / 2;
4594                   cell_area.width -= grid_line_width;
4595                 }
4596             }
4597
4598           if (draw_hgrid_lines)
4599             {
4600               cell_area.y += grid_line_width / 2;
4601               cell_area.height -= grid_line_width;
4602             }
4603
4604           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4605             {
4606               cell_offset += column->width;
4607               continue;
4608             }
4609
4610           gtk_tree_view_column_cell_set_cell_data (column,
4611                                                    tree_view->priv->model,
4612                                                    &iter,
4613                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4614                                                    node->children?TRUE:FALSE);
4615
4616           /* Select the detail for drawing the cell.  relevant
4617            * factors are parity, sortedness, and whether to
4618            * display rules.
4619            */
4620           if (allow_rules && tree_view->priv->has_rules)
4621             {
4622               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4623                   n_visible_columns >= 3)
4624                 {
4625                   if (parity)
4626                     detail = "cell_odd_ruled_sorted";
4627                   else
4628                     detail = "cell_even_ruled_sorted";
4629                 }
4630               else
4631                 {
4632                   if (parity)
4633                     detail = "cell_odd_ruled";
4634                   else
4635                     detail = "cell_even_ruled";
4636                 }
4637             }
4638           else
4639             {
4640               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4641                   n_visible_columns >= 3)
4642                 {
4643                   if (parity)
4644                     detail = "cell_odd_sorted";
4645                   else
4646                     detail = "cell_even_sorted";
4647                 }
4648               else
4649                 {
4650                   if (parity)
4651                     detail = "cell_odd";
4652                   else
4653                     detail = "cell_even";
4654                 }
4655             }
4656
4657           g_assert (detail);
4658
4659           if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
4660             state = GTK_STATE_INSENSITIVE;          
4661           else if (flags & GTK_CELL_RENDERER_SELECTED)
4662             state = GTK_STATE_SELECTED;
4663           else
4664             state = GTK_STATE_NORMAL;
4665
4666           /* Draw background */
4667           is_first = (rtl ? !list->next : !list->prev);
4668           is_last = (rtl ? !list->prev : !list->next);
4669
4670           /* (I don't like the snprintfs either, but couldn't find a
4671            * less messy way).
4672            */
4673           if (is_first && is_last)
4674             g_snprintf (new_detail, 127, "%s", detail);
4675           else if (is_first)
4676             g_snprintf (new_detail, 127, "%s_start", detail);
4677           else if (is_last)
4678             g_snprintf (new_detail, 127, "%s_end", detail);
4679           else
4680             g_snprintf (new_detail, 127, "%s_middle", detail);
4681
4682           gtk_paint_flat_box (style,
4683                               cr,
4684                               state,
4685                               GTK_SHADOW_NONE,
4686                               widget,
4687                               new_detail,
4688                               background_area.x,
4689                               background_area.y,
4690                               background_area.width,
4691                               background_area.height);
4692
4693           if (gtk_tree_view_is_expander_column (tree_view, column))
4694             {
4695               if (!rtl)
4696                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4697               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4698
4699               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4700                 {
4701                   if (!rtl)
4702                     cell_area.x += depth * tree_view->priv->expander_size;
4703                   cell_area.width -= depth * tree_view->priv->expander_size;
4704                 }
4705
4706               /* If we have an expander column, the highlight underline
4707                * starts with that column, so that it indicates which
4708                * level of the tree we're dropping at.
4709                */
4710               highlight_x = cell_area.x;
4711               expander_cell_width = cell_area.width;
4712
4713               if (is_separator)
4714                 gtk_paint_hline (style,
4715                                  cr,
4716                                  state,
4717                                  widget,
4718                                  NULL,
4719                                  cell_area.x,
4720                                  cell_area.x + cell_area.width,
4721                                  cell_area.y + cell_area.height / 2);
4722               else
4723                 _gtk_tree_view_column_cell_render (column,
4724                                                    cr,
4725                                                    &background_area,
4726                                                    &cell_area,
4727                                                    flags);
4728               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4729                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4730                 {
4731                   if (!got_pointer)
4732                     {
4733                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4734                                               &pointer_x, &pointer_y, NULL);
4735                       got_pointer = TRUE;
4736                     }
4737
4738                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4739                                             cr,
4740                                             tree,
4741                                             node,
4742                                             pointer_x, pointer_y);
4743                 }
4744             }
4745           else
4746             {
4747               if (is_separator)
4748                 gtk_paint_hline (style,
4749                                  cr,
4750                                  state,
4751                                  widget,
4752                                  NULL,
4753                                  cell_area.x,
4754                                  cell_area.x + cell_area.width,
4755                                  cell_area.y + cell_area.height / 2);
4756               else
4757                 _gtk_tree_view_column_cell_render (column,
4758                                                    cr,
4759                                                    &background_area,
4760                                                    &cell_area,
4761                                                    flags);
4762             }
4763
4764           if (draw_hgrid_lines)
4765             {
4766               if (background_area.y > 0)
4767                 gtk_tree_view_draw_line (tree_view, cr,
4768                                          GTK_TREE_VIEW_GRID_LINE,
4769                                          background_area.x, background_area.y,
4770                                          background_area.x + background_area.width,
4771                                          background_area.y);
4772
4773               if (y_offset + max_height >= clip.height)
4774                 gtk_tree_view_draw_line (tree_view, cr,
4775                                          GTK_TREE_VIEW_GRID_LINE,
4776                                          background_area.x, background_area.y + max_height,
4777                                          background_area.x + background_area.width,
4778                                          background_area.y + max_height);
4779             }
4780
4781           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4782               tree_view->priv->tree_lines_enabled)
4783             {
4784               gint x = background_area.x;
4785               gint mult = rtl ? -1 : 1;
4786               gint y0 = background_area.y;
4787               gint y1 = background_area.y + background_area.height/2;
4788               gint y2 = background_area.y + background_area.height;
4789
4790               if (rtl)
4791                 x += background_area.width - 1;
4792
4793               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4794                   && depth > 1)
4795                 {
4796                   gtk_tree_view_draw_line (tree_view, cr,
4797                                            GTK_TREE_VIEW_TREE_LINE,
4798                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4799                                            y1,
4800                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4801                                            y1);
4802                 }
4803               else if (depth > 1)
4804                 {
4805                   gtk_tree_view_draw_line (tree_view, cr,
4806                                            GTK_TREE_VIEW_TREE_LINE,
4807                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4808                                            y1,
4809                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4810                                            y1);
4811                 }
4812
4813               if (depth > 1)
4814                 {
4815                   gint i;
4816                   GtkRBNode *tmp_node;
4817                   GtkRBTree *tmp_tree;
4818
4819                   if (!_gtk_rbtree_next (tree, node))
4820                     gtk_tree_view_draw_line (tree_view, cr,
4821                                              GTK_TREE_VIEW_TREE_LINE,
4822                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4823                                              y0,
4824                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4825                                              y1);
4826                   else
4827                     gtk_tree_view_draw_line (tree_view, cr,
4828                                              GTK_TREE_VIEW_TREE_LINE,
4829                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4830                                              y0,
4831                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4832                                              y2);
4833
4834                   tmp_node = tree->parent_node;
4835                   tmp_tree = tree->parent_tree;
4836
4837                   for (i = depth - 2; i > 0; i--)
4838                     {
4839                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4840                         gtk_tree_view_draw_line (tree_view, cr,
4841                                                  GTK_TREE_VIEW_TREE_LINE,
4842                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4843                                                  y0,
4844                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4845                                                  y2);
4846
4847                       tmp_node = tmp_tree->parent_node;
4848                       tmp_tree = tmp_tree->parent_tree;
4849                     }
4850                 }
4851             }
4852
4853           if (node == cursor && has_special_cell &&
4854               ((column == tree_view->priv->focus_column &&
4855                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4856                 gtk_widget_has_focus (widget)) ||
4857                (column == tree_view->priv->edited_column)))
4858             {
4859               _gtk_tree_view_column_cell_draw_focus (column,
4860                                                      cr,
4861                                                      &background_area,
4862                                                      &cell_area,
4863                                                      flags);
4864             }
4865
4866           cell_offset += column->width;
4867         }
4868
4869       if (node == drag_highlight)
4870         {
4871           /* Draw indicator for the drop
4872            */
4873           gint highlight_y = -1;
4874           GtkRBTree *tree = NULL;
4875           GtkRBNode *node = NULL;
4876
4877           switch (tree_view->priv->drag_dest_pos)
4878             {
4879             case GTK_TREE_VIEW_DROP_BEFORE:
4880               highlight_y = background_area.y - 1;
4881               if (highlight_y < 0)
4882                       highlight_y = 0;
4883               break;
4884
4885             case GTK_TREE_VIEW_DROP_AFTER:
4886               highlight_y = background_area.y + background_area.height - 1;
4887               break;
4888
4889             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4890             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4891               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4892
4893               if (tree == NULL)
4894                 break;
4895
4896               gtk_paint_focus (style,
4897                                cr,
4898                                gtk_widget_get_state (widget),
4899                                widget,
4900                                (is_first
4901                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4902                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4903                                 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4904                                    - focus_line_width / 2,
4905                                 gdk_window_get_width (tree_view->priv->bin_window),
4906                                 ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4907                                    - focus_line_width + 1);
4908               break;
4909             }
4910
4911           if (highlight_y >= 0)
4912             {
4913               gtk_tree_view_draw_line (tree_view, cr,
4914                                        GTK_TREE_VIEW_FOREGROUND_LINE,
4915                                        rtl ? highlight_x + expander_cell_width : highlight_x,
4916                                        highlight_y,
4917                                        rtl ? 0 : bin_window_width,
4918                                        highlight_y);
4919             }
4920         }
4921
4922       /* draw the big row-spanning focus rectangle, if needed */
4923       if (!has_special_cell && node == cursor &&
4924           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4925           gtk_widget_has_focus (widget))
4926         {
4927           gint tmp_y, tmp_height;
4928           GtkStateType focus_rect_state;
4929
4930           focus_rect_state =
4931             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4932             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4933              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4934               GTK_STATE_NORMAL));
4935
4936           if (draw_hgrid_lines)
4937             {
4938               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4939               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4940             }
4941           else
4942             {
4943               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4944               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4945             }
4946
4947           gtk_paint_focus (style,
4948                            cr,
4949                            focus_rect_state,
4950                            widget,
4951                            (is_first
4952                             ? (is_last ? "treeview" : "treeview-left" )
4953                             : (is_last ? "treeview-right" : "treeview-middle" )),
4954                            0, tmp_y,
4955                            gdk_window_get_width (tree_view->priv->bin_window),
4956                            tmp_height);
4957         }
4958
4959       y_offset += max_height;
4960       if (node->children)
4961         {
4962           GtkTreeIter parent = iter;
4963           gboolean has_child;
4964
4965           tree = node->children;
4966           node = tree->root;
4967
4968           g_assert (node != tree->nil);
4969
4970           while (node->left != tree->nil)
4971             node = node->left;
4972           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4973                                                     &iter,
4974                                                     &parent);
4975           depth++;
4976
4977           /* Sanity Check! */
4978           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4979         }
4980       else
4981         {
4982           gboolean done = FALSE;
4983
4984           do
4985             {
4986               node = _gtk_rbtree_next (tree, node);
4987               if (node != NULL)
4988                 {
4989                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4990                   done = TRUE;
4991
4992                   /* Sanity Check! */
4993                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4994                 }
4995               else
4996                 {
4997                   GtkTreeIter parent_iter = iter;
4998                   gboolean has_parent;
4999
5000                   node = tree->parent_node;
5001                   tree = tree->parent_tree;
5002                   if (tree == NULL)
5003                     /* we should go to done to free some memory */
5004                     goto done;
5005                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5006                                                            &iter,
5007                                                            &parent_iter);
5008                   depth--;
5009
5010                   /* Sanity check */
5011                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5012                 }
5013             }
5014           while (!done);
5015         }
5016     }
5017   while (y_offset < clip.height);
5018
5019 done:
5020   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5021
5022   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5023     gtk_tree_view_paint_rubber_band (tree_view, cr);
5024
5025   if (cursor_path)
5026     gtk_tree_path_free (cursor_path);
5027
5028   if (drag_dest_path)
5029     gtk_tree_path_free (drag_dest_path);
5030
5031   return FALSE;
5032 }
5033
5034 static gboolean
5035 gtk_tree_view_draw (GtkWidget *widget,
5036                     cairo_t   *cr)
5037 {
5038   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5039
5040   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5041     {
5042       GList *tmp_list;
5043
5044       cairo_save (cr);
5045
5046       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5047
5048       gtk_tree_view_bin_draw (widget, cr);
5049
5050       cairo_restore (cr);
5051
5052       /* We can't just chain up to Container::draw as it will try to send the
5053        * event to the headers, so we handle propagating it to our children
5054        * (eg. widgets being edited) ourselves.
5055        */
5056       tmp_list = tree_view->priv->children;
5057       while (tmp_list)
5058         {
5059           GtkTreeViewChild *child = tmp_list->data;
5060           tmp_list = tmp_list->next;
5061
5062           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5063         }
5064     }
5065
5066   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5067     {
5068       GList *list;
5069       
5070       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5071         {
5072           GtkTreeViewColumn *column = list->data;
5073
5074           if (column == tree_view->priv->drag_column)
5075             continue;
5076
5077           if (column->visible)
5078             gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5079                                           column->button,
5080                                           cr);
5081         }
5082     }
5083   
5084   if (tree_view->priv->drag_window &&
5085       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5086     {
5087       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5088                                     tree_view->priv->drag_column->button,
5089                                     cr);
5090     }
5091
5092   return TRUE;
5093 }
5094
5095 enum
5096 {
5097   DROP_HOME,
5098   DROP_RIGHT,
5099   DROP_LEFT,
5100   DROP_END
5101 };
5102
5103 /* returns 0x1 when no column has been found -- yes it's hackish */
5104 static GtkTreeViewColumn *
5105 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5106                                GtkTreeViewColumn *column,
5107                                gint               drop_position)
5108 {
5109   GtkTreeViewColumn *left_column = NULL;
5110   GtkTreeViewColumn *cur_column = NULL;
5111   GList *tmp_list;
5112
5113   if (!column->reorderable)
5114     return (GtkTreeViewColumn *)0x1;
5115
5116   switch (drop_position)
5117     {
5118       case DROP_HOME:
5119         /* find first column where we can drop */
5120         tmp_list = tree_view->priv->columns;
5121         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5122           return (GtkTreeViewColumn *)0x1;
5123
5124         while (tmp_list)
5125           {
5126             g_assert (tmp_list);
5127
5128             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5129             tmp_list = tmp_list->next;
5130
5131             if (left_column && left_column->visible == FALSE)
5132               continue;
5133
5134             if (!tree_view->priv->column_drop_func)
5135               return left_column;
5136
5137             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5138               {
5139                 left_column = cur_column;
5140                 continue;
5141               }
5142
5143             return left_column;
5144           }
5145
5146         if (!tree_view->priv->column_drop_func)
5147           return left_column;
5148
5149         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5150           return left_column;
5151         else
5152           return (GtkTreeViewColumn *)0x1;
5153         break;
5154
5155       case DROP_RIGHT:
5156         /* find first column after column where we can drop */
5157         tmp_list = tree_view->priv->columns;
5158
5159         for (; tmp_list; tmp_list = tmp_list->next)
5160           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5161             break;
5162
5163         if (!tmp_list || !tmp_list->next)
5164           return (GtkTreeViewColumn *)0x1;
5165
5166         tmp_list = tmp_list->next;
5167         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5168         tmp_list = tmp_list->next;
5169
5170         while (tmp_list)
5171           {
5172             g_assert (tmp_list);
5173
5174             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5175             tmp_list = tmp_list->next;
5176
5177             if (left_column && left_column->visible == FALSE)
5178               {
5179                 left_column = cur_column;
5180                 if (tmp_list)
5181                   tmp_list = tmp_list->next;
5182                 continue;
5183               }
5184
5185             if (!tree_view->priv->column_drop_func)
5186               return left_column;
5187
5188             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5189               {
5190                 left_column = cur_column;
5191                 continue;
5192               }
5193
5194             return left_column;
5195           }
5196
5197         if (!tree_view->priv->column_drop_func)
5198           return left_column;
5199
5200         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5201           return left_column;
5202         else
5203           return (GtkTreeViewColumn *)0x1;
5204         break;
5205
5206       case DROP_LEFT:
5207         /* find first column before column where we can drop */
5208         tmp_list = tree_view->priv->columns;
5209
5210         for (; tmp_list; tmp_list = tmp_list->next)
5211           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5212             break;
5213
5214         if (!tmp_list || !tmp_list->prev)
5215           return (GtkTreeViewColumn *)0x1;
5216
5217         tmp_list = tmp_list->prev;
5218         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5219         tmp_list = tmp_list->prev;
5220
5221         while (tmp_list)
5222           {
5223             g_assert (tmp_list);
5224
5225             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5226
5227             if (left_column && !left_column->visible)
5228               {
5229                 /*if (!tmp_list->prev)
5230                   return (GtkTreeViewColumn *)0x1;
5231                   */
5232 /*
5233                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5234                 tmp_list = tmp_list->prev->prev;
5235                 continue;*/
5236
5237                 cur_column = left_column;
5238                 if (tmp_list)
5239                   tmp_list = tmp_list->prev;
5240                 continue;
5241               }
5242
5243             if (!tree_view->priv->column_drop_func)
5244               return left_column;
5245
5246             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5247               return left_column;
5248
5249             cur_column = left_column;
5250             tmp_list = tmp_list->prev;
5251           }
5252
5253         if (!tree_view->priv->column_drop_func)
5254           return NULL;
5255
5256         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5257           return NULL;
5258         else
5259           return (GtkTreeViewColumn *)0x1;
5260         break;
5261
5262       case DROP_END:
5263         /* same as DROP_HOME case, but doing it backwards */
5264         tmp_list = g_list_last (tree_view->priv->columns);
5265         cur_column = NULL;
5266
5267         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5268           return (GtkTreeViewColumn *)0x1;
5269
5270         while (tmp_list)
5271           {
5272             g_assert (tmp_list);
5273
5274             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5275
5276             if (left_column && !left_column->visible)
5277               {
5278                 cur_column = left_column;
5279                 tmp_list = tmp_list->prev;
5280               }
5281
5282             if (!tree_view->priv->column_drop_func)
5283               return left_column;
5284
5285             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5286               return left_column;
5287
5288             cur_column = left_column;
5289             tmp_list = tmp_list->prev;
5290           }
5291
5292         if (!tree_view->priv->column_drop_func)
5293           return NULL;
5294
5295         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5296           return NULL;
5297         else
5298           return (GtkTreeViewColumn *)0x1;
5299         break;
5300     }
5301
5302   return (GtkTreeViewColumn *)0x1;
5303 }
5304
5305 static gboolean
5306 gtk_tree_view_key_press (GtkWidget   *widget,
5307                          GdkEventKey *event)
5308 {
5309   GtkTreeView *tree_view = (GtkTreeView *) widget;
5310
5311   if (tree_view->priv->rubber_band_status)
5312     {
5313       if (event->keyval == GDK_KEY_Escape)
5314         gtk_tree_view_stop_rubber_band (tree_view);
5315
5316       return TRUE;
5317     }
5318
5319   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5320     {
5321       if (event->keyval == GDK_KEY_Escape)
5322         {
5323           tree_view->priv->cur_reorder = NULL;
5324           gtk_tree_view_button_release_drag_column (widget, NULL);
5325         }
5326       return TRUE;
5327     }
5328
5329   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5330     {
5331       GList *focus_column;
5332       gboolean rtl;
5333
5334       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5335
5336       for (focus_column = tree_view->priv->columns;
5337            focus_column;
5338            focus_column = focus_column->next)
5339         {
5340           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5341
5342           if (gtk_widget_has_focus (column->button))
5343             break;
5344         }
5345
5346       if (focus_column &&
5347           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5348           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5349            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5350         {
5351           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5352
5353           if (!column->resizable)
5354             {
5355               gtk_widget_error_bell (widget);
5356               return TRUE;
5357             }
5358
5359           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5360               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5361             {
5362               GtkRequisition button_req;
5363               gint old_width = column->resized_width;
5364
5365               gtk_widget_get_preferred_size (column->button, &button_req, NULL);
5366
5367               column->resized_width = MAX (column->resized_width,
5368                                            column->width);
5369               column->resized_width -= 2;
5370               if (column->resized_width < 0)
5371                 column->resized_width = 0;
5372
5373               if (column->min_width == -1)
5374                 column->resized_width = MAX (button_req.width,
5375                                              column->resized_width);
5376               else
5377                 {
5378                   column->resized_width = MAX (column->min_width,
5379                                                column->resized_width);
5380                 }
5381
5382               if (column->max_width != -1)
5383                 column->resized_width = MIN (column->resized_width,
5384                                              column->max_width);
5385
5386               column->use_resized_width = TRUE;
5387
5388               if (column->resized_width != old_width)
5389                 gtk_widget_queue_resize (widget);
5390               else
5391                 gtk_widget_error_bell (widget);
5392             }
5393           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5394                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5395             {
5396               gint old_width = column->resized_width;
5397
5398               column->resized_width = MAX (column->resized_width,
5399                                            column->width);
5400               column->resized_width += 2;
5401
5402               if (column->max_width != -1)
5403                 column->resized_width = MIN (column->resized_width,
5404                                              column->max_width);
5405
5406               column->use_resized_width = TRUE;
5407
5408               if (column->resized_width != old_width)
5409                 gtk_widget_queue_resize (widget);
5410               else
5411                 gtk_widget_error_bell (widget);
5412             }
5413
5414           return TRUE;
5415         }
5416
5417       if (focus_column &&
5418           (event->state & GDK_MOD1_MASK) &&
5419           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5420            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5421            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5422            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5423         {
5424           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5425
5426           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5427               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5428             {
5429               GtkTreeViewColumn *col;
5430               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5431               if (col != (GtkTreeViewColumn *)0x1)
5432                 gtk_tree_view_move_column_after (tree_view, column, col);
5433               else
5434                 gtk_widget_error_bell (widget);
5435             }
5436           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5437                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5438             {
5439               GtkTreeViewColumn *col;
5440               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5441               if (col != (GtkTreeViewColumn *)0x1)
5442                 gtk_tree_view_move_column_after (tree_view, column, col);
5443               else
5444                 gtk_widget_error_bell (widget);
5445             }
5446           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5447             {
5448               GtkTreeViewColumn *col;
5449               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5450               if (col != (GtkTreeViewColumn *)0x1)
5451                 gtk_tree_view_move_column_after (tree_view, column, col);
5452               else
5453                 gtk_widget_error_bell (widget);
5454             }
5455           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5456             {
5457               GtkTreeViewColumn *col;
5458               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5459               if (col != (GtkTreeViewColumn *)0x1)
5460                 gtk_tree_view_move_column_after (tree_view, column, col);
5461               else
5462                 gtk_widget_error_bell (widget);
5463             }
5464
5465           return TRUE;
5466         }
5467     }
5468
5469   /* Chain up to the parent class.  It handles the keybindings. */
5470   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5471     return TRUE;
5472
5473   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5474     {
5475       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5476       return FALSE;
5477     }
5478
5479   /* We pass the event to the search_entry.  If its text changes, then we start
5480    * the typeahead find capabilities. */
5481   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5482       && tree_view->priv->enable_search
5483       && !tree_view->priv->search_custom_entry_set)
5484     {
5485       GdkEvent *new_event;
5486       char *old_text;
5487       const char *new_text;
5488       gboolean retval;
5489       GdkScreen *screen;
5490       gboolean text_modified;
5491       gulong popup_menu_id;
5492
5493       gtk_tree_view_ensure_interactive_directory (tree_view);
5494
5495       /* Make a copy of the current text */
5496       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5497       new_event = gdk_event_copy ((GdkEvent *) event);
5498       g_object_unref (((GdkEventKey *) new_event)->window);
5499       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5500       gtk_widget_realize (tree_view->priv->search_window);
5501
5502       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5503                                         "popup-menu", G_CALLBACK (gtk_true),
5504                                         NULL);
5505
5506       /* Move the entry off screen */
5507       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5508       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5509                        gdk_screen_get_width (screen) + 1,
5510                        gdk_screen_get_height (screen) + 1);
5511       gtk_widget_show (tree_view->priv->search_window);
5512
5513       /* Send the event to the window.  If the preedit_changed signal is emitted
5514        * during this event, we will set priv->imcontext_changed  */
5515       tree_view->priv->imcontext_changed = FALSE;
5516       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5517       gdk_event_free (new_event);
5518       gtk_widget_hide (tree_view->priv->search_window);
5519
5520       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5521                                    popup_menu_id);
5522
5523       /* We check to make sure that the entry tried to handle the text, and that
5524        * the text has changed.
5525        */
5526       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5527       text_modified = strcmp (old_text, new_text) != 0;
5528       g_free (old_text);
5529       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5530           (retval && text_modified))               /* ...or the text was modified */
5531         {
5532           if (gtk_tree_view_real_start_interactive_search (tree_view,
5533                                                            gdk_event_get_device ((GdkEvent *) event),
5534                                                            FALSE))
5535             {
5536               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5537               return TRUE;
5538             }
5539           else
5540             {
5541               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5542               return FALSE;
5543             }
5544         }
5545     }
5546
5547   return FALSE;
5548 }
5549
5550 static gboolean
5551 gtk_tree_view_key_release (GtkWidget   *widget,
5552                            GdkEventKey *event)
5553 {
5554   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5555
5556   if (tree_view->priv->rubber_band_status)
5557     return TRUE;
5558
5559   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5560 }
5561
5562 /* FIXME Is this function necessary? Can I get an enter_notify event
5563  * w/o either an expose event or a mouse motion event?
5564  */
5565 static gboolean
5566 gtk_tree_view_enter_notify (GtkWidget        *widget,
5567                             GdkEventCrossing *event)
5568 {
5569   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5570   GtkRBTree *tree;
5571   GtkRBNode *node;
5572   gint new_y;
5573
5574   /* Sanity check it */
5575   if (event->window != tree_view->priv->bin_window)
5576     return FALSE;
5577
5578   if (tree_view->priv->tree == NULL)
5579     return FALSE;
5580
5581   if (event->mode == GDK_CROSSING_GRAB ||
5582       event->mode == GDK_CROSSING_GTK_GRAB ||
5583       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5584       event->mode == GDK_CROSSING_STATE_CHANGED)
5585     return TRUE;
5586
5587   /* find the node internally */
5588   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5589   if (new_y < 0)
5590     new_y = 0;
5591   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5592
5593   tree_view->priv->event_last_x = event->x;
5594   tree_view->priv->event_last_y = event->y;
5595
5596   if ((tree_view->priv->button_pressed_node == NULL) ||
5597       (tree_view->priv->button_pressed_node == node))
5598     prelight_or_select (tree_view, tree, node, event->x, event->y);
5599
5600   return TRUE;
5601 }
5602
5603 static gboolean
5604 gtk_tree_view_leave_notify (GtkWidget        *widget,
5605                             GdkEventCrossing *event)
5606 {
5607   GtkTreeView *tree_view;
5608
5609   if (event->mode == GDK_CROSSING_GRAB)
5610     return TRUE;
5611
5612   tree_view = GTK_TREE_VIEW (widget);
5613
5614   if (tree_view->priv->prelight_node)
5615     _gtk_tree_view_queue_draw_node (tree_view,
5616                                    tree_view->priv->prelight_tree,
5617                                    tree_view->priv->prelight_node,
5618                                    NULL);
5619
5620   tree_view->priv->event_last_x = -10000;
5621   tree_view->priv->event_last_y = -10000;
5622
5623   prelight_or_select (tree_view,
5624                       NULL, NULL,
5625                       -1000, -1000); /* coords not possibly over an arrow */
5626
5627   return TRUE;
5628 }
5629
5630
5631 static gint
5632 gtk_tree_view_focus_out (GtkWidget     *widget,
5633                          GdkEventFocus *event)
5634 {
5635   GtkTreeView *tree_view;
5636
5637   tree_view = GTK_TREE_VIEW (widget);
5638
5639   gtk_widget_queue_draw (widget);
5640
5641   /* destroy interactive search dialog */
5642   if (tree_view->priv->search_window)
5643     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5644                                       gdk_event_get_device ((GdkEvent *) event));
5645
5646   return FALSE;
5647 }
5648
5649
5650 /* Incremental Reflow
5651  */
5652
5653 static void
5654 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5655                                  GtkRBTree   *tree,
5656                                  GtkRBNode   *node)
5657 {
5658   GtkAllocation allocation;
5659   gint y;
5660
5661   y = _gtk_rbtree_node_find_offset (tree, node)
5662     - tree_view->priv->vadjustment->value
5663     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5664
5665   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5666   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5667                               0, y,
5668                               allocation.width,
5669                               GTK_RBNODE_GET_HEIGHT (node));
5670 }
5671
5672 static gboolean
5673 node_is_visible (GtkTreeView *tree_view,
5674                  GtkRBTree   *tree,
5675                  GtkRBNode   *node)
5676 {
5677   int y;
5678   int height;
5679
5680   y = _gtk_rbtree_node_find_offset (tree, node);
5681   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5682
5683   if (y >= tree_view->priv->vadjustment->value &&
5684       y + height <= (tree_view->priv->vadjustment->value
5685                      + tree_view->priv->vadjustment->page_size))
5686     return TRUE;
5687
5688   return FALSE;
5689 }
5690
5691 /* Returns TRUE if it updated the size
5692  */
5693 static gboolean
5694 validate_row (GtkTreeView *tree_view,
5695               GtkRBTree   *tree,
5696               GtkRBNode   *node,
5697               GtkTreeIter *iter,
5698               GtkTreePath *path)
5699 {
5700   GtkTreeViewColumn *column;
5701   GList *list, *first_column, *last_column;
5702   gint height = 0;
5703   gint horizontal_separator;
5704   gint vertical_separator;
5705   gint focus_line_width;
5706   gint depth = gtk_tree_path_get_depth (path);
5707   gboolean retval = FALSE;
5708   gboolean is_separator = FALSE;
5709   gboolean draw_vgrid_lines, draw_hgrid_lines;
5710   gint focus_pad;
5711   gint grid_line_width;
5712   gboolean wide_separators;
5713   gint separator_height;
5714
5715   /* double check the row needs validating */
5716   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5717       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5718     return FALSE;
5719
5720   is_separator = row_is_separator (tree_view, iter, NULL);
5721
5722   gtk_widget_style_get (GTK_WIDGET (tree_view),
5723                         "focus-padding", &focus_pad,
5724                         "focus-line-width", &focus_line_width,
5725                         "horizontal-separator", &horizontal_separator,
5726                         "vertical-separator", &vertical_separator,
5727                         "grid-line-width", &grid_line_width,
5728                         "wide-separators",  &wide_separators,
5729                         "separator-height", &separator_height,
5730                         NULL);
5731   
5732   draw_vgrid_lines =
5733     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5734     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5735   draw_hgrid_lines =
5736     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5737     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5738
5739   for (last_column = g_list_last (tree_view->priv->columns);
5740        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5741        last_column = last_column->prev)
5742     ;
5743
5744   for (first_column = g_list_first (tree_view->priv->columns);
5745        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5746        first_column = first_column->next)
5747     ;
5748
5749   for (list = tree_view->priv->columns; list; list = list->next)
5750     {
5751       gint tmp_width;
5752       gint tmp_height;
5753
5754       column = list->data;
5755
5756       if (! column->visible)
5757         continue;
5758
5759       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5760         continue;
5761
5762       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5763                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5764                                                node->children?TRUE:FALSE);
5765       gtk_tree_view_column_cell_get_size (column,
5766                                           NULL, NULL, NULL,
5767                                           &tmp_width, &tmp_height);
5768
5769       if (!is_separator)
5770         {
5771           tmp_height += vertical_separator;
5772           height = MAX (height, tmp_height);
5773           height = MAX (height, tree_view->priv->expander_size);
5774         }
5775       else
5776         {
5777           if (wide_separators)
5778             height = separator_height + 2 * focus_pad;
5779           else
5780             height = 2 + 2 * focus_pad;
5781         }
5782
5783       if (gtk_tree_view_is_expander_column (tree_view, column))
5784         {
5785           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5786
5787           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5788             tmp_width += depth * tree_view->priv->expander_size;
5789         }
5790       else
5791         tmp_width = tmp_width + horizontal_separator;
5792
5793       if (draw_vgrid_lines)
5794         {
5795           if (list->data == first_column || list->data == last_column)
5796             tmp_width += grid_line_width / 2.0;
5797           else
5798             tmp_width += grid_line_width;
5799         }
5800
5801       if (tmp_width > column->requested_width)
5802         {
5803           retval = TRUE;
5804           column->requested_width = tmp_width;
5805         }
5806     }
5807
5808   if (draw_hgrid_lines)
5809     height += grid_line_width;
5810
5811   if (height != GTK_RBNODE_GET_HEIGHT (node))
5812     {
5813       retval = TRUE;
5814       _gtk_rbtree_node_set_height (tree, node, height);
5815     }
5816   _gtk_rbtree_node_mark_valid (tree, node);
5817   tree_view->priv->post_validation_flag = TRUE;
5818
5819   return retval;
5820 }
5821
5822
5823 static void
5824 validate_visible_area (GtkTreeView *tree_view)
5825 {
5826   GtkAllocation allocation;
5827   GtkTreePath *path = NULL;
5828   GtkTreePath *above_path = NULL;
5829   GtkTreeIter iter;
5830   GtkRBTree *tree = NULL;
5831   GtkRBNode *node = NULL;
5832   gboolean need_redraw = FALSE;
5833   gboolean size_changed = FALSE;
5834   gint total_height;
5835   gint area_above = 0;
5836   gint area_below = 0;
5837
5838   if (tree_view->priv->tree == NULL)
5839     return;
5840
5841   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5842       tree_view->priv->scroll_to_path == NULL)
5843     return;
5844
5845   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5846   total_height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5847
5848   if (total_height == 0)
5849     return;
5850
5851   /* First, we check to see if we need to scroll anywhere
5852    */
5853   if (tree_view->priv->scroll_to_path)
5854     {
5855       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5856       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5857         {
5858           /* we are going to scroll, and will update dy */
5859           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5860           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5861               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5862             {
5863               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5864               if (validate_row (tree_view, tree, node, &iter, path))
5865                 size_changed = TRUE;
5866             }
5867
5868           if (tree_view->priv->scroll_to_use_align)
5869             {
5870               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5871               area_above = (total_height - height) *
5872                 tree_view->priv->scroll_to_row_align;
5873               area_below = total_height - area_above - height;
5874               area_above = MAX (area_above, 0);
5875               area_below = MAX (area_below, 0);
5876             }
5877           else
5878             {
5879               /* two cases:
5880                * 1) row not visible
5881                * 2) row visible
5882                */
5883               gint dy;
5884               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5885
5886               dy = _gtk_rbtree_node_find_offset (tree, node);
5887
5888               if (dy >= tree_view->priv->vadjustment->value &&
5889                   dy + height <= (tree_view->priv->vadjustment->value
5890                                   + tree_view->priv->vadjustment->page_size))
5891                 {
5892                   /* row visible: keep the row at the same position */
5893                   area_above = dy - tree_view->priv->vadjustment->value;
5894                   area_below = (tree_view->priv->vadjustment->value +
5895                                 tree_view->priv->vadjustment->page_size)
5896                                - dy - height;
5897                 }
5898               else
5899                 {
5900                   /* row not visible */
5901                   if (dy >= 0
5902                       && dy + height <= tree_view->priv->vadjustment->page_size)
5903                     {
5904                       /* row at the beginning -- fixed */
5905                       area_above = dy;
5906                       area_below = tree_view->priv->vadjustment->page_size
5907                                    - area_above - height;
5908                     }
5909                   else if (dy >= (tree_view->priv->vadjustment->upper -
5910                                   tree_view->priv->vadjustment->page_size))
5911                     {
5912                       /* row at the end -- fixed */
5913                       area_above = dy - (tree_view->priv->vadjustment->upper -
5914                                    tree_view->priv->vadjustment->page_size);
5915                       area_below = tree_view->priv->vadjustment->page_size -
5916                                    area_above - height;
5917
5918                       if (area_below < 0)
5919                         {
5920                           area_above = tree_view->priv->vadjustment->page_size - height;
5921                           area_below = 0;
5922                         }
5923                     }
5924                   else
5925                     {
5926                       /* row somewhere in the middle, bring it to the top
5927                        * of the view
5928                        */
5929                       area_above = 0;
5930                       area_below = total_height - height;
5931                     }
5932                 }
5933             }
5934         }
5935       else
5936         /* the scroll to isn't valid; ignore it.
5937          */
5938         {
5939           if (tree_view->priv->scroll_to_path && !path)
5940             {
5941               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5942               tree_view->priv->scroll_to_path = NULL;
5943             }
5944           if (path)
5945             gtk_tree_path_free (path);
5946           path = NULL;
5947         }      
5948     }
5949
5950   /* We didn't have a scroll_to set, so we just handle things normally
5951    */
5952   if (path == NULL)
5953     {
5954       gint offset;
5955
5956       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5957                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5958                                         &tree, &node);
5959       if (node == NULL)
5960         {
5961           /* In this case, nothing has been validated */
5962           path = gtk_tree_path_new_first ();
5963           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5964         }
5965       else
5966         {
5967           path = _gtk_tree_view_find_path (tree_view, tree, node);
5968           total_height += offset;
5969         }
5970
5971       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5972
5973       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5974           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5975         {
5976           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5977           if (validate_row (tree_view, tree, node, &iter, path))
5978             size_changed = TRUE;
5979         }
5980       area_above = 0;
5981       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5982     }
5983
5984   above_path = gtk_tree_path_copy (path);
5985
5986   /* if we do not validate any row above the new top_row, we will make sure
5987    * that the row immediately above top_row has been validated. (if we do not
5988    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5989    * when invalidated that row's height will be zero. and this will mess up
5990    * scrolling).
5991    */
5992   if (area_above == 0)
5993     {
5994       GtkRBTree *tmptree;
5995       GtkRBNode *tmpnode;
5996
5997       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5998       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5999
6000       if (tmpnode)
6001         {
6002           GtkTreePath *tmppath;
6003           GtkTreeIter tmpiter;
6004
6005           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6006           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6007
6008           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6009               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6010             {
6011               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6012               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6013                 size_changed = TRUE;
6014             }
6015
6016           gtk_tree_path_free (tmppath);
6017         }
6018     }
6019
6020   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6021    * backwards is much slower then forward, as there is no iter_prev function.
6022    * We go forwards first in case we run out of tree.  Then we go backwards to
6023    * fill out the top.
6024    */
6025   while (node && area_below > 0)
6026     {
6027       if (node->children)
6028         {
6029           GtkTreeIter parent = iter;
6030           gboolean has_child;
6031
6032           tree = node->children;
6033           node = tree->root;
6034
6035           g_assert (node != tree->nil);
6036
6037           while (node->left != tree->nil)
6038             node = node->left;
6039           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6040                                                     &iter,
6041                                                     &parent);
6042           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6043           gtk_tree_path_down (path);
6044         }
6045       else
6046         {
6047           gboolean done = FALSE;
6048           do
6049             {
6050               node = _gtk_rbtree_next (tree, node);
6051               if (node != NULL)
6052                 {
6053                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6054                   done = TRUE;
6055                   gtk_tree_path_next (path);
6056
6057                   /* Sanity Check! */
6058                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6059                 }
6060               else
6061                 {
6062                   GtkTreeIter parent_iter = iter;
6063                   gboolean has_parent;
6064
6065                   node = tree->parent_node;
6066                   tree = tree->parent_tree;
6067                   if (tree == NULL)
6068                     break;
6069                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6070                                                            &iter,
6071                                                            &parent_iter);
6072                   gtk_tree_path_up (path);
6073
6074                   /* Sanity check */
6075                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6076                 }
6077             }
6078           while (!done);
6079         }
6080
6081       if (!node)
6082         break;
6083
6084       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6085           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6086         {
6087           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6088           if (validate_row (tree_view, tree, node, &iter, path))
6089               size_changed = TRUE;
6090         }
6091
6092       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6093     }
6094   gtk_tree_path_free (path);
6095
6096   /* If we ran out of tree, and have extra area_below left, we need to add it
6097    * to area_above */
6098   if (area_below > 0)
6099     area_above += area_below;
6100
6101   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6102
6103   /* We walk backwards */
6104   while (area_above > 0)
6105     {
6106       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6107
6108       /* Always find the new path in the tree.  We cannot just assume
6109        * a gtk_tree_path_prev() is enough here, as there might be children
6110        * in between this node and the previous sibling node.  If this
6111        * appears to be a performance hotspot in profiles, we can look into
6112        * intrigate logic for keeping path, node and iter in sync like
6113        * we do for forward walks.  (Which will be hard because of the lacking
6114        * iter_prev).
6115        */
6116
6117       if (node == NULL)
6118         break;
6119
6120       gtk_tree_path_free (above_path);
6121       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6122
6123       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6124
6125       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6126           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6127         {
6128           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6129           if (validate_row (tree_view, tree, node, &iter, above_path))
6130             size_changed = TRUE;
6131         }
6132       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6133     }
6134
6135   /* if we scrolled to a path, we need to set the dy here,
6136    * and sync the top row accordingly
6137    */
6138   if (tree_view->priv->scroll_to_path)
6139     {
6140       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6141       gtk_tree_view_top_row_to_dy (tree_view);
6142
6143       need_redraw = TRUE;
6144     }
6145   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6146     {
6147       /* when we are not scrolling, we should never set dy to something
6148        * else than zero. we update top_row to be in sync with dy = 0.
6149        */
6150       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6151       gtk_tree_view_dy_to_top_row (tree_view);
6152     }
6153   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6154     {
6155       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6156       gtk_tree_view_dy_to_top_row (tree_view);
6157     }
6158   else
6159     gtk_tree_view_top_row_to_dy (tree_view);
6160
6161   /* update width/height and queue a resize */
6162   if (size_changed)
6163     {
6164       GtkRequisition requisition;
6165
6166       /* We temporarily guess a size, under the assumption that it will be the
6167        * same when we get our next size_allocate.  If we don't do this, we'll be
6168        * in an inconsistent state if we call top_row_to_dy. */
6169
6170       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6171                                      &requisition, NULL);
6172       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6173       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6174       gtk_adjustment_changed (tree_view->priv->hadjustment);
6175       gtk_adjustment_changed (tree_view->priv->vadjustment);
6176       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6177     }
6178
6179   if (tree_view->priv->scroll_to_path)
6180     {
6181       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6182       tree_view->priv->scroll_to_path = NULL;
6183     }
6184
6185   if (above_path)
6186     gtk_tree_path_free (above_path);
6187
6188   if (tree_view->priv->scroll_to_column)
6189     {
6190       tree_view->priv->scroll_to_column = NULL;
6191     }
6192   if (need_redraw)
6193     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6194 }
6195
6196 static void
6197 initialize_fixed_height_mode (GtkTreeView *tree_view)
6198 {
6199   if (!tree_view->priv->tree)
6200     return;
6201
6202   if (tree_view->priv->fixed_height < 0)
6203     {
6204       GtkTreeIter iter;
6205       GtkTreePath *path;
6206
6207       GtkRBTree *tree = NULL;
6208       GtkRBNode *node = NULL;
6209
6210       tree = tree_view->priv->tree;
6211       node = tree->root;
6212
6213       path = _gtk_tree_view_find_path (tree_view, tree, node);
6214       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6215
6216       validate_row (tree_view, tree, node, &iter, path);
6217
6218       gtk_tree_path_free (path);
6219
6220       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6221     }
6222
6223    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6224                                  tree_view->priv->fixed_height, TRUE);
6225 }
6226
6227 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6228  * the left-most uninvalidated node.  We then try walking right, validating
6229  * nodes.  Once we find a valid node, we repeat the previous process of finding
6230  * the first invalid node.
6231  */
6232
6233 static gboolean
6234 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6235 {
6236   GtkRBTree *tree = NULL;
6237   GtkRBNode *node = NULL;
6238   gboolean validated_area = FALSE;
6239   gint retval = TRUE;
6240   GtkTreePath *path = NULL;
6241   GtkTreeIter iter;
6242   GTimer *timer;
6243   gint i = 0;
6244
6245   gint prev_height = -1;
6246   gboolean fixed_height = TRUE;
6247
6248   g_assert (tree_view);
6249
6250   if (tree_view->priv->tree == NULL)
6251       return FALSE;
6252
6253   if (tree_view->priv->fixed_height_mode)
6254     {
6255       if (tree_view->priv->fixed_height < 0)
6256         initialize_fixed_height_mode (tree_view);
6257
6258       return FALSE;
6259     }
6260
6261   timer = g_timer_new ();
6262   g_timer_start (timer);
6263
6264   do
6265     {
6266       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6267         {
6268           retval = FALSE;
6269           goto done;
6270         }
6271
6272       if (path != NULL)
6273         {
6274           node = _gtk_rbtree_next (tree, node);
6275           if (node != NULL)
6276             {
6277               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6278               gtk_tree_path_next (path);
6279             }
6280           else
6281             {
6282               gtk_tree_path_free (path);
6283               path = NULL;
6284             }
6285         }
6286
6287       if (path == NULL)
6288         {
6289           tree = tree_view->priv->tree;
6290           node = tree_view->priv->tree->root;
6291
6292           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6293
6294           do
6295             {
6296               if (node->left != tree->nil &&
6297                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6298                 {
6299                   node = node->left;
6300                 }
6301               else if (node->right != tree->nil &&
6302                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6303                 {
6304                   node = node->right;
6305                 }
6306               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6307                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6308                 {
6309                   break;
6310                 }
6311               else if (node->children != NULL)
6312                 {
6313                   tree = node->children;
6314                   node = tree->root;
6315                 }
6316               else
6317                 /* RBTree corruption!  All bad */
6318                 g_assert_not_reached ();
6319             }
6320           while (TRUE);
6321           path = _gtk_tree_view_find_path (tree_view, tree, node);
6322           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6323         }
6324
6325       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6326                        validated_area;
6327
6328       if (!tree_view->priv->fixed_height_check)
6329         {
6330           gint height;
6331
6332           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6333           if (prev_height < 0)
6334             prev_height = height;
6335           else if (prev_height != height)
6336             fixed_height = FALSE;
6337         }
6338
6339       i++;
6340     }
6341   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6342
6343   if (!tree_view->priv->fixed_height_check)
6344    {
6345      if (fixed_height)
6346        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6347
6348      tree_view->priv->fixed_height_check = 1;
6349    }
6350   
6351  done:
6352   if (validated_area)
6353     {
6354       GtkRequisition requisition;
6355
6356       /* We temporarily guess a size, under the assumption that it will be the
6357        * same when we get our next size_allocate.  If we don't do this, we'll be
6358        * in an inconsistent state when we call top_row_to_dy. */
6359
6360       /* FIXME: This is called from size_request, for some reason it is not infinitely
6361        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6362        * not allowed (from inside ->get_preferred_width/height() implementations, one
6363        * should call the vfuncs directly). However what is desired here is the full
6364        * size including any margins and limited by any alignment (i.e. after 
6365        * GtkWidget:adjust_size_request() is called).
6366        *
6367        * Currently bypassing this but the real solution is to not update the scroll adjustments
6368        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6369        */
6370       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition);
6371
6372       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6373       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6374       gtk_adjustment_changed (tree_view->priv->hadjustment);
6375       gtk_adjustment_changed (tree_view->priv->vadjustment);
6376
6377       if (queue_resize)
6378         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6379     }
6380
6381   if (path) gtk_tree_path_free (path);
6382   g_timer_destroy (timer);
6383
6384   return retval;
6385 }
6386
6387 static gboolean
6388 validate_rows (GtkTreeView *tree_view)
6389 {
6390   gboolean retval;
6391   
6392   retval = do_validate_rows (tree_view, TRUE);
6393   
6394   if (! retval && tree_view->priv->validate_rows_timer)
6395     {
6396       g_source_remove (tree_view->priv->validate_rows_timer);
6397       tree_view->priv->validate_rows_timer = 0;
6398     }
6399
6400   return retval;
6401 }
6402
6403 static gboolean
6404 validate_rows_handler (GtkTreeView *tree_view)
6405 {
6406   gboolean retval;
6407
6408   retval = do_validate_rows (tree_view, TRUE);
6409   if (! retval && tree_view->priv->validate_rows_timer)
6410     {
6411       g_source_remove (tree_view->priv->validate_rows_timer);
6412       tree_view->priv->validate_rows_timer = 0;
6413     }
6414
6415   return retval;
6416 }
6417
6418 static gboolean
6419 do_presize_handler (GtkTreeView *tree_view)
6420 {
6421   if (tree_view->priv->mark_rows_col_dirty)
6422     {
6423       if (tree_view->priv->tree)
6424         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6425       tree_view->priv->mark_rows_col_dirty = FALSE;
6426     }
6427   validate_visible_area (tree_view);
6428   tree_view->priv->presize_handler_timer = 0;
6429
6430   if (tree_view->priv->fixed_height_mode)
6431     {
6432       GtkRequisition requisition;
6433
6434       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6435                                      &requisition, NULL);
6436
6437       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6438       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6439       gtk_adjustment_changed (tree_view->priv->hadjustment);
6440       gtk_adjustment_changed (tree_view->priv->vadjustment);
6441       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6442     }
6443                    
6444   return FALSE;
6445 }
6446
6447 static gboolean
6448 presize_handler_callback (gpointer data)
6449 {
6450   do_presize_handler (GTK_TREE_VIEW (data));
6451                    
6452   return FALSE;
6453 }
6454
6455 static void
6456 install_presize_handler (GtkTreeView *tree_view)
6457 {
6458   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6459     return;
6460
6461   if (! tree_view->priv->presize_handler_timer)
6462     {
6463       tree_view->priv->presize_handler_timer =
6464         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6465     }
6466   if (! tree_view->priv->validate_rows_timer)
6467     {
6468       tree_view->priv->validate_rows_timer =
6469         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6470     }
6471 }
6472
6473 static void
6474 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6475 {
6476   /* Prior to drawing, we make sure the visible area is validated. */
6477   if (tree_view->priv->presize_handler_timer)
6478     {
6479       g_source_remove (tree_view->priv->presize_handler_timer);
6480       tree_view->priv->presize_handler_timer = 0;
6481
6482       do_presize_handler (tree_view);
6483     }
6484
6485   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6486 }
6487
6488 static gboolean
6489 scroll_sync_handler (GtkTreeView *tree_view)
6490 {
6491   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6492     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6493   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6494     gtk_tree_view_top_row_to_dy (tree_view);
6495   else
6496     gtk_tree_view_dy_to_top_row (tree_view);
6497
6498   tree_view->priv->scroll_sync_timer = 0;
6499
6500   return FALSE;
6501 }
6502
6503 static void
6504 install_scroll_sync_handler (GtkTreeView *tree_view)
6505 {
6506   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6507     return;
6508
6509   if (!tree_view->priv->scroll_sync_timer)
6510     {
6511       tree_view->priv->scroll_sync_timer =
6512         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6513     }
6514 }
6515
6516 static void
6517 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6518                            GtkTreePath *path,
6519                            gint         offset)
6520 {
6521   gtk_tree_row_reference_free (tree_view->priv->top_row);
6522
6523   if (!path)
6524     {
6525       tree_view->priv->top_row = NULL;
6526       tree_view->priv->top_row_dy = 0;
6527     }
6528   else
6529     {
6530       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6531       tree_view->priv->top_row_dy = offset;
6532     }
6533 }
6534
6535 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6536  * it's set to be NULL, and top_row_dy is 0;
6537  */
6538 static void
6539 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6540 {
6541   gint offset;
6542   GtkTreePath *path;
6543   GtkRBTree *tree;
6544   GtkRBNode *node;
6545
6546   if (tree_view->priv->tree == NULL)
6547     {
6548       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6549     }
6550   else
6551     {
6552       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6553                                         tree_view->priv->dy,
6554                                         &tree, &node);
6555
6556       if (tree == NULL)
6557         {
6558           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6559         }
6560       else
6561         {
6562           path = _gtk_tree_view_find_path (tree_view, tree, node);
6563           gtk_tree_view_set_top_row (tree_view, path, offset);
6564           gtk_tree_path_free (path);
6565         }
6566     }
6567 }
6568
6569 static void
6570 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6571 {
6572   GtkTreePath *path;
6573   GtkRBTree *tree;
6574   GtkRBNode *node;
6575   int new_dy;
6576
6577   /* Avoid recursive calls */
6578   if (tree_view->priv->in_top_row_to_dy)
6579     return;
6580
6581   if (tree_view->priv->top_row)
6582     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6583   else
6584     path = NULL;
6585
6586   if (!path)
6587     tree = NULL;
6588   else
6589     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6590
6591   if (path)
6592     gtk_tree_path_free (path);
6593
6594   if (tree == NULL)
6595     {
6596       /* keep dy and set new toprow */
6597       gtk_tree_row_reference_free (tree_view->priv->top_row);
6598       tree_view->priv->top_row = NULL;
6599       tree_view->priv->top_row_dy = 0;
6600       /* DO NOT install the idle handler */
6601       gtk_tree_view_dy_to_top_row (tree_view);
6602       return;
6603     }
6604
6605   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6606       < tree_view->priv->top_row_dy)
6607     {
6608       /* new top row -- do NOT install the idle handler */
6609       gtk_tree_view_dy_to_top_row (tree_view);
6610       return;
6611     }
6612
6613   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6614   new_dy += tree_view->priv->top_row_dy;
6615
6616   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6617     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6618
6619   new_dy = MAX (0, new_dy);
6620
6621   tree_view->priv->in_top_row_to_dy = TRUE;
6622   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6623   tree_view->priv->in_top_row_to_dy = FALSE;
6624 }
6625
6626
6627 void
6628 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6629 {
6630   tree_view->priv->mark_rows_col_dirty = TRUE;
6631
6632   install_presize_handler (tree_view);
6633 }
6634
6635 /*
6636  * This function works synchronously (due to the while (validate_rows...)
6637  * loop).
6638  *
6639  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6640  * here. You now need to check that yourself.
6641  */
6642 void
6643 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6644                                 GtkTreeViewColumn *column)
6645 {
6646   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6647   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6648
6649   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6650
6651   do_presize_handler (tree_view);
6652   while (validate_rows (tree_view));
6653
6654   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6655 }
6656
6657 /* Drag-and-drop */
6658
6659 static void
6660 set_source_row (GdkDragContext *context,
6661                 GtkTreeModel   *model,
6662                 GtkTreePath    *source_row)
6663 {
6664   g_object_set_data_full (G_OBJECT (context),
6665                           I_("gtk-tree-view-source-row"),
6666                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6667                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6668 }
6669
6670 static GtkTreePath*
6671 get_source_row (GdkDragContext *context)
6672 {
6673   GtkTreeRowReference *ref =
6674     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6675
6676   if (ref)
6677     return gtk_tree_row_reference_get_path (ref);
6678   else
6679     return NULL;
6680 }
6681
6682 typedef struct
6683 {
6684   GtkTreeRowReference *dest_row;
6685   guint                path_down_mode   : 1;
6686   guint                empty_view_drop  : 1;
6687   guint                drop_append_mode : 1;
6688 }
6689 DestRow;
6690
6691 static void
6692 dest_row_free (gpointer data)
6693 {
6694   DestRow *dr = (DestRow *)data;
6695
6696   gtk_tree_row_reference_free (dr->dest_row);
6697   g_slice_free (DestRow, dr);
6698 }
6699
6700 static void
6701 set_dest_row (GdkDragContext *context,
6702               GtkTreeModel   *model,
6703               GtkTreePath    *dest_row,
6704               gboolean        path_down_mode,
6705               gboolean        empty_view_drop,
6706               gboolean        drop_append_mode)
6707 {
6708   DestRow *dr;
6709
6710   if (!dest_row)
6711     {
6712       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6713                               NULL, NULL);
6714       return;
6715     }
6716
6717   dr = g_slice_new (DestRow);
6718
6719   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6720   dr->path_down_mode = path_down_mode != FALSE;
6721   dr->empty_view_drop = empty_view_drop != FALSE;
6722   dr->drop_append_mode = drop_append_mode != FALSE;
6723
6724   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6725                           dr, (GDestroyNotify) dest_row_free);
6726 }
6727
6728 static GtkTreePath*
6729 get_dest_row (GdkDragContext *context,
6730               gboolean       *path_down_mode)
6731 {
6732   DestRow *dr =
6733     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6734
6735   if (dr)
6736     {
6737       GtkTreePath *path = NULL;
6738
6739       if (path_down_mode)
6740         *path_down_mode = dr->path_down_mode;
6741
6742       if (dr->dest_row)
6743         path = gtk_tree_row_reference_get_path (dr->dest_row);
6744       else if (dr->empty_view_drop)
6745         path = gtk_tree_path_new_from_indices (0, -1);
6746       else
6747         path = NULL;
6748
6749       if (path && dr->drop_append_mode)
6750         gtk_tree_path_next (path);
6751
6752       return path;
6753     }
6754   else
6755     return NULL;
6756 }
6757
6758 /* Get/set whether drag_motion requested the drag data and
6759  * drag_data_received should thus not actually insert the data,
6760  * since the data doesn't result from a drop.
6761  */
6762 static void
6763 set_status_pending (GdkDragContext *context,
6764                     GdkDragAction   suggested_action)
6765 {
6766   g_object_set_data (G_OBJECT (context),
6767                      I_("gtk-tree-view-status-pending"),
6768                      GINT_TO_POINTER (suggested_action));
6769 }
6770
6771 static GdkDragAction
6772 get_status_pending (GdkDragContext *context)
6773 {
6774   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6775                                              "gtk-tree-view-status-pending"));
6776 }
6777
6778 static TreeViewDragInfo*
6779 get_info (GtkTreeView *tree_view)
6780 {
6781   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6782 }
6783
6784 static void
6785 destroy_info (TreeViewDragInfo *di)
6786 {
6787   g_slice_free (TreeViewDragInfo, di);
6788 }
6789
6790 static TreeViewDragInfo*
6791 ensure_info (GtkTreeView *tree_view)
6792 {
6793   TreeViewDragInfo *di;
6794
6795   di = get_info (tree_view);
6796
6797   if (di == NULL)
6798     {
6799       di = g_slice_new0 (TreeViewDragInfo);
6800
6801       g_object_set_data_full (G_OBJECT (tree_view),
6802                               I_("gtk-tree-view-drag-info"),
6803                               di,
6804                               (GDestroyNotify) destroy_info);
6805     }
6806
6807   return di;
6808 }
6809
6810 static void
6811 remove_info (GtkTreeView *tree_view)
6812 {
6813   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6814 }
6815
6816 #if 0
6817 static gint
6818 drag_scan_timeout (gpointer data)
6819 {
6820   GtkTreeView *tree_view;
6821   gint x, y;
6822   GdkModifierType state;
6823   GtkTreePath *path = NULL;
6824   GtkTreeViewColumn *column = NULL;
6825   GdkRectangle visible_rect;
6826
6827   GDK_THREADS_ENTER ();
6828
6829   tree_view = GTK_TREE_VIEW (data);
6830
6831   gdk_window_get_pointer (tree_view->priv->bin_window,
6832                           &x, &y, &state);
6833
6834   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6835
6836   /* See if we are near the edge. */
6837   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6838       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6839       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6840       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6841     {
6842       gtk_tree_view_get_path_at_pos (tree_view,
6843                                      tree_view->priv->bin_window,
6844                                      x, y,
6845                                      &path,
6846                                      &column,
6847                                      NULL,
6848                                      NULL);
6849
6850       if (path != NULL)
6851         {
6852           gtk_tree_view_scroll_to_cell (tree_view,
6853                                         path,
6854                                         column,
6855                                         TRUE,
6856                                         0.5, 0.5);
6857
6858           gtk_tree_path_free (path);
6859         }
6860     }
6861
6862   GDK_THREADS_LEAVE ();
6863
6864   return TRUE;
6865 }
6866 #endif /* 0 */
6867
6868 static void
6869 add_scroll_timeout (GtkTreeView *tree_view)
6870 {
6871   if (tree_view->priv->scroll_timeout == 0)
6872     {
6873       tree_view->priv->scroll_timeout =
6874         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6875     }
6876 }
6877
6878 static void
6879 remove_scroll_timeout (GtkTreeView *tree_view)
6880 {
6881   if (tree_view->priv->scroll_timeout != 0)
6882     {
6883       g_source_remove (tree_view->priv->scroll_timeout);
6884       tree_view->priv->scroll_timeout = 0;
6885     }
6886 }
6887
6888 static gboolean
6889 check_model_dnd (GtkTreeModel *model,
6890                  GType         required_iface,
6891                  const gchar  *signal)
6892 {
6893   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6894     {
6895       g_warning ("You must override the default '%s' handler "
6896                  "on GtkTreeView when using models that don't support "
6897                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6898                  "is to connect to '%s' and call "
6899                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6900                  "the default handler from running. Look at the source code "
6901                  "for the default handler in gtktreeview.c to get an idea what "
6902                  "your handler should do. (gtktreeview.c is in the GTK source "
6903                  "code.) If you're using GTK from a language other than C, "
6904                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6905                  signal, g_type_name (required_iface), signal);
6906       return FALSE;
6907     }
6908   else
6909     return TRUE;
6910 }
6911
6912 static void
6913 remove_open_timeout (GtkTreeView *tree_view)
6914 {
6915   if (tree_view->priv->open_dest_timeout != 0)
6916     {
6917       g_source_remove (tree_view->priv->open_dest_timeout);
6918       tree_view->priv->open_dest_timeout = 0;
6919     }
6920 }
6921
6922
6923 static gint
6924 open_row_timeout (gpointer data)
6925 {
6926   GtkTreeView *tree_view = data;
6927   GtkTreePath *dest_path = NULL;
6928   GtkTreeViewDropPosition pos;
6929   gboolean result = FALSE;
6930
6931   gtk_tree_view_get_drag_dest_row (tree_view,
6932                                    &dest_path,
6933                                    &pos);
6934
6935   if (dest_path &&
6936       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6937        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6938     {
6939       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6940       tree_view->priv->open_dest_timeout = 0;
6941
6942       gtk_tree_path_free (dest_path);
6943     }
6944   else
6945     {
6946       if (dest_path)
6947         gtk_tree_path_free (dest_path);
6948
6949       result = TRUE;
6950     }
6951
6952   return result;
6953 }
6954
6955 static gboolean
6956 scroll_row_timeout (gpointer data)
6957 {
6958   GtkTreeView *tree_view = data;
6959
6960   gtk_tree_view_vertical_autoscroll (tree_view);
6961
6962   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6963     gtk_tree_view_update_rubber_band (tree_view);
6964
6965   return TRUE;
6966 }
6967
6968 /* Returns TRUE if event should not be propagated to parent widgets */
6969 static gboolean
6970 set_destination_row (GtkTreeView    *tree_view,
6971                      GdkDragContext *context,
6972                      /* coordinates relative to the widget */
6973                      gint            x,
6974                      gint            y,
6975                      GdkDragAction  *suggested_action,
6976                      GdkAtom        *target)
6977 {
6978   GtkTreePath *path = NULL;
6979   GtkTreeViewDropPosition pos;
6980   GtkTreeViewDropPosition old_pos;
6981   TreeViewDragInfo *di;
6982   GtkWidget *widget;
6983   GtkTreePath *old_dest_path = NULL;
6984   gboolean can_drop = FALSE;
6985
6986   *suggested_action = 0;
6987   *target = GDK_NONE;
6988
6989   widget = GTK_WIDGET (tree_view);
6990
6991   di = get_info (tree_view);
6992
6993   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6994     {
6995       /* someone unset us as a drag dest, note that if
6996        * we return FALSE drag_leave isn't called
6997        */
6998
6999       gtk_tree_view_set_drag_dest_row (tree_view,
7000                                        NULL,
7001                                        GTK_TREE_VIEW_DROP_BEFORE);
7002
7003       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7004       remove_open_timeout (GTK_TREE_VIEW (widget));
7005
7006       return FALSE; /* no longer a drop site */
7007     }
7008
7009   *target = gtk_drag_dest_find_target (widget, context,
7010                                        gtk_drag_dest_get_target_list (widget));
7011   if (*target == GDK_NONE)
7012     {
7013       return FALSE;
7014     }
7015
7016   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7017                                           x, y,
7018                                           &path,
7019                                           &pos))
7020     {
7021       gint n_children;
7022       GtkTreeModel *model;
7023
7024       remove_open_timeout (tree_view);
7025
7026       /* the row got dropped on empty space, let's setup a special case
7027        */
7028
7029       if (path)
7030         gtk_tree_path_free (path);
7031
7032       model = gtk_tree_view_get_model (tree_view);
7033
7034       n_children = gtk_tree_model_iter_n_children (model, NULL);
7035       if (n_children)
7036         {
7037           pos = GTK_TREE_VIEW_DROP_AFTER;
7038           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7039         }
7040       else
7041         {
7042           pos = GTK_TREE_VIEW_DROP_BEFORE;
7043           path = gtk_tree_path_new_from_indices (0, -1);
7044         }
7045
7046       can_drop = TRUE;
7047
7048       goto out;
7049     }
7050
7051   g_assert (path);
7052
7053   /* If we left the current row's "open" zone, unset the timeout for
7054    * opening the row
7055    */
7056   gtk_tree_view_get_drag_dest_row (tree_view,
7057                                    &old_dest_path,
7058                                    &old_pos);
7059
7060   if (old_dest_path &&
7061       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7062        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7063          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7064     remove_open_timeout (tree_view);
7065
7066   if (old_dest_path)
7067     gtk_tree_path_free (old_dest_path);
7068
7069   if (TRUE /* FIXME if the location droppable predicate */)
7070     {
7071       can_drop = TRUE;
7072     }
7073
7074 out:
7075   if (can_drop)
7076     {
7077       GtkWidget *source_widget;
7078
7079       *suggested_action = context->suggested_action;
7080       source_widget = gtk_drag_get_source_widget (context);
7081
7082       if (source_widget == widget)
7083         {
7084           /* Default to MOVE, unless the user has
7085            * pressed ctrl or shift to affect available actions
7086            */
7087           if ((context->actions & GDK_ACTION_MOVE) != 0)
7088             *suggested_action = GDK_ACTION_MOVE;
7089         }
7090
7091       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7092                                        path, pos);
7093     }
7094   else
7095     {
7096       /* can't drop here */
7097       remove_open_timeout (tree_view);
7098
7099       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7100                                        NULL,
7101                                        GTK_TREE_VIEW_DROP_BEFORE);
7102     }
7103
7104   if (path)
7105     gtk_tree_path_free (path);
7106
7107   return TRUE;
7108 }
7109
7110 static GtkTreePath*
7111 get_logical_dest_row (GtkTreeView *tree_view,
7112                       gboolean    *path_down_mode,
7113                       gboolean    *drop_append_mode)
7114 {
7115   /* adjust path to point to the row the drop goes in front of */
7116   GtkTreePath *path = NULL;
7117   GtkTreeViewDropPosition pos;
7118
7119   g_return_val_if_fail (path_down_mode != NULL, NULL);
7120   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7121
7122   *path_down_mode = FALSE;
7123   *drop_append_mode = 0;
7124
7125   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7126
7127   if (path == NULL)
7128     return NULL;
7129
7130   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7131     ; /* do nothing */
7132   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7133            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7134     *path_down_mode = TRUE;
7135   else
7136     {
7137       GtkTreeIter iter;
7138       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7139
7140       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7141
7142       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7143           !gtk_tree_model_iter_next (model, &iter))
7144         *drop_append_mode = 1;
7145       else
7146         {
7147           *drop_append_mode = 0;
7148           gtk_tree_path_next (path);
7149         }
7150     }
7151
7152   return path;
7153 }
7154
7155 static gboolean
7156 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7157                                         GdkEventMotion   *event)
7158 {
7159   GtkWidget *widget = GTK_WIDGET (tree_view);
7160   GdkDragContext *context;
7161   TreeViewDragInfo *di;
7162   GtkTreePath *path = NULL;
7163   gint button;
7164   gint cell_x, cell_y;
7165   GtkTreeModel *model;
7166   gboolean retval = FALSE;
7167
7168   di = get_info (tree_view);
7169
7170   if (di == NULL || !di->source_set)
7171     goto out;
7172
7173   if (tree_view->priv->pressed_button < 0)
7174     goto out;
7175
7176   if (!gtk_drag_check_threshold (widget,
7177                                  tree_view->priv->press_start_x,
7178                                  tree_view->priv->press_start_y,
7179                                  event->x, event->y))
7180     goto out;
7181
7182   model = gtk_tree_view_get_model (tree_view);
7183
7184   if (model == NULL)
7185     goto out;
7186
7187   button = tree_view->priv->pressed_button;
7188   tree_view->priv->pressed_button = -1;
7189
7190   gtk_tree_view_get_path_at_pos (tree_view,
7191                                  tree_view->priv->press_start_x,
7192                                  tree_view->priv->press_start_y,
7193                                  &path,
7194                                  NULL,
7195                                  &cell_x,
7196                                  &cell_y);
7197
7198   if (path == NULL)
7199     goto out;
7200
7201   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7202       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7203                                            path))
7204     goto out;
7205
7206   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7207     goto out;
7208
7209   /* Now we can begin the drag */
7210
7211   retval = TRUE;
7212
7213   context = gtk_drag_begin (widget,
7214                             gtk_drag_source_get_target_list (widget),
7215                             di->source_actions,
7216                             button,
7217                             (GdkEvent*)event);
7218
7219   set_source_row (context, model, path);
7220
7221  out:
7222   if (path)
7223     gtk_tree_path_free (path);
7224
7225   return retval;
7226 }
7227
7228
7229 static void
7230 gtk_tree_view_drag_begin (GtkWidget      *widget,
7231                           GdkDragContext *context)
7232 {
7233   GtkTreeView *tree_view;
7234   GtkTreePath *path = NULL;
7235   gint cell_x, cell_y;
7236   cairo_surface_t *row_pix;
7237   TreeViewDragInfo *di;
7238
7239   tree_view = GTK_TREE_VIEW (widget);
7240
7241   /* if the user uses a custom DND source impl, we don't set the icon here */
7242   di = get_info (tree_view);
7243
7244   if (di == NULL || !di->source_set)
7245     return;
7246
7247   gtk_tree_view_get_path_at_pos (tree_view,
7248                                  tree_view->priv->press_start_x,
7249                                  tree_view->priv->press_start_y,
7250                                  &path,
7251                                  NULL,
7252                                  &cell_x,
7253                                  &cell_y);
7254
7255   g_return_if_fail (path != NULL);
7256
7257   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7258                                                 path);
7259   cairo_surface_set_device_offset (row_pix,
7260                                    /* the + 1 is for the black border in the icon */
7261                                    - (tree_view->priv->press_start_x + 1),
7262                                    - (cell_y + 1));
7263
7264   gtk_drag_set_icon_surface (context, row_pix);
7265
7266   cairo_surface_destroy (row_pix);
7267   gtk_tree_path_free (path);
7268 }
7269
7270 static void
7271 gtk_tree_view_drag_end (GtkWidget      *widget,
7272                         GdkDragContext *context)
7273 {
7274   /* do nothing */
7275 }
7276
7277 /* Default signal implementations for the drag signals */
7278 static void
7279 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7280                              GdkDragContext   *context,
7281                              GtkSelectionData *selection_data,
7282                              guint             info,
7283                              guint             time)
7284 {
7285   GtkTreeView *tree_view;
7286   GtkTreeModel *model;
7287   TreeViewDragInfo *di;
7288   GtkTreePath *source_row;
7289
7290   tree_view = GTK_TREE_VIEW (widget);
7291
7292   model = gtk_tree_view_get_model (tree_view);
7293
7294   if (model == NULL)
7295     return;
7296
7297   di = get_info (GTK_TREE_VIEW (widget));
7298
7299   if (di == NULL)
7300     return;
7301
7302   source_row = get_source_row (context);
7303
7304   if (source_row == NULL)
7305     return;
7306
7307   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7308    * any model; for DragSource models there are some other targets
7309    * we also support.
7310    */
7311
7312   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7313       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7314                                           source_row,
7315                                           selection_data))
7316     goto done;
7317
7318   /* If drag_data_get does nothing, try providing row data. */
7319   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7320     {
7321       gtk_tree_set_row_drag_data (selection_data,
7322                                   model,
7323                                   source_row);
7324     }
7325
7326  done:
7327   gtk_tree_path_free (source_row);
7328 }
7329
7330
7331 static void
7332 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7333                                 GdkDragContext *context)
7334 {
7335   TreeViewDragInfo *di;
7336   GtkTreeModel *model;
7337   GtkTreeView *tree_view;
7338   GtkTreePath *source_row;
7339
7340   tree_view = GTK_TREE_VIEW (widget);
7341   model = gtk_tree_view_get_model (tree_view);
7342
7343   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7344     return;
7345
7346   di = get_info (tree_view);
7347
7348   if (di == NULL)
7349     return;
7350
7351   source_row = get_source_row (context);
7352
7353   if (source_row == NULL)
7354     return;
7355
7356   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7357                                          source_row);
7358
7359   gtk_tree_path_free (source_row);
7360
7361   set_source_row (context, NULL, NULL);
7362 }
7363
7364 static void
7365 gtk_tree_view_drag_leave (GtkWidget      *widget,
7366                           GdkDragContext *context,
7367                           guint             time)
7368 {
7369   /* unset any highlight row */
7370   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7371                                    NULL,
7372                                    GTK_TREE_VIEW_DROP_BEFORE);
7373
7374   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7375   remove_open_timeout (GTK_TREE_VIEW (widget));
7376 }
7377
7378
7379 static gboolean
7380 gtk_tree_view_drag_motion (GtkWidget        *widget,
7381                            GdkDragContext   *context,
7382                            /* coordinates relative to the widget */
7383                            gint              x,
7384                            gint              y,
7385                            guint             time)
7386 {
7387   gboolean empty;
7388   GtkTreePath *path = NULL;
7389   GtkTreeViewDropPosition pos;
7390   GtkTreeView *tree_view;
7391   GdkDragAction suggested_action = 0;
7392   GdkAtom target;
7393
7394   tree_view = GTK_TREE_VIEW (widget);
7395
7396   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7397     return FALSE;
7398
7399   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7400
7401   /* we only know this *after* set_desination_row */
7402   empty = tree_view->priv->empty_view_drop;
7403
7404   if (path == NULL && !empty)
7405     {
7406       /* Can't drop here. */
7407       gdk_drag_status (context, 0, time);
7408     }
7409   else
7410     {
7411       if (tree_view->priv->open_dest_timeout == 0 &&
7412           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7413            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7414         {
7415           tree_view->priv->open_dest_timeout =
7416             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7417         }
7418       else
7419         {
7420           add_scroll_timeout (tree_view);
7421         }
7422
7423       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7424         {
7425           /* Request data so we can use the source row when
7426            * determining whether to accept the drop
7427            */
7428           set_status_pending (context, suggested_action);
7429           gtk_drag_get_data (widget, context, target, time);
7430         }
7431       else
7432         {
7433           set_status_pending (context, 0);
7434           gdk_drag_status (context, suggested_action, time);
7435         }
7436     }
7437
7438   if (path)
7439     gtk_tree_path_free (path);
7440
7441   return TRUE;
7442 }
7443
7444
7445 static gboolean
7446 gtk_tree_view_drag_drop (GtkWidget        *widget,
7447                          GdkDragContext   *context,
7448                          /* coordinates relative to the widget */
7449                          gint              x,
7450                          gint              y,
7451                          guint             time)
7452 {
7453   GtkTreeView *tree_view;
7454   GtkTreePath *path;
7455   GdkDragAction suggested_action = 0;
7456   GdkAtom target = GDK_NONE;
7457   TreeViewDragInfo *di;
7458   GtkTreeModel *model;
7459   gboolean path_down_mode;
7460   gboolean drop_append_mode;
7461
7462   tree_view = GTK_TREE_VIEW (widget);
7463
7464   model = gtk_tree_view_get_model (tree_view);
7465
7466   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7467   remove_open_timeout (GTK_TREE_VIEW (widget));
7468
7469   di = get_info (tree_view);
7470
7471   if (di == NULL)
7472     return FALSE;
7473
7474   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7475     return FALSE;
7476
7477   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7478     return FALSE;
7479
7480   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7481
7482   if (target != GDK_NONE && path != NULL)
7483     {
7484       /* in case a motion had requested drag data, change things so we
7485        * treat drag data receives as a drop.
7486        */
7487       set_status_pending (context, 0);
7488       set_dest_row (context, model, path,
7489                     path_down_mode, tree_view->priv->empty_view_drop,
7490                     drop_append_mode);
7491     }
7492
7493   if (path)
7494     gtk_tree_path_free (path);
7495
7496   /* Unset this thing */
7497   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7498                                    NULL,
7499                                    GTK_TREE_VIEW_DROP_BEFORE);
7500
7501   if (target != GDK_NONE)
7502     {
7503       gtk_drag_get_data (widget, context, target, time);
7504       return TRUE;
7505     }
7506   else
7507     return FALSE;
7508 }
7509
7510 static void
7511 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7512                                   GdkDragContext   *context,
7513                                   /* coordinates relative to the widget */
7514                                   gint              x,
7515                                   gint              y,
7516                                   GtkSelectionData *selection_data,
7517                                   guint             info,
7518                                   guint             time)
7519 {
7520   GtkTreePath *path;
7521   TreeViewDragInfo *di;
7522   gboolean accepted = FALSE;
7523   GtkTreeModel *model;
7524   GtkTreeView *tree_view;
7525   GtkTreePath *dest_row;
7526   GdkDragAction suggested_action;
7527   gboolean path_down_mode;
7528   gboolean drop_append_mode;
7529
7530   tree_view = GTK_TREE_VIEW (widget);
7531
7532   model = gtk_tree_view_get_model (tree_view);
7533
7534   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7535     return;
7536
7537   di = get_info (tree_view);
7538
7539   if (di == NULL)
7540     return;
7541
7542   suggested_action = get_status_pending (context);
7543
7544   if (suggested_action)
7545     {
7546       /* We are getting this data due to a request in drag_motion,
7547        * rather than due to a request in drag_drop, so we are just
7548        * supposed to call drag_status, not actually paste in the
7549        * data.
7550        */
7551       path = get_logical_dest_row (tree_view, &path_down_mode,
7552                                    &drop_append_mode);
7553
7554       if (path == NULL)
7555         suggested_action = 0;
7556       else if (path_down_mode)
7557         gtk_tree_path_down (path);
7558
7559       if (suggested_action)
7560         {
7561           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7562                                                      path,
7563                                                      selection_data))
7564             {
7565               if (path_down_mode)
7566                 {
7567                   path_down_mode = FALSE;
7568                   gtk_tree_path_up (path);
7569
7570                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7571                                                              path,
7572                                                              selection_data))
7573                     suggested_action = 0;
7574                 }
7575               else
7576                 suggested_action = 0;
7577             }
7578         }
7579
7580       gdk_drag_status (context, suggested_action, time);
7581
7582       if (path)
7583         gtk_tree_path_free (path);
7584
7585       /* If you can't drop, remove user drop indicator until the next motion */
7586       if (suggested_action == 0)
7587         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7588                                          NULL,
7589                                          GTK_TREE_VIEW_DROP_BEFORE);
7590
7591       return;
7592     }
7593
7594   dest_row = get_dest_row (context, &path_down_mode);
7595
7596   if (dest_row == NULL)
7597     return;
7598
7599   if (selection_data->length >= 0)
7600     {
7601       if (path_down_mode)
7602         {
7603           gtk_tree_path_down (dest_row);
7604           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7605                                                      dest_row, selection_data))
7606             gtk_tree_path_up (dest_row);
7607         }
7608     }
7609
7610   if (selection_data->length >= 0)
7611     {
7612       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7613                                                  dest_row,
7614                                                  selection_data))
7615         accepted = TRUE;
7616     }
7617
7618   gtk_drag_finish (context,
7619                    accepted,
7620                    (context->action == GDK_ACTION_MOVE),
7621                    time);
7622
7623   if (gtk_tree_path_get_depth (dest_row) == 1
7624       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7625     {
7626       /* special special case drag to "0", scroll to first item */
7627       if (!tree_view->priv->scroll_to_path)
7628         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7629     }
7630
7631   gtk_tree_path_free (dest_row);
7632
7633   /* drop dest_row */
7634   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7635 }
7636
7637
7638
7639 /* GtkContainer Methods
7640  */
7641
7642
7643 static void
7644 gtk_tree_view_remove (GtkContainer *container,
7645                       GtkWidget    *widget)
7646 {
7647   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7648   GtkTreeViewChild *child = NULL;
7649   GList *tmp_list;
7650
7651   tmp_list = tree_view->priv->children;
7652   while (tmp_list)
7653     {
7654       child = tmp_list->data;
7655       if (child->widget == widget)
7656         {
7657           gtk_widget_unparent (widget);
7658
7659           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7660           g_list_free_1 (tmp_list);
7661           g_slice_free (GtkTreeViewChild, child);
7662           return;
7663         }
7664
7665       tmp_list = tmp_list->next;
7666     }
7667
7668   tmp_list = tree_view->priv->columns;
7669
7670   while (tmp_list)
7671     {
7672       GtkTreeViewColumn *column;
7673       column = tmp_list->data;
7674       if (column->button == widget)
7675         {
7676           gtk_widget_unparent (widget);
7677           return;
7678         }
7679       tmp_list = tmp_list->next;
7680     }
7681 }
7682
7683 static void
7684 gtk_tree_view_forall (GtkContainer *container,
7685                       gboolean      include_internals,
7686                       GtkCallback   callback,
7687                       gpointer      callback_data)
7688 {
7689   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7690   GtkTreeViewChild *child = NULL;
7691   GtkTreeViewColumn *column;
7692   GList *tmp_list;
7693
7694   tmp_list = tree_view->priv->children;
7695   while (tmp_list)
7696     {
7697       child = tmp_list->data;
7698       tmp_list = tmp_list->next;
7699
7700       (* callback) (child->widget, callback_data);
7701     }
7702   if (include_internals == FALSE)
7703     return;
7704
7705   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7706     {
7707       column = tmp_list->data;
7708
7709       if (column->button)
7710         (* callback) (column->button, callback_data);
7711     }
7712 }
7713
7714 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7715  * cells. If so we draw one big row-spanning focus rectangle.
7716  */
7717 static gboolean
7718 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7719 {
7720   GList *list;
7721
7722   for (list = tree_view->priv->columns; list; list = list->next)
7723     {
7724       if (!((GtkTreeViewColumn *)list->data)->visible)
7725         continue;
7726       if (_gtk_tree_view_column_count_special_cells (list->data))
7727         return TRUE;
7728     }
7729
7730   return FALSE;
7731 }
7732
7733 static void
7734 column_sizing_notify (GObject    *object,
7735                       GParamSpec *pspec,
7736                       gpointer    data)
7737 {
7738   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7739
7740   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7741     /* disable fixed height mode */
7742     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7743 }
7744
7745 /**
7746  * gtk_tree_view_set_fixed_height_mode:
7747  * @tree_view: a #GtkTreeView 
7748  * @enable: %TRUE to enable fixed height mode
7749  * 
7750  * Enables or disables the fixed height mode of @tree_view. 
7751  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7752  * rows have the same height. 
7753  * Only enable this option if all rows are the same height and all
7754  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7755  *
7756  * Since: 2.6 
7757  **/
7758 void
7759 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7760                                      gboolean     enable)
7761 {
7762   GList *l;
7763   
7764   enable = enable != FALSE;
7765
7766   if (enable == tree_view->priv->fixed_height_mode)
7767     return;
7768
7769   if (!enable)
7770     {
7771       tree_view->priv->fixed_height_mode = 0;
7772       tree_view->priv->fixed_height = -1;
7773
7774       /* force a revalidation */
7775       install_presize_handler (tree_view);
7776     }
7777   else 
7778     {
7779       /* make sure all columns are of type FIXED */
7780       for (l = tree_view->priv->columns; l; l = l->next)
7781         {
7782           GtkTreeViewColumn *c = l->data;
7783           
7784           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7785         }
7786       
7787       /* yes, we really have to do this is in a separate loop */
7788       for (l = tree_view->priv->columns; l; l = l->next)
7789         g_signal_connect (l->data, "notify::sizing",
7790                           G_CALLBACK (column_sizing_notify), tree_view);
7791       
7792       tree_view->priv->fixed_height_mode = 1;
7793       tree_view->priv->fixed_height = -1;
7794       
7795       if (tree_view->priv->tree)
7796         initialize_fixed_height_mode (tree_view);
7797     }
7798
7799   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7800 }
7801
7802 /**
7803  * gtk_tree_view_get_fixed_height_mode:
7804  * @tree_view: a #GtkTreeView
7805  * 
7806  * Returns whether fixed height mode is turned on for @tree_view.
7807  * 
7808  * Return value: %TRUE if @tree_view is in fixed height mode
7809  * 
7810  * Since: 2.6
7811  **/
7812 gboolean
7813 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7814 {
7815   return tree_view->priv->fixed_height_mode;
7816 }
7817
7818 /* Returns TRUE if the focus is within the headers, after the focus operation is
7819  * done
7820  */
7821 static gboolean
7822 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7823                             GtkDirectionType  dir,
7824                             gboolean          clamp_column_visible)
7825 {
7826   GtkWidget *focus_child;
7827
7828   GList *last_column, *first_column;
7829   GList *tmp_list;
7830   gboolean rtl;
7831
7832   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7833     return FALSE;
7834
7835   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
7836
7837   first_column = tree_view->priv->columns;
7838   while (first_column)
7839     {
7840       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7841           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7842           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7843            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7844         break;
7845       first_column = first_column->next;
7846     }
7847
7848   /* No headers are visible, or are focusable.  We can't focus in or out.
7849    */
7850   if (first_column == NULL)
7851     return FALSE;
7852
7853   last_column = g_list_last (tree_view->priv->columns);
7854   while (last_column)
7855     {
7856       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7857           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7858           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7859            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7860         break;
7861       last_column = last_column->prev;
7862     }
7863
7864
7865   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7866
7867   switch (dir)
7868     {
7869     case GTK_DIR_TAB_BACKWARD:
7870     case GTK_DIR_TAB_FORWARD:
7871     case GTK_DIR_UP:
7872     case GTK_DIR_DOWN:
7873       if (focus_child == NULL)
7874         {
7875           if (tree_view->priv->focus_column != NULL &&
7876               gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
7877             focus_child = tree_view->priv->focus_column->button;
7878           else
7879             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7880           gtk_widget_grab_focus (focus_child);
7881           break;
7882         }
7883       return FALSE;
7884
7885     case GTK_DIR_LEFT:
7886     case GTK_DIR_RIGHT:
7887       if (focus_child == NULL)
7888         {
7889           if (tree_view->priv->focus_column != NULL)
7890             focus_child = tree_view->priv->focus_column->button;
7891           else if (dir == GTK_DIR_LEFT)
7892             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7893           else
7894             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7895           gtk_widget_grab_focus (focus_child);
7896           break;
7897         }
7898
7899       if (gtk_widget_child_focus (focus_child, dir))
7900         {
7901           /* The focus moves inside the button. */
7902           /* This is probably a great example of bad UI */
7903           break;
7904         }
7905
7906       /* We need to move the focus among the row of buttons. */
7907       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7908         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7909           break;
7910
7911       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7912           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7913         {
7914           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7915           break;
7916         }
7917
7918       while (tmp_list)
7919         {
7920           GtkTreeViewColumn *column;
7921
7922           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7923             tmp_list = tmp_list->next;
7924           else
7925             tmp_list = tmp_list->prev;
7926
7927           if (tmp_list == NULL)
7928             {
7929               g_warning ("Internal button not found");
7930               break;
7931             }
7932           column = tmp_list->data;
7933           if (column->button &&
7934               column->visible &&
7935               gtk_widget_get_can_focus (column->button))
7936             {
7937               focus_child = column->button;
7938               gtk_widget_grab_focus (column->button);
7939               break;
7940             }
7941         }
7942       break;
7943     default:
7944       g_assert_not_reached ();
7945       break;
7946     }
7947
7948   /* if focus child is non-null, we assume it's been set to the current focus child
7949    */
7950   if (focus_child)
7951     {
7952       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7953         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7954           {
7955             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7956             break;
7957           }
7958
7959       if (clamp_column_visible)
7960         {
7961           gtk_tree_view_clamp_column_visible (tree_view,
7962                                               tree_view->priv->focus_column,
7963                                               FALSE);
7964         }
7965     }
7966
7967   return (focus_child != NULL);
7968 }
7969
7970 /* This function returns in 'path' the first focusable path, if the given path
7971  * is already focusable, it's the returned one.
7972  */
7973 static gboolean
7974 search_first_focusable_path (GtkTreeView  *tree_view,
7975                              GtkTreePath **path,
7976                              gboolean      search_forward,
7977                              GtkRBTree   **new_tree,
7978                              GtkRBNode   **new_node)
7979 {
7980   GtkRBTree *tree = NULL;
7981   GtkRBNode *node = NULL;
7982
7983   if (!path || !*path)
7984     return FALSE;
7985
7986   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7987
7988   if (!tree || !node)
7989     return FALSE;
7990
7991   while (node && row_is_separator (tree_view, NULL, *path))
7992     {
7993       if (search_forward)
7994         _gtk_rbtree_next_full (tree, node, &tree, &node);
7995       else
7996         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7997
7998       if (*path)
7999         gtk_tree_path_free (*path);
8000
8001       if (node)
8002         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8003       else
8004         *path = NULL;
8005     }
8006
8007   if (new_tree)
8008     *new_tree = tree;
8009
8010   if (new_node)
8011     *new_node = node;
8012
8013   return (*path != NULL);
8014 }
8015
8016 static gint
8017 gtk_tree_view_focus (GtkWidget        *widget,
8018                      GtkDirectionType  direction)
8019 {
8020   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8021   GtkContainer *container = GTK_CONTAINER (widget);
8022   GtkWidget *focus_child;
8023
8024   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8025     return FALSE;
8026
8027   focus_child = gtk_container_get_focus_child (container);
8028
8029   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8030   /* Case 1.  Headers currently have focus. */
8031   if (focus_child)
8032     {
8033       switch (direction)
8034         {
8035         case GTK_DIR_LEFT:
8036         case GTK_DIR_RIGHT:
8037           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8038           return TRUE;
8039         case GTK_DIR_TAB_BACKWARD:
8040         case GTK_DIR_UP:
8041           return FALSE;
8042         case GTK_DIR_TAB_FORWARD:
8043         case GTK_DIR_DOWN:
8044           gtk_widget_grab_focus (widget);
8045           return TRUE;
8046         default:
8047           g_assert_not_reached ();
8048           return FALSE;
8049         }
8050     }
8051
8052   /* Case 2. We don't have focus at all. */
8053   if (!gtk_widget_has_focus (widget))
8054     {
8055       gtk_widget_grab_focus (widget);
8056       return TRUE;
8057     }
8058
8059   /* Case 3. We have focus already. */
8060   if (direction == GTK_DIR_TAB_BACKWARD)
8061     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8062   else if (direction == GTK_DIR_TAB_FORWARD)
8063     return FALSE;
8064
8065   /* Other directions caught by the keybindings */
8066   gtk_widget_grab_focus (widget);
8067   return TRUE;
8068 }
8069
8070 static void
8071 gtk_tree_view_grab_focus (GtkWidget *widget)
8072 {
8073   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8074
8075   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8076 }
8077
8078 static void
8079 gtk_tree_view_style_set (GtkWidget *widget,
8080                          GtkStyle *previous_style)
8081 {
8082   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8083   GtkStyle *style;
8084   GList *list;
8085   GtkTreeViewColumn *column;
8086
8087   if (gtk_widget_get_realized (widget))
8088     {
8089       style = gtk_widget_get_style (widget);
8090       gdk_window_set_background (tree_view->priv->bin_window,
8091                                  &style->base[gtk_widget_get_state (widget)]);
8092       gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8093
8094       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8095       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8096     }
8097
8098   gtk_widget_style_get (widget,
8099                         "expander-size", &tree_view->priv->expander_size,
8100                         NULL);
8101   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8102
8103   for (list = tree_view->priv->columns; list; list = list->next)
8104     {
8105       column = list->data;
8106       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8107     }
8108
8109   tree_view->priv->fixed_height = -1;
8110   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8111
8112   gtk_widget_queue_resize (widget);
8113 }
8114
8115
8116 static void
8117 gtk_tree_view_set_focus_child (GtkContainer *container,
8118                                GtkWidget    *child)
8119 {
8120   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8121   GList *list;
8122
8123   for (list = tree_view->priv->columns; list; list = list->next)
8124     {
8125       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8126         {
8127           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8128           break;
8129         }
8130     }
8131
8132   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8133 }
8134
8135 static gboolean
8136 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8137                                 GtkMovementStep    step,
8138                                 gint               count)
8139 {
8140   GdkModifierType state;
8141
8142   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8143   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8144                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8145                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8146                         step == GTK_MOVEMENT_PAGES ||
8147                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8148
8149   if (tree_view->priv->tree == NULL)
8150     return FALSE;
8151   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8152     return FALSE;
8153
8154   gtk_tree_view_stop_editing (tree_view, FALSE);
8155   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8156   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8157
8158   if (gtk_get_current_event_state (&state))
8159     {
8160       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8161         tree_view->priv->ctrl_pressed = TRUE;
8162       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8163         tree_view->priv->shift_pressed = TRUE;
8164     }
8165   /* else we assume not pressed */
8166
8167   switch (step)
8168     {
8169       /* currently we make no distinction.  When we go bi-di, we need to */
8170     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8171     case GTK_MOVEMENT_VISUAL_POSITIONS:
8172       gtk_tree_view_move_cursor_left_right (tree_view, count);
8173       break;
8174     case GTK_MOVEMENT_DISPLAY_LINES:
8175       gtk_tree_view_move_cursor_up_down (tree_view, count);
8176       break;
8177     case GTK_MOVEMENT_PAGES:
8178       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8179       break;
8180     case GTK_MOVEMENT_BUFFER_ENDS:
8181       gtk_tree_view_move_cursor_start_end (tree_view, count);
8182       break;
8183     default:
8184       g_assert_not_reached ();
8185     }
8186
8187   tree_view->priv->ctrl_pressed = FALSE;
8188   tree_view->priv->shift_pressed = FALSE;
8189
8190   return TRUE;
8191 }
8192
8193 static void
8194 gtk_tree_view_put (GtkTreeView *tree_view,
8195                    GtkWidget   *child_widget,
8196                    /* in bin_window coordinates */
8197                    gint         x,
8198                    gint         y,
8199                    gint         width,
8200                    gint         height)
8201 {
8202   GtkTreeViewChild *child;
8203   
8204   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8205   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8206
8207   child = g_slice_new (GtkTreeViewChild);
8208
8209   child->widget = child_widget;
8210   child->x = x;
8211   child->y = y;
8212   child->width = width;
8213   child->height = height;
8214
8215   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8216
8217   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8218     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8219   
8220   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8221 }
8222
8223 void
8224 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8225                                   GtkWidget   *widget,
8226                                   /* in tree coordinates */
8227                                   gint         x,
8228                                   gint         y,
8229                                   gint         width,
8230                                   gint         height)
8231 {
8232   GtkTreeViewChild *child = NULL;
8233   GList *list;
8234   GdkRectangle allocation;
8235
8236   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8237   g_return_if_fail (GTK_IS_WIDGET (widget));
8238
8239   for (list = tree_view->priv->children; list; list = list->next)
8240     {
8241       if (((GtkTreeViewChild *)list->data)->widget == widget)
8242         {
8243           child = list->data;
8244           break;
8245         }
8246     }
8247   if (child == NULL)
8248     return;
8249
8250   allocation.x = child->x = x;
8251   allocation.y = child->y = y;
8252   allocation.width = child->width = width;
8253   allocation.height = child->height = height;
8254
8255   if (gtk_widget_get_realized (widget))
8256     gtk_widget_size_allocate (widget, &allocation);
8257 }
8258
8259
8260 /* TreeModel Callbacks
8261  */
8262
8263 static void
8264 gtk_tree_view_row_changed (GtkTreeModel *model,
8265                            GtkTreePath  *path,
8266                            GtkTreeIter  *iter,
8267                            gpointer      data)
8268 {
8269   GtkTreeView *tree_view = (GtkTreeView *)data;
8270   GtkRBTree *tree;
8271   GtkRBNode *node;
8272   gboolean free_path = FALSE;
8273   GList *list;
8274   GtkTreePath *cursor_path;
8275
8276   g_return_if_fail (path != NULL || iter != NULL);
8277
8278   if (tree_view->priv->cursor != NULL)
8279     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8280   else
8281     cursor_path = NULL;
8282
8283   if (tree_view->priv->edited_column &&
8284       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8285     gtk_tree_view_stop_editing (tree_view, TRUE);
8286
8287   if (cursor_path != NULL)
8288     gtk_tree_path_free (cursor_path);
8289
8290   if (path == NULL)
8291     {
8292       path = gtk_tree_model_get_path (model, iter);
8293       free_path = TRUE;
8294     }
8295   else if (iter == NULL)
8296     gtk_tree_model_get_iter (model, iter, path);
8297
8298   if (_gtk_tree_view_find_node (tree_view,
8299                                 path,
8300                                 &tree,
8301                                 &node))
8302     /* We aren't actually showing the node */
8303     goto done;
8304
8305   if (tree == NULL)
8306     goto done;
8307
8308   if (tree_view->priv->fixed_height_mode
8309       && tree_view->priv->fixed_height >= 0)
8310     {
8311       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8312       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8313         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8314     }
8315   else
8316     {
8317       _gtk_rbtree_node_mark_invalid (tree, node);
8318       for (list = tree_view->priv->columns; list; list = list->next)
8319         {
8320           GtkTreeViewColumn *column;
8321
8322           column = list->data;
8323           if (! column->visible)
8324             continue;
8325
8326           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8327             {
8328               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8329             }
8330         }
8331     }
8332
8333  done:
8334   if (!tree_view->priv->fixed_height_mode &&
8335       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8336     install_presize_handler (tree_view);
8337   if (free_path)
8338     gtk_tree_path_free (path);
8339 }
8340
8341 static void
8342 gtk_tree_view_row_inserted (GtkTreeModel *model,
8343                             GtkTreePath  *path,
8344                             GtkTreeIter  *iter,
8345                             gpointer      data)
8346 {
8347   GtkTreeView *tree_view = (GtkTreeView *) data;
8348   gint *indices;
8349   GtkRBTree *tmptree, *tree;
8350   GtkRBNode *tmpnode = NULL;
8351   gint depth;
8352   gint i = 0;
8353   gint height;
8354   gboolean free_path = FALSE;
8355   gboolean node_visible = TRUE;
8356
8357   g_return_if_fail (path != NULL || iter != NULL);
8358
8359   if (tree_view->priv->fixed_height_mode
8360       && tree_view->priv->fixed_height >= 0)
8361     height = tree_view->priv->fixed_height;
8362   else
8363     height = 0;
8364
8365   if (path == NULL)
8366     {
8367       path = gtk_tree_model_get_path (model, iter);
8368       free_path = TRUE;
8369     }
8370   else if (iter == NULL)
8371     gtk_tree_model_get_iter (model, iter, path);
8372
8373   if (tree_view->priv->tree == NULL)
8374     tree_view->priv->tree = _gtk_rbtree_new ();
8375
8376   tmptree = tree = tree_view->priv->tree;
8377
8378   /* Update all row-references */
8379   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8380   depth = gtk_tree_path_get_depth (path);
8381   indices = gtk_tree_path_get_indices (path);
8382
8383   /* First, find the parent tree */
8384   while (i < depth - 1)
8385     {
8386       if (tmptree == NULL)
8387         {
8388           /* We aren't showing the node */
8389           node_visible = FALSE;
8390           goto done;
8391         }
8392
8393       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8394       if (tmpnode == NULL)
8395         {
8396           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8397                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8398                      "before the parent was inserted.");
8399           goto done;
8400         }
8401       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8402         {
8403           /* FIXME enforce correct behavior on model, probably */
8404           /* In theory, the model should have emitted has_child_toggled here.  We
8405            * try to catch it anyway, just to be safe, in case the model hasn't.
8406            */
8407           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8408                                                            tree,
8409                                                            tmpnode);
8410           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8411           gtk_tree_path_free (tmppath);
8412           goto done;
8413         }
8414
8415       tmptree = tmpnode->children;
8416       tree = tmptree;
8417       i++;
8418     }
8419
8420   if (tree == NULL)
8421     {
8422       node_visible = FALSE;
8423       goto done;
8424     }
8425
8426   /* ref the node */
8427   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8428   if (indices[depth - 1] == 0)
8429     {
8430       tmpnode = _gtk_rbtree_find_count (tree, 1);
8431       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8432     }
8433   else
8434     {
8435       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8436       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8437     }
8438
8439  done:
8440   if (height > 0)
8441     {
8442       if (tree)
8443         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8444
8445       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8446         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8447       else
8448         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8449     }
8450   else
8451     install_presize_handler (tree_view);
8452   if (free_path)
8453     gtk_tree_path_free (path);
8454 }
8455
8456 static void
8457 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8458                                      GtkTreePath  *path,
8459                                      GtkTreeIter  *iter,
8460                                      gpointer      data)
8461 {
8462   GtkTreeView *tree_view = (GtkTreeView *)data;
8463   GtkTreeIter real_iter;
8464   gboolean has_child;
8465   GtkRBTree *tree;
8466   GtkRBNode *node;
8467   gboolean free_path = FALSE;
8468
8469   g_return_if_fail (path != NULL || iter != NULL);
8470
8471   if (iter)
8472     real_iter = *iter;
8473
8474   if (path == NULL)
8475     {
8476       path = gtk_tree_model_get_path (model, iter);
8477       free_path = TRUE;
8478     }
8479   else if (iter == NULL)
8480     gtk_tree_model_get_iter (model, &real_iter, path);
8481
8482   if (_gtk_tree_view_find_node (tree_view,
8483                                 path,
8484                                 &tree,
8485                                 &node))
8486     /* We aren't actually showing the node */
8487     goto done;
8488
8489   if (tree == NULL)
8490     goto done;
8491
8492   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8493   /* Sanity check.
8494    */
8495   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8496     goto done;
8497
8498   if (has_child)
8499     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8500   else
8501     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8502
8503   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8504     {
8505       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8506       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8507         {
8508           GList *list;
8509
8510           for (list = tree_view->priv->columns; list; list = list->next)
8511             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8512               {
8513                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8514                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8515                 break;
8516               }
8517         }
8518       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8519     }
8520   else
8521     {
8522       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8523     }
8524
8525  done:
8526   if (free_path)
8527     gtk_tree_path_free (path);
8528 }
8529
8530 static void
8531 count_children_helper (GtkRBTree *tree,
8532                        GtkRBNode *node,
8533                        gpointer   data)
8534 {
8535   if (node->children)
8536     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8537   (*((gint *)data))++;
8538 }
8539
8540 static void
8541 check_selection_helper (GtkRBTree *tree,
8542                         GtkRBNode *node,
8543                         gpointer   data)
8544 {
8545   gint *value = (gint *)data;
8546
8547   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8548
8549   if (node->children && !*value)
8550     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8551 }
8552
8553 static void
8554 gtk_tree_view_row_deleted (GtkTreeModel *model,
8555                            GtkTreePath  *path,
8556                            gpointer      data)
8557 {
8558   GtkTreeView *tree_view = (GtkTreeView *)data;
8559   GtkRBTree *tree;
8560   GtkRBNode *node;
8561   GList *list;
8562   gint selection_changed = FALSE;
8563
8564   g_return_if_fail (path != NULL);
8565
8566   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8567
8568   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8569     return;
8570
8571   if (tree == NULL)
8572     return;
8573
8574   /* check if the selection has been changed */
8575   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8576                         check_selection_helper, &selection_changed);
8577
8578   for (list = tree_view->priv->columns; list; list = list->next)
8579     if (((GtkTreeViewColumn *)list->data)->visible &&
8580         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8581       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8582
8583   /* Ensure we don't have a dangling pointer to a dead node */
8584   ensure_unprelighted (tree_view);
8585
8586   /* Cancel editting if we've started */
8587   gtk_tree_view_stop_editing (tree_view, TRUE);
8588
8589   /* If we have a node expanded/collapsed timeout, remove it */
8590   remove_expand_collapse_timeout (tree_view);
8591
8592   if (tree_view->priv->destroy_count_func)
8593     {
8594       gint child_count = 0;
8595       if (node->children)
8596         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8597       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8598     }
8599
8600   if (tree->root->count == 1)
8601     {
8602       if (tree_view->priv->tree == tree)
8603         tree_view->priv->tree = NULL;
8604
8605       _gtk_rbtree_remove (tree);
8606     }
8607   else
8608     {
8609       _gtk_rbtree_remove_node (tree, node);
8610     }
8611
8612   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8613     {
8614       gtk_tree_row_reference_free (tree_view->priv->top_row);
8615       tree_view->priv->top_row = NULL;
8616     }
8617
8618   install_scroll_sync_handler (tree_view);
8619
8620   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8621
8622   if (selection_changed)
8623     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8624 }
8625
8626 static void
8627 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8628                               GtkTreePath  *parent,
8629                               GtkTreeIter  *iter,
8630                               gint         *new_order,
8631                               gpointer      data)
8632 {
8633   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8634   GtkRBTree *tree;
8635   GtkRBNode *node;
8636   gint len;
8637
8638   len = gtk_tree_model_iter_n_children (model, iter);
8639
8640   if (len < 2)
8641     return;
8642
8643   gtk_tree_row_reference_reordered (G_OBJECT (data),
8644                                     parent,
8645                                     iter,
8646                                     new_order);
8647
8648   if (_gtk_tree_view_find_node (tree_view,
8649                                 parent,
8650                                 &tree,
8651                                 &node))
8652     return;
8653
8654   /* We need to special case the parent path */
8655   if (tree == NULL)
8656     tree = tree_view->priv->tree;
8657   else
8658     tree = node->children;
8659
8660   if (tree == NULL)
8661     return;
8662
8663   if (tree_view->priv->edited_column)
8664     gtk_tree_view_stop_editing (tree_view, TRUE);
8665
8666   /* we need to be unprelighted */
8667   ensure_unprelighted (tree_view);
8668
8669   /* clear the timeout */
8670   cancel_arrow_animation (tree_view);
8671   
8672   _gtk_rbtree_reorder (tree, new_order, len);
8673
8674   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8675
8676   gtk_tree_view_dy_to_top_row (tree_view);
8677 }
8678
8679
8680 /* Internal tree functions
8681  */
8682
8683
8684 static void
8685 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8686                                      GtkRBTree         *tree,
8687                                      GtkTreeViewColumn *column,
8688                                      gint              *x1,
8689                                      gint              *x2)
8690 {
8691   GtkTreeViewColumn *tmp_column = NULL;
8692   gint total_width;
8693   GList *list;
8694   gboolean rtl;
8695
8696   if (x1)
8697     *x1 = 0;
8698
8699   if (x2)
8700     *x2 = 0;
8701
8702   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8703
8704   total_width = 0;
8705   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8706        list;
8707        list = (rtl ? list->prev : list->next))
8708     {
8709       tmp_column = list->data;
8710
8711       if (tmp_column == column)
8712         break;
8713
8714       if (tmp_column->visible)
8715         total_width += tmp_column->width;
8716     }
8717
8718   if (tmp_column != column)
8719     {
8720       g_warning (G_STRLOC": passed-in column isn't in the tree");
8721       return;
8722     }
8723
8724   if (x1)
8725     *x1 = total_width;
8726
8727   if (x2)
8728     {
8729       if (column->visible)
8730         *x2 = total_width + column->width;
8731       else
8732         *x2 = total_width; /* width of 0 */
8733     }
8734 }
8735 static void
8736 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8737                                 GtkRBTree   *tree,
8738                                 gint        *x1,
8739                                 gint        *x2)
8740 {
8741   gint x_offset = 0;
8742   GList *list;
8743   GtkTreeViewColumn *tmp_column = NULL;
8744   gint total_width;
8745   gboolean indent_expanders;
8746   gboolean rtl;
8747
8748   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8749
8750   total_width = 0;
8751   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8752        list;
8753        list = (rtl ? list->prev : list->next))
8754     {
8755       tmp_column = list->data;
8756
8757       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8758         {
8759           if (rtl)
8760             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8761           else
8762             x_offset = total_width;
8763           break;
8764         }
8765
8766       if (tmp_column->visible)
8767         total_width += tmp_column->width;
8768     }
8769
8770   gtk_widget_style_get (GTK_WIDGET (tree_view),
8771                         "indent-expanders", &indent_expanders,
8772                         NULL);
8773
8774   if (indent_expanders)
8775     {
8776       if (rtl)
8777         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8778       else
8779         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8780     }
8781
8782   *x1 = x_offset;
8783   
8784   if (tmp_column && tmp_column->visible)
8785     /* +1 because x2 isn't included in the range. */
8786     *x2 = *x1 + tree_view->priv->expander_size + 1;
8787   else
8788     *x2 = *x1;
8789 }
8790
8791 static void
8792 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8793                           GtkRBTree   *tree,
8794                           GtkTreeIter *iter,
8795                           gint         depth,
8796                           gboolean     recurse)
8797 {
8798   GtkRBNode *temp = NULL;
8799   GtkTreePath *path = NULL;
8800   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8801
8802   do
8803     {
8804       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8805       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8806
8807       if (tree_view->priv->fixed_height > 0)
8808         {
8809           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8810             {
8811               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8812               _gtk_rbtree_node_mark_valid (tree, temp);
8813             }
8814         }
8815
8816       if (is_list)
8817         continue;
8818
8819       if (recurse)
8820         {
8821           GtkTreeIter child;
8822
8823           if (!path)
8824             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8825           else
8826             gtk_tree_path_next (path);
8827
8828           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8829             {
8830               gboolean expand;
8831
8832               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8833
8834               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8835                   && !expand)
8836                 {
8837                   temp->children = _gtk_rbtree_new ();
8838                   temp->children->parent_tree = tree;
8839                   temp->children->parent_node = temp;
8840                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8841                 }
8842             }
8843         }
8844
8845       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8846         {
8847           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8848             temp->flags ^= GTK_RBNODE_IS_PARENT;
8849         }
8850     }
8851   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8852
8853   if (path)
8854     gtk_tree_path_free (path);
8855 }
8856
8857 /* Make sure the node is visible vertically */
8858 static void
8859 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8860                                   GtkRBTree   *tree,
8861                                   GtkRBNode   *node)
8862 {
8863   gint node_dy, height;
8864   GtkTreePath *path = NULL;
8865
8866   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8867     return;
8868
8869   /* just return if the node is visible, avoiding a costly expose */
8870   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8871   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8872   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8873       && node_dy >= tree_view->priv->vadjustment->value
8874       && node_dy + height <= (tree_view->priv->vadjustment->value
8875                               + tree_view->priv->vadjustment->page_size))
8876     return;
8877
8878   path = _gtk_tree_view_find_path (tree_view, tree, node);
8879   if (path)
8880     {
8881       /* We process updates because we want to clear old selected items when we scroll.
8882        * if this is removed, we get a "selection streak" at the bottom. */
8883       gtk_tree_view_bin_process_updates (tree_view);
8884
8885       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8886       gtk_tree_path_free (path);
8887     }
8888 }
8889
8890 static void
8891 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8892                                     GtkTreeViewColumn *column,
8893                                     gboolean           focus_to_cell)
8894 {
8895   GtkAllocation allocation;
8896   gint x, width;
8897
8898   if (column == NULL)
8899     return;
8900
8901   gtk_widget_get_allocation (column->button, &allocation);
8902   x = allocation.x;
8903   width = allocation.width;
8904
8905   if (width > tree_view->priv->hadjustment->page_size)
8906     {
8907       /* The column is larger than the horizontal page size.  If the
8908        * column has cells which can be focussed individually, then we make
8909        * sure the cell which gets focus is fully visible (if even the
8910        * focus cell is bigger than the page size, we make sure the
8911        * left-hand side of the cell is visible).
8912        *
8913        * If the column does not have those so-called special cells, we
8914        * make sure the left-hand side of the column is visible.
8915        */
8916
8917       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8918         {
8919           GtkTreePath *cursor_path;
8920           GdkRectangle background_area, cell_area, focus_area;
8921
8922           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8923
8924           gtk_tree_view_get_cell_area (tree_view,
8925                                        cursor_path, column, &cell_area);
8926           gtk_tree_view_get_background_area (tree_view,
8927                                              cursor_path, column,
8928                                              &background_area);
8929
8930           gtk_tree_path_free (cursor_path);
8931
8932           _gtk_tree_view_column_get_focus_area (column,
8933                                                 &background_area,
8934                                                 &cell_area,
8935                                                 &focus_area);
8936
8937           x = focus_area.x;
8938           width = focus_area.width;
8939
8940           if (width < tree_view->priv->hadjustment->page_size)
8941             {
8942               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8943                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8944                                           x + width - tree_view->priv->hadjustment->page_size);
8945               else if (tree_view->priv->hadjustment->value > x)
8946                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8947             }
8948         }
8949
8950       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8951     }
8952   else
8953     {
8954       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8955           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8956                                     x + width - tree_view->priv->hadjustment->page_size);
8957       else if (tree_view->priv->hadjustment->value > x)
8958         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8959   }
8960 }
8961
8962 /* This function could be more efficient.  I'll optimize it if profiling seems
8963  * to imply that it is important */
8964 GtkTreePath *
8965 _gtk_tree_view_find_path (GtkTreeView *tree_view,
8966                           GtkRBTree   *tree,
8967                           GtkRBNode   *node)
8968 {
8969   GtkTreePath *path;
8970   GtkRBTree *tmp_tree;
8971   GtkRBNode *tmp_node, *last;
8972   gint count;
8973
8974   path = gtk_tree_path_new ();
8975
8976   g_return_val_if_fail (node != NULL, path);
8977   g_return_val_if_fail (node != tree->nil, path);
8978
8979   count = 1 + node->left->count;
8980
8981   last = node;
8982   tmp_node = node->parent;
8983   tmp_tree = tree;
8984   while (tmp_tree)
8985     {
8986       while (tmp_node != tmp_tree->nil)
8987         {
8988           if (tmp_node->right == last)
8989             count += 1 + tmp_node->left->count;
8990           last = tmp_node;
8991           tmp_node = tmp_node->parent;
8992         }
8993       gtk_tree_path_prepend_index (path, count - 1);
8994       last = tmp_tree->parent_node;
8995       tmp_tree = tmp_tree->parent_tree;
8996       if (last)
8997         {
8998           count = 1 + last->left->count;
8999           tmp_node = last->parent;
9000         }
9001     }
9002   return path;
9003 }
9004
9005 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9006  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9007  * both set to NULL.
9008  */
9009 gboolean
9010 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9011                           GtkTreePath  *path,
9012                           GtkRBTree   **tree,
9013                           GtkRBNode   **node)
9014 {
9015   GtkRBNode *tmpnode = NULL;
9016   GtkRBTree *tmptree = tree_view->priv->tree;
9017   gint *indices = gtk_tree_path_get_indices (path);
9018   gint depth = gtk_tree_path_get_depth (path);
9019   gint i = 0;
9020
9021   *node = NULL;
9022   *tree = NULL;
9023
9024   if (depth == 0 || tmptree == NULL)
9025     return FALSE;
9026   do
9027     {
9028       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9029       ++i;
9030       if (tmpnode == NULL)
9031         {
9032           *tree = NULL;
9033           *node = NULL;
9034           return FALSE;
9035         }
9036       if (i >= depth)
9037         {
9038           *tree = tmptree;
9039           *node = tmpnode;
9040           return FALSE;
9041         }
9042       *tree = tmptree;
9043       *node = tmpnode;
9044       tmptree = tmpnode->children;
9045       if (tmptree == NULL)
9046         return TRUE;
9047     }
9048   while (1);
9049 }
9050
9051 static gboolean
9052 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9053                                   GtkTreeViewColumn *column)
9054 {
9055   GList *list;
9056
9057   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9058     return FALSE;
9059
9060   if (tree_view->priv->expander_column != NULL)
9061     {
9062       if (tree_view->priv->expander_column == column)
9063         return TRUE;
9064       return FALSE;
9065     }
9066   else
9067     {
9068       for (list = tree_view->priv->columns;
9069            list;
9070            list = list->next)
9071         if (((GtkTreeViewColumn *)list->data)->visible)
9072           break;
9073       if (list && list->data == column)
9074         return TRUE;
9075     }
9076   return FALSE;
9077 }
9078
9079 static void
9080 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9081                                 guint           keyval,
9082                                 guint           modmask,
9083                                 gboolean        add_shifted_binding,
9084                                 GtkMovementStep step,
9085                                 gint            count)
9086 {
9087   
9088   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9089                                 "move-cursor", 2,
9090                                 G_TYPE_ENUM, step,
9091                                 G_TYPE_INT, count);
9092
9093   if (add_shifted_binding)
9094     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9095                                   "move-cursor", 2,
9096                                   G_TYPE_ENUM, step,
9097                                   G_TYPE_INT, count);
9098
9099   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9100    return;
9101
9102   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9103                                 "move-cursor", 2,
9104                                 G_TYPE_ENUM, step,
9105                                 G_TYPE_INT, count);
9106
9107   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9108                                 "move-cursor", 2,
9109                                 G_TYPE_ENUM, step,
9110                                 G_TYPE_INT, count);
9111 }
9112
9113 static gint
9114 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9115                                  GtkTreeIter  *iter,
9116                                  GtkRBTree    *tree,
9117                                  GtkRBNode    *node)
9118 {
9119   gint retval = FALSE;
9120   do
9121     {
9122       g_return_val_if_fail (node != NULL, FALSE);
9123
9124       if (node->children)
9125         {
9126           GtkTreeIter child;
9127           GtkRBTree *new_tree;
9128           GtkRBNode *new_node;
9129
9130           new_tree = node->children;
9131           new_node = new_tree->root;
9132
9133           while (new_node && new_node->left != new_tree->nil)
9134             new_node = new_node->left;
9135
9136           if (!gtk_tree_model_iter_children (model, &child, iter))
9137             return FALSE;
9138
9139           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9140         }
9141
9142       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9143         retval = TRUE;
9144       gtk_tree_model_unref_node (model, iter);
9145       node = _gtk_rbtree_next (tree, node);
9146     }
9147   while (gtk_tree_model_iter_next (model, iter));
9148
9149   return retval;
9150 }
9151
9152 static gint
9153 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9154                                               GtkRBTree   *tree)
9155 {
9156   GtkTreeIter iter;
9157   GtkTreePath *path;
9158   GtkRBNode *node;
9159   gint retval;
9160
9161   if (!tree)
9162     return FALSE;
9163
9164   node = tree->root;
9165   while (node && node->left != tree->nil)
9166     node = node->left;
9167
9168   g_return_val_if_fail (node != NULL, FALSE);
9169   path = _gtk_tree_view_find_path (tree_view, tree, node);
9170   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9171                            &iter, path);
9172   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9173   gtk_tree_path_free (path);
9174
9175   return retval;
9176 }
9177
9178 static void
9179 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9180                                     GtkTreeViewColumn *column)
9181 {
9182   GtkTreeViewColumn *left_column;
9183   GtkTreeViewColumn *cur_column = NULL;
9184   GtkTreeViewColumnReorder *reorder;
9185   gboolean rtl;
9186   GList *tmp_list;
9187   gint left;
9188
9189   /* We want to precalculate the motion list such that we know what column slots
9190    * are available.
9191    */
9192   left_column = NULL;
9193   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9194
9195   /* First, identify all possible drop spots */
9196   if (rtl)
9197     tmp_list = g_list_last (tree_view->priv->columns);
9198   else
9199     tmp_list = g_list_first (tree_view->priv->columns);
9200
9201   while (tmp_list)
9202     {
9203       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9204       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9205
9206       if (cur_column->visible == FALSE)
9207         continue;
9208
9209       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9210       if (left_column != column && cur_column != column &&
9211           tree_view->priv->column_drop_func &&
9212           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9213         {
9214           left_column = cur_column;
9215           continue;
9216         }
9217       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9218       reorder->left_column = left_column;
9219       left_column = reorder->right_column = cur_column;
9220
9221       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9222     }
9223
9224   /* Add the last one */
9225   if (tree_view->priv->column_drop_func == NULL ||
9226       ((left_column != column) &&
9227        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9228     {
9229       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9230       reorder->left_column = left_column;
9231       reorder->right_column = NULL;
9232       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9233     }
9234
9235   /* We quickly check to see if it even makes sense to reorder columns. */
9236   /* If there is nothing that can be moved, then we return */
9237
9238   if (tree_view->priv->column_drag_info == NULL)
9239     return;
9240
9241   /* We know there are always 2 slots possbile, as you can always return column. */
9242   /* If that's all there is, return */
9243   if (tree_view->priv->column_drag_info->next == NULL || 
9244       (tree_view->priv->column_drag_info->next->next == NULL &&
9245        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9246        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9247     {
9248       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9249         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9250       g_list_free (tree_view->priv->column_drag_info);
9251       tree_view->priv->column_drag_info = NULL;
9252       return;
9253     }
9254   /* We fill in the ranges for the columns, now that we've isolated them */
9255   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9256
9257   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9258     {
9259       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9260
9261       reorder->left_align = left;
9262       if (tmp_list->next != NULL)
9263         {
9264           GtkAllocation right_allocation, left_allocation;
9265
9266           g_assert (tmp_list->next->data);
9267
9268           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
9269           gtk_widget_get_allocation (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button, &left_allocation);
9270           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9271         }
9272       else
9273         {
9274           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9275                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9276         }
9277     }
9278 }
9279
9280 void
9281 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9282                                   GtkTreeViewColumn *column,
9283                                   GdkDevice         *device)
9284 {
9285   GdkEvent *send_event;
9286   GtkAllocation allocation;
9287   GtkAllocation button_allocation;
9288   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9289   GdkDisplay *display = gdk_screen_get_display (screen);
9290
9291   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9292   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9293
9294   gtk_tree_view_set_column_drag_info (tree_view, column);
9295
9296   if (tree_view->priv->column_drag_info == NULL)
9297     return;
9298
9299   if (tree_view->priv->drag_window == NULL)
9300     {
9301       GdkWindowAttr attributes;
9302       guint attributes_mask;
9303
9304       gtk_widget_get_allocation (column->button, &button_allocation);
9305
9306       attributes.window_type = GDK_WINDOW_CHILD;
9307       attributes.wclass = GDK_INPUT_OUTPUT;
9308       attributes.x = button_allocation.x;
9309       attributes.y = 0;
9310       attributes.width = button_allocation.width;
9311       attributes.height = button_allocation.height;
9312       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9313       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9314       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9315
9316       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9317                                                      &attributes,
9318                                                      attributes_mask);
9319       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9320     }
9321
9322   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9323   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9324
9325   gtk_grab_remove (column->button);
9326
9327   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9328   send_event->crossing.send_event = TRUE;
9329   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (column->button)));
9330   send_event->crossing.subwindow = NULL;
9331   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9332   send_event->crossing.time = GDK_CURRENT_TIME;
9333   gdk_event_set_device (send_event, device);
9334
9335   gtk_propagate_event (column->button, send_event);
9336   gdk_event_free (send_event);
9337
9338   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9339   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9340   send_event->button.send_event = TRUE;
9341   send_event->button.time = GDK_CURRENT_TIME;
9342   send_event->button.x = -1;
9343   send_event->button.y = -1;
9344   send_event->button.axes = NULL;
9345   send_event->button.state = 0;
9346   send_event->button.button = 1;
9347   send_event->button.x_root = 0;
9348   send_event->button.y_root = 0;
9349   gdk_event_set_device (send_event, device);
9350
9351   gtk_propagate_event (column->button, send_event);
9352   gdk_event_free (send_event);
9353
9354   /* Kids, don't try this at home */
9355   g_object_ref (column->button);
9356   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9357   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9358   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9359   g_object_unref (column->button);
9360
9361   gtk_widget_get_allocation (column->button, &button_allocation);
9362   tree_view->priv->drag_column_x = button_allocation.x;
9363   allocation = button_allocation;
9364   allocation.x = 0;
9365   gtk_widget_size_allocate (column->button, &allocation);
9366   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9367
9368   tree_view->priv->drag_column = column;
9369   gdk_window_show (tree_view->priv->drag_window);
9370
9371   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9372   while (gtk_events_pending ())
9373     gtk_main_iteration ();
9374
9375   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9376   gdk_pointer_grab (tree_view->priv->drag_window,
9377                     FALSE,
9378                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9379                     NULL, NULL, GDK_CURRENT_TIME);
9380   gdk_keyboard_grab (tree_view->priv->drag_window,
9381                      FALSE,
9382                      GDK_CURRENT_TIME);
9383 }
9384
9385 static void
9386 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9387                                 GtkRBTree          *tree,
9388                                 GtkRBNode          *node)
9389 {
9390   GtkAllocation allocation;
9391   GdkRectangle rect;
9392
9393   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9394     return;
9395
9396   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9397   rect.x = 0;
9398   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9399
9400   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9401   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9402
9403   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9404 }
9405
9406 void
9407 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9408                                 GtkRBTree          *tree,
9409                                 GtkRBNode          *node,
9410                                 const GdkRectangle *clip_rect)
9411 {
9412   GtkAllocation allocation;
9413   GdkRectangle rect;
9414
9415   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9416     return;
9417
9418   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9419   rect.x = 0;
9420   rect.width = MAX (tree_view->priv->width, allocation.width);
9421
9422   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9423   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9424
9425   if (clip_rect)
9426     {
9427       GdkRectangle new_rect;
9428
9429       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9430
9431       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9432     }
9433   else
9434     {
9435       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9436     }
9437 }
9438
9439 static void
9440 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9441                                GtkTreePath        *path,
9442                                const GdkRectangle *clip_rect)
9443 {
9444   GtkRBTree *tree = NULL;
9445   GtkRBNode *node = NULL;
9446
9447   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9448
9449   if (tree)
9450     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9451 }
9452
9453 /* x and y are the mouse position
9454  */
9455 static void
9456 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9457                           cairo_t     *cr,
9458                           GtkRBTree   *tree,
9459                           GtkRBNode   *node,
9460                           /* in bin_window coordinates */
9461                           gint         x,
9462                           gint         y)
9463 {
9464   GdkRectangle area;
9465   GtkStateType state;
9466   GtkWidget *widget;
9467   gint x_offset = 0;
9468   gint x2;
9469   gint vertical_separator;
9470   gint expander_size;
9471   GtkExpanderStyle expander_style;
9472
9473   widget = GTK_WIDGET (tree_view);
9474
9475   gtk_widget_style_get (widget,
9476                         "vertical-separator", &vertical_separator,
9477                         NULL);
9478   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9479
9480   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9481     return;
9482
9483   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9484
9485   area.x = x_offset;
9486   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9487   area.width = expander_size + 2;
9488   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9489
9490   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9491     {
9492       state = GTK_STATE_INSENSITIVE;
9493     }
9494   else if (node == tree_view->priv->button_pressed_node)
9495     {
9496       if (x >= area.x && x <= (area.x + area.width) &&
9497           y >= area.y && y <= (area.y + area.height))
9498         state = GTK_STATE_ACTIVE;
9499       else
9500         state = GTK_STATE_NORMAL;
9501     }
9502   else
9503     {
9504       if (node == tree_view->priv->prelight_node &&
9505           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9506         state = GTK_STATE_PRELIGHT;
9507       else
9508         state = GTK_STATE_NORMAL;
9509     }
9510
9511   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9512     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9513   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9514     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9515   else if (node->children != NULL)
9516     expander_style = GTK_EXPANDER_EXPANDED;
9517   else
9518     expander_style = GTK_EXPANDER_COLLAPSED;
9519
9520   gtk_paint_expander (gtk_widget_get_style (widget),
9521                       cr,
9522                       state,
9523                       widget,
9524                       "treeview",
9525                       area.x + area.width / 2,
9526                       area.y + area.height / 2,
9527                       expander_style);
9528 }
9529
9530 static void
9531 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9532
9533 {
9534   GtkTreePath *cursor_path;
9535
9536   if ((tree_view->priv->tree == NULL) ||
9537       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
9538     return;
9539
9540   cursor_path = NULL;
9541   if (tree_view->priv->cursor)
9542     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9543
9544   if (cursor_path == NULL)
9545     {
9546       /* Consult the selection before defaulting to the
9547        * first focusable element
9548        */
9549       GList *selected_rows;
9550       GtkTreeModel *model;
9551       GtkTreeSelection *selection;
9552
9553       selection = gtk_tree_view_get_selection (tree_view);
9554       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9555
9556       if (selected_rows)
9557         {
9558           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9559           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9560           g_list_free (selected_rows);
9561         }
9562       else
9563         {
9564           cursor_path = gtk_tree_path_new_first ();
9565           search_first_focusable_path (tree_view, &cursor_path,
9566                                        TRUE, NULL, NULL);
9567         }
9568
9569       gtk_tree_row_reference_free (tree_view->priv->cursor);
9570       tree_view->priv->cursor = NULL;
9571
9572       if (cursor_path)
9573         {
9574           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9575             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9576           else
9577             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9578         }
9579     }
9580
9581   if (cursor_path)
9582     {
9583       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9584
9585       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9586       gtk_tree_path_free (cursor_path);
9587
9588       if (tree_view->priv->focus_column == NULL)
9589         {
9590           GList *list;
9591           for (list = tree_view->priv->columns; list; list = list->next)
9592             {
9593               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9594                 {
9595                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9596                   break;
9597                 }
9598             }
9599         }
9600     }
9601 }
9602
9603 static void
9604 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9605                                    gint         count)
9606 {
9607   gint selection_count;
9608   GtkRBTree *cursor_tree = NULL;
9609   GtkRBNode *cursor_node = NULL;
9610   GtkRBTree *new_cursor_tree = NULL;
9611   GtkRBNode *new_cursor_node = NULL;
9612   GtkTreePath *cursor_path = NULL;
9613   gboolean grab_focus = TRUE;
9614   gboolean selectable;
9615
9616   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9617     return;
9618
9619   cursor_path = NULL;
9620   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9621     /* FIXME: we lost the cursor; should we get the first? */
9622     return;
9623
9624   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9625   _gtk_tree_view_find_node (tree_view, cursor_path,
9626                             &cursor_tree, &cursor_node);
9627
9628   if (cursor_tree == NULL)
9629     /* FIXME: we lost the cursor; should we get the first? */
9630     return;
9631
9632   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9633   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9634                                                       cursor_node,
9635                                                       cursor_path);
9636
9637   if (selection_count == 0
9638       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9639       && !tree_view->priv->ctrl_pressed
9640       && selectable)
9641     {
9642       /* Don't move the cursor, but just select the current node */
9643       new_cursor_tree = cursor_tree;
9644       new_cursor_node = cursor_node;
9645     }
9646   else
9647     {
9648       if (count == -1)
9649         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9650                                &new_cursor_tree, &new_cursor_node);
9651       else
9652         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9653                                &new_cursor_tree, &new_cursor_node);
9654     }
9655
9656   gtk_tree_path_free (cursor_path);
9657
9658   if (new_cursor_node)
9659     {
9660       cursor_path = _gtk_tree_view_find_path (tree_view,
9661                                               new_cursor_tree, new_cursor_node);
9662
9663       search_first_focusable_path (tree_view, &cursor_path,
9664                                    (count != -1),
9665                                    &new_cursor_tree,
9666                                    &new_cursor_node);
9667
9668       if (cursor_path)
9669         gtk_tree_path_free (cursor_path);
9670     }
9671
9672   /*
9673    * If the list has only one item and multi-selection is set then select
9674    * the row (if not yet selected).
9675    */
9676   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9677       new_cursor_node == NULL)
9678     {
9679       if (count == -1)
9680         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9681                                &new_cursor_tree, &new_cursor_node);
9682       else
9683         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9684                                &new_cursor_tree, &new_cursor_node);
9685
9686       if (new_cursor_node == NULL
9687           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9688         {
9689           new_cursor_node = cursor_node;
9690           new_cursor_tree = cursor_tree;
9691         }
9692       else
9693         {
9694           new_cursor_node = NULL;
9695         }
9696     }
9697
9698   if (new_cursor_node)
9699     {
9700       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9701       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9702       gtk_tree_path_free (cursor_path);
9703     }
9704   else
9705     {
9706       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9707
9708       if (!tree_view->priv->shift_pressed)
9709         {
9710           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9711                                           count < 0 ?
9712                                           GTK_DIR_UP : GTK_DIR_DOWN))
9713             {
9714               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9715
9716               if (toplevel)
9717                 gtk_widget_child_focus (toplevel,
9718                                         count < 0 ?
9719                                         GTK_DIR_TAB_BACKWARD :
9720                                         GTK_DIR_TAB_FORWARD);
9721
9722               grab_focus = FALSE;
9723             }
9724         }
9725       else
9726         {
9727           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9728         }
9729     }
9730
9731   if (grab_focus)
9732     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9733 }
9734
9735 static void
9736 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9737                                         gint         count)
9738 {
9739   GtkRBTree *cursor_tree = NULL;
9740   GtkRBNode *cursor_node = NULL;
9741   GtkTreePath *old_cursor_path = NULL;
9742   GtkTreePath *cursor_path = NULL;
9743   GtkRBTree *start_cursor_tree = NULL;
9744   GtkRBNode *start_cursor_node = NULL;
9745   gint y;
9746   gint window_y;
9747   gint vertical_separator;
9748
9749   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9750     return;
9751
9752   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9753     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9754   else
9755     /* This is sorta weird.  Focus in should give us a cursor */
9756     return;
9757
9758   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9759   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9760                             &cursor_tree, &cursor_node);
9761
9762   if (cursor_tree == NULL)
9763     {
9764       /* FIXME: we lost the cursor.  Should we try to get one? */
9765       gtk_tree_path_free (old_cursor_path);
9766       return;
9767     }
9768   g_return_if_fail (cursor_node != NULL);
9769
9770   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9771   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9772   y += tree_view->priv->cursor_offset;
9773   y += count * (int)tree_view->priv->vadjustment->page_increment;
9774   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9775
9776   if (y >= tree_view->priv->height)
9777     y = tree_view->priv->height - 1;
9778
9779   tree_view->priv->cursor_offset =
9780     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9781                              &cursor_tree, &cursor_node);
9782
9783   if (cursor_tree == NULL)
9784     {
9785       /* FIXME: we lost the cursor.  Should we try to get one? */
9786       gtk_tree_path_free (old_cursor_path);
9787       return;
9788     }
9789
9790   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9791     {
9792       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9793                              &cursor_tree, &cursor_node);
9794       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9795     }
9796
9797   y -= tree_view->priv->cursor_offset;
9798   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9799
9800   start_cursor_tree = cursor_tree;
9801   start_cursor_node = cursor_node;
9802
9803   if (! search_first_focusable_path (tree_view, &cursor_path,
9804                                      (count != -1),
9805                                      &cursor_tree, &cursor_node))
9806     {
9807       /* It looks like we reached the end of the view without finding
9808        * a focusable row.  We will step backwards to find the last
9809        * focusable row.
9810        */
9811       cursor_tree = start_cursor_tree;
9812       cursor_node = start_cursor_node;
9813       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9814
9815       search_first_focusable_path (tree_view, &cursor_path,
9816                                    (count == -1),
9817                                    &cursor_tree, &cursor_node);
9818     }
9819
9820   if (!cursor_path)
9821     goto cleanup;
9822
9823   /* update y */
9824   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9825
9826   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9827
9828   y -= window_y;
9829   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9830   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9831   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9832
9833   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9834     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9835
9836   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9837
9838 cleanup:
9839   gtk_tree_path_free (old_cursor_path);
9840   gtk_tree_path_free (cursor_path);
9841 }
9842
9843 static void
9844 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9845                                       gint         count)
9846 {
9847   GtkRBTree *cursor_tree = NULL;
9848   GtkRBNode *cursor_node = NULL;
9849   GtkTreePath *cursor_path = NULL;
9850   GtkTreeViewColumn *column;
9851   GtkTreeIter iter;
9852   GList *list;
9853   gboolean found_column = FALSE;
9854   gboolean rtl;
9855
9856   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9857
9858   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9859     return;
9860
9861   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9862     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9863   else
9864     return;
9865
9866   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9867   if (cursor_tree == NULL)
9868     return;
9869   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9870     {
9871       gtk_tree_path_free (cursor_path);
9872       return;
9873     }
9874   gtk_tree_path_free (cursor_path);
9875
9876   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9877   if (tree_view->priv->focus_column)
9878     {
9879       for (; list; list = (rtl ? list->prev : list->next))
9880         {
9881           if (list->data == tree_view->priv->focus_column)
9882             break;
9883         }
9884     }
9885
9886   while (list)
9887     {
9888       gboolean left, right;
9889
9890       column = list->data;
9891       if (column->visible == FALSE)
9892         goto loop_end;
9893
9894       gtk_tree_view_column_cell_set_cell_data (column,
9895                                                tree_view->priv->model,
9896                                                &iter,
9897                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9898                                                cursor_node->children?TRUE:FALSE);
9899
9900       if (rtl)
9901         {
9902           right = list->prev ? TRUE : FALSE;
9903           left = list->next ? TRUE : FALSE;
9904         }
9905       else
9906         {
9907           left = list->prev ? TRUE : FALSE;
9908           right = list->next ? TRUE : FALSE;
9909         }
9910
9911       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9912         {
9913           tree_view->priv->focus_column = column;
9914           found_column = TRUE;
9915           break;
9916         }
9917     loop_end:
9918       if (count == 1)
9919         list = rtl ? list->prev : list->next;
9920       else
9921         list = rtl ? list->next : list->prev;
9922     }
9923
9924   if (found_column)
9925     {
9926       if (!gtk_tree_view_has_special_cell (tree_view))
9927         _gtk_tree_view_queue_draw_node (tree_view,
9928                                         cursor_tree,
9929                                         cursor_node,
9930                                         NULL);
9931       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9932       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9933     }
9934   else
9935     {
9936       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9937     }
9938
9939   gtk_tree_view_clamp_column_visible (tree_view,
9940                                       tree_view->priv->focus_column, TRUE);
9941 }
9942
9943 static void
9944 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9945                                      gint         count)
9946 {
9947   GtkRBTree *cursor_tree;
9948   GtkRBNode *cursor_node;
9949   GtkTreePath *path;
9950   GtkTreePath *old_path;
9951
9952   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9953     return;
9954
9955   g_return_if_fail (tree_view->priv->tree != NULL);
9956
9957   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9958
9959   cursor_tree = tree_view->priv->tree;
9960   cursor_node = cursor_tree->root;
9961
9962   if (count == -1)
9963     {
9964       while (cursor_node && cursor_node->left != cursor_tree->nil)
9965         cursor_node = cursor_node->left;
9966
9967       /* Now go forward to find the first focusable row. */
9968       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9969       search_first_focusable_path (tree_view, &path,
9970                                    TRUE, &cursor_tree, &cursor_node);
9971     }
9972   else
9973     {
9974       do
9975         {
9976           while (cursor_node && cursor_node->right != cursor_tree->nil)
9977             cursor_node = cursor_node->right;
9978           if (cursor_node->children == NULL)
9979             break;
9980
9981           cursor_tree = cursor_node->children;
9982           cursor_node = cursor_tree->root;
9983         }
9984       while (1);
9985
9986       /* Now go backwards to find last focusable row. */
9987       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9988       search_first_focusable_path (tree_view, &path,
9989                                    FALSE, &cursor_tree, &cursor_node);
9990     }
9991
9992   if (!path)
9993     goto cleanup;
9994
9995   if (gtk_tree_path_compare (old_path, path))
9996     {
9997       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
9998       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9999     }
10000   else
10001     {
10002       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10003     }
10004
10005 cleanup:
10006   gtk_tree_path_free (old_path);
10007   gtk_tree_path_free (path);
10008 }
10009
10010 static gboolean
10011 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10012 {
10013   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10014     return FALSE;
10015
10016   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10017     return FALSE;
10018
10019   gtk_tree_selection_select_all (tree_view->priv->selection);
10020
10021   return TRUE;
10022 }
10023
10024 static gboolean
10025 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10026 {
10027   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10028     return FALSE;
10029
10030   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10031     return FALSE;
10032
10033   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10034
10035   return TRUE;
10036 }
10037
10038 static gboolean
10039 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10040                                       gboolean     start_editing)
10041 {
10042   GtkRBTree *new_tree = NULL;
10043   GtkRBNode *new_node = NULL;
10044   GtkRBTree *cursor_tree = NULL;
10045   GtkRBNode *cursor_node = NULL;
10046   GtkTreePath *cursor_path = NULL;
10047   GtkTreeSelectMode mode = 0;
10048
10049   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10050     return FALSE;
10051
10052   if (tree_view->priv->cursor)
10053     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10054
10055   if (cursor_path == NULL)
10056     return FALSE;
10057
10058   _gtk_tree_view_find_node (tree_view, cursor_path,
10059                             &cursor_tree, &cursor_node);
10060
10061   if (cursor_tree == NULL)
10062     {
10063       gtk_tree_path_free (cursor_path);
10064       return FALSE;
10065     }
10066
10067   if (!tree_view->priv->shift_pressed && start_editing &&
10068       tree_view->priv->focus_column)
10069     {
10070       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10071         {
10072           gtk_tree_path_free (cursor_path);
10073           return TRUE;
10074         }
10075     }
10076
10077   if (tree_view->priv->ctrl_pressed)
10078     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10079   if (tree_view->priv->shift_pressed)
10080     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10081
10082   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10083                                             cursor_node,
10084                                             cursor_tree,
10085                                             cursor_path,
10086                                             mode,
10087                                             FALSE);
10088
10089   /* We bail out if the original (tree, node) don't exist anymore after
10090    * handling the selection-changed callback.  We do return TRUE because
10091    * the key press has been handled at this point.
10092    */
10093   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10094
10095   if (cursor_tree != new_tree || cursor_node != new_node)
10096     return FALSE;
10097
10098   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10099
10100   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10101   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10102
10103   if (!tree_view->priv->shift_pressed)
10104     gtk_tree_view_row_activated (tree_view, cursor_path,
10105                                  tree_view->priv->focus_column);
10106     
10107   gtk_tree_path_free (cursor_path);
10108
10109   return TRUE;
10110 }
10111
10112 static gboolean
10113 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10114 {
10115   GtkRBTree *new_tree = NULL;
10116   GtkRBNode *new_node = NULL;
10117   GtkRBTree *cursor_tree = NULL;
10118   GtkRBNode *cursor_node = NULL;
10119   GtkTreePath *cursor_path = NULL;
10120
10121   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10122     return FALSE;
10123
10124   cursor_path = NULL;
10125   if (tree_view->priv->cursor)
10126     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10127
10128   if (cursor_path == NULL)
10129     return FALSE;
10130
10131   _gtk_tree_view_find_node (tree_view, cursor_path,
10132                             &cursor_tree, &cursor_node);
10133   if (cursor_tree == NULL)
10134     {
10135       gtk_tree_path_free (cursor_path);
10136       return FALSE;
10137     }
10138
10139   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10140                                             cursor_node,
10141                                             cursor_tree,
10142                                             cursor_path,
10143                                             GTK_TREE_SELECT_MODE_TOGGLE,
10144                                             FALSE);
10145
10146   /* We bail out if the original (tree, node) don't exist anymore after
10147    * handling the selection-changed callback.  We do return TRUE because
10148    * the key press has been handled at this point.
10149    */
10150   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10151
10152   if (cursor_tree != new_tree || cursor_node != new_node)
10153     return FALSE;
10154
10155   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10156
10157   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10158   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10159   gtk_tree_path_free (cursor_path);
10160
10161   return TRUE;
10162 }
10163
10164 static gboolean
10165 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10166                                                gboolean     logical,
10167                                                gboolean     expand,
10168                                                gboolean     open_all)
10169 {
10170   GtkTreePath *cursor_path = NULL;
10171   GtkRBTree *tree;
10172   GtkRBNode *node;
10173
10174   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10175     return FALSE;
10176
10177   cursor_path = NULL;
10178   if (tree_view->priv->cursor)
10179     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10180
10181   if (cursor_path == NULL)
10182     return FALSE;
10183
10184   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10185     return FALSE;
10186
10187   /* Don't handle the event if we aren't an expander */
10188   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10189     return FALSE;
10190
10191   if (!logical
10192       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10193     expand = !expand;
10194
10195   if (expand)
10196     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10197   else
10198     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10199
10200   gtk_tree_path_free (cursor_path);
10201
10202   return TRUE;
10203 }
10204
10205 static gboolean
10206 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10207 {
10208   GtkRBTree *cursor_tree = NULL;
10209   GtkRBNode *cursor_node = NULL;
10210   GtkTreePath *cursor_path = NULL;
10211   GdkModifierType state;
10212
10213   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10214     goto out;
10215
10216   cursor_path = NULL;
10217   if (tree_view->priv->cursor)
10218     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10219
10220   if (cursor_path == NULL)
10221     goto out;
10222
10223   _gtk_tree_view_find_node (tree_view, cursor_path,
10224                             &cursor_tree, &cursor_node);
10225   if (cursor_tree == NULL)
10226     {
10227       gtk_tree_path_free (cursor_path);
10228       goto out;
10229     }
10230
10231   if (cursor_tree->parent_node)
10232     {
10233       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10234       cursor_node = cursor_tree->parent_node;
10235       cursor_tree = cursor_tree->parent_tree;
10236
10237       gtk_tree_path_up (cursor_path);
10238
10239       if (gtk_get_current_event_state (&state))
10240         {
10241           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10242             tree_view->priv->ctrl_pressed = TRUE;
10243         }
10244
10245       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10246       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10247
10248       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10249       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10250       gtk_tree_path_free (cursor_path);
10251
10252       tree_view->priv->ctrl_pressed = FALSE;
10253
10254       return TRUE;
10255     }
10256
10257  out:
10258
10259   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10260   return FALSE;
10261 }
10262
10263 static gboolean
10264 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10265 {
10266   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10267   tree_view->priv->typeselect_flush_timeout = 0;
10268
10269   return FALSE;
10270 }
10271
10272 /* Cut and paste from gtkwindow.c */
10273 static void
10274 send_focus_change (GtkWidget *widget,
10275                    GdkDevice *device,
10276                    gboolean   in)
10277 {
10278   GdkDeviceManager *device_manager;
10279   GList *devices, *d;
10280
10281   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10282   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10283   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10284   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10285
10286   for (d = devices; d; d = d->next)
10287     {
10288       GdkDevice *dev = d->data;
10289       GdkEvent *fevent;
10290       GdkWindow *window;
10291
10292       if (dev->source != GDK_SOURCE_KEYBOARD)
10293         continue;
10294
10295       window = gtk_widget_get_window (widget);
10296
10297       /* Skip non-master keyboards that haven't
10298        * selected for events from this window
10299        */
10300       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10301           !gdk_window_get_device_events (window, dev))
10302         continue;
10303
10304       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10305
10306       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10307       fevent->focus_change.window = g_object_ref (window);
10308       fevent->focus_change.in = in;
10309       gdk_event_set_device (fevent, device);
10310
10311       gtk_widget_send_focus_change (widget, fevent);
10312
10313       gdk_event_free (fevent);
10314     }
10315 }
10316
10317 static void
10318 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10319 {
10320   GtkWidget *frame, *vbox, *toplevel;
10321   GdkScreen *screen;
10322
10323   if (tree_view->priv->search_custom_entry_set)
10324     return;
10325
10326   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10327   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10328
10329    if (tree_view->priv->search_window != NULL)
10330      {
10331        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10332          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10333                                       GTK_WINDOW (tree_view->priv->search_window));
10334        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10335          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10336                                          GTK_WINDOW (tree_view->priv->search_window));
10337
10338        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10339
10340        return;
10341      }
10342    
10343   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10344   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10345
10346   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10347     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10348                                  GTK_WINDOW (tree_view->priv->search_window));
10349
10350   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10351                             GDK_WINDOW_TYPE_HINT_UTILITY);
10352   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10353   g_signal_connect (tree_view->priv->search_window, "delete-event",
10354                     G_CALLBACK (gtk_tree_view_search_delete_event),
10355                     tree_view);
10356   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10357                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10358                     tree_view);
10359   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10360                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10361                     tree_view);
10362   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10363                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10364                     tree_view);
10365
10366   frame = gtk_frame_new (NULL);
10367   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10368   gtk_widget_show (frame);
10369   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10370
10371   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
10372   gtk_widget_show (vbox);
10373   gtk_container_add (GTK_CONTAINER (frame), vbox);
10374   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10375
10376   /* add entry */
10377   tree_view->priv->search_entry = gtk_entry_new ();
10378   gtk_widget_show (tree_view->priv->search_entry);
10379   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10380                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10381                     tree_view);
10382   g_signal_connect (tree_view->priv->search_entry,
10383                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10384                     tree_view);
10385   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10386                     "preedit-changed",
10387                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10388                     tree_view);
10389   gtk_container_add (GTK_CONTAINER (vbox),
10390                      tree_view->priv->search_entry);
10391
10392   gtk_widget_realize (tree_view->priv->search_entry);
10393 }
10394
10395 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10396  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10397  */
10398 static gboolean
10399 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10400                                              GdkDevice   *device,
10401                                              gboolean     keybinding)
10402 {
10403   /* We only start interactive search if we have focus or the columns
10404    * have focus.  If one of our children have focus, we don't want to
10405    * start the search.
10406    */
10407   GList *list;
10408   gboolean found_focus = FALSE;
10409   GtkWidgetClass *entry_parent_class;
10410   
10411   if (!tree_view->priv->enable_search && !keybinding)
10412     return FALSE;
10413
10414   if (tree_view->priv->search_custom_entry_set)
10415     return FALSE;
10416
10417   if (tree_view->priv->search_window != NULL &&
10418       gtk_widget_get_visible (tree_view->priv->search_window))
10419     return TRUE;
10420
10421   for (list = tree_view->priv->columns; list; list = list->next)
10422     {
10423       GtkTreeViewColumn *column;
10424
10425       column = list->data;
10426       if (! column->visible)
10427         continue;
10428
10429       if (gtk_widget_has_focus (column->button))
10430         {
10431           found_focus = TRUE;
10432           break;
10433         }
10434     }
10435   
10436   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10437     found_focus = TRUE;
10438
10439   if (!found_focus)
10440     return FALSE;
10441
10442   if (tree_view->priv->search_column < 0)
10443     return FALSE;
10444
10445   gtk_tree_view_ensure_interactive_directory (tree_view);
10446
10447   if (keybinding)
10448     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10449
10450   /* done, show it */
10451   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10452   gtk_widget_show (tree_view->priv->search_window);
10453   if (tree_view->priv->search_entry_changed_id == 0)
10454     {
10455       tree_view->priv->search_entry_changed_id =
10456         g_signal_connect (tree_view->priv->search_entry, "changed",
10457                           G_CALLBACK (gtk_tree_view_search_init),
10458                           tree_view);
10459     }
10460
10461   tree_view->priv->typeselect_flush_timeout =
10462     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10463                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10464                    tree_view);
10465
10466   /* Grab focus will select all the text.  We don't want that to happen, so we
10467    * call the parent instance and bypass the selection change.  This is probably
10468    * really non-kosher. */
10469   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10470   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10471
10472   /* send focus-in event */
10473   send_focus_change (tree_view->priv->search_entry, device, TRUE);
10474
10475   /* search first matching iter */
10476   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10477
10478   return TRUE;
10479 }
10480
10481 static gboolean
10482 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10483 {
10484   return gtk_tree_view_real_start_interactive_search (tree_view,
10485                                                       gtk_get_current_event_device (),
10486                                                       TRUE);
10487 }
10488
10489 /* this function returns the new width of the column being resized given
10490  * the column and x position of the cursor; the x cursor position is passed
10491  * in as a pointer and automagicly corrected if it's beyond min/max limits
10492  */
10493 static gint
10494 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10495                                 gint       i,
10496                                 gint      *x)
10497 {
10498   GtkAllocation allocation;
10499   GtkTreeViewColumn *column;
10500   GtkRequisition button_req;
10501   gint width;
10502   gboolean rtl;
10503
10504   /* first translate the x position from widget->window
10505    * to clist->clist_window
10506    */
10507   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10508   column = g_list_nth (tree_view->priv->columns, i)->data;
10509   gtk_widget_get_allocation (column->button, &allocation);
10510   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
10511
10512   /* Clamp down the value */
10513   if (column->min_width == -1)
10514     {
10515       gtk_widget_get_preferred_size (column->button, &button_req, NULL);
10516       width = MAX (button_req.width, width);
10517     }
10518   else
10519     width = MAX (column->min_width,
10520                  width);
10521   if (column->max_width != -1)
10522     width = MIN (width, column->max_width);
10523
10524   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
10525
10526   return width;
10527 }
10528
10529
10530 /* FIXME this adjust_allocation is a big cut-and-paste from
10531  * GtkCList, needs to be some "official" way to do this
10532  * factored out.
10533  */
10534 typedef struct
10535 {
10536   GdkWindow *window;
10537   int dx;
10538   int dy;
10539 } ScrollData;
10540
10541 /* The window to which widget->window is relative */
10542 #define ALLOCATION_WINDOW(widget)               \
10543    (!gtk_widget_get_has_window (widget) ?                   \
10544     gtk_widget_get_window (widget) :                        \
10545     gdk_window_get_parent (gtk_widget_get_window (widget)))
10546
10547 static void
10548 adjust_allocation_recurse (GtkWidget *widget,
10549                            gpointer   data)
10550 {
10551   GtkAllocation allocation;
10552   ScrollData *scroll_data = data;
10553
10554   /* Need to really size allocate instead of just poking
10555    * into widget->allocation if the widget is not realized.
10556    * FIXME someone figure out why this was.
10557    */
10558   gtk_widget_get_allocation (widget, &allocation);
10559   if (!gtk_widget_get_realized (widget))
10560     {
10561       if (gtk_widget_get_visible (widget))
10562         {
10563           GdkRectangle tmp_rectangle = allocation;
10564           tmp_rectangle.x += scroll_data->dx;
10565           tmp_rectangle.y += scroll_data->dy;
10566           
10567           gtk_widget_size_allocate (widget, &tmp_rectangle);
10568         }
10569     }
10570   else
10571     {
10572       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10573         {
10574           allocation.x += scroll_data->dx;
10575           allocation.y += scroll_data->dy;
10576           gtk_widget_set_allocation (widget, &allocation);
10577
10578           if (GTK_IS_CONTAINER (widget))
10579             gtk_container_forall (GTK_CONTAINER (widget),
10580                                   adjust_allocation_recurse,
10581                                   data);
10582         }
10583     }
10584 }
10585
10586 static void
10587 adjust_allocation (GtkWidget *widget,
10588                    int        dx,
10589                    int        dy)
10590 {
10591   ScrollData scroll_data;
10592
10593   if (gtk_widget_get_realized (widget))
10594     scroll_data.window = ALLOCATION_WINDOW (widget);
10595   else
10596     scroll_data.window = NULL;
10597     
10598   scroll_data.dx = dx;
10599   scroll_data.dy = dy;
10600   
10601   adjust_allocation_recurse (widget, &scroll_data);
10602 }
10603
10604 /* Callbacks */
10605 static void
10606 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10607                                   GtkTreeView   *tree_view)
10608 {
10609   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10610     {
10611       gint dy;
10612         
10613       gdk_window_move (tree_view->priv->bin_window,
10614                        - tree_view->priv->hadjustment->value,
10615                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10616       gdk_window_move (tree_view->priv->header_window,
10617                        - tree_view->priv->hadjustment->value,
10618                        0);
10619       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10620       if (dy)
10621         {
10622           update_prelight (tree_view,
10623                            tree_view->priv->event_last_x,
10624                            tree_view->priv->event_last_y - dy);
10625
10626           if (tree_view->priv->edited_column &&
10627               GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10628             {
10629               GList *list;
10630               GtkWidget *widget;
10631               GtkTreeViewChild *child = NULL;
10632
10633               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10634               adjust_allocation (widget, 0, dy); 
10635               
10636               for (list = tree_view->priv->children; list; list = list->next)
10637                 {
10638                   child = (GtkTreeViewChild *)list->data;
10639                   if (child->widget == widget)
10640                     {
10641                       child->y += dy;
10642                       break;
10643                     }
10644                 }
10645             }
10646         }
10647       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10648
10649       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10650         {
10651           /* update our dy and top_row */
10652           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10653
10654           if (!tree_view->priv->in_top_row_to_dy)
10655             gtk_tree_view_dy_to_top_row (tree_view);
10656         }
10657
10658       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10659       gtk_tree_view_bin_process_updates (tree_view);
10660     }
10661 }
10662
10663 \f
10664
10665 /* Public methods
10666  */
10667
10668 /**
10669  * gtk_tree_view_new:
10670  *
10671  * Creates a new #GtkTreeView widget.
10672  *
10673  * Return value: A newly created #GtkTreeView widget.
10674  **/
10675 GtkWidget *
10676 gtk_tree_view_new (void)
10677 {
10678   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10679 }
10680
10681 /**
10682  * gtk_tree_view_new_with_model:
10683  * @model: the model.
10684  *
10685  * Creates a new #GtkTreeView widget with the model initialized to @model.
10686  *
10687  * Return value: A newly created #GtkTreeView widget.
10688  **/
10689 GtkWidget *
10690 gtk_tree_view_new_with_model (GtkTreeModel *model)
10691 {
10692   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10693 }
10694
10695 /* Public Accessors
10696  */
10697
10698 /**
10699  * gtk_tree_view_get_model:
10700  * @tree_view: a #GtkTreeView
10701  *
10702  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10703  * model is unset.
10704  *
10705  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
10706  **/
10707 GtkTreeModel *
10708 gtk_tree_view_get_model (GtkTreeView *tree_view)
10709 {
10710   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10711
10712   return tree_view->priv->model;
10713 }
10714
10715 /**
10716  * gtk_tree_view_set_model:
10717  * @tree_view: A #GtkTreeNode.
10718  * @model: (allow-none): The model.
10719  *
10720  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10721  * set, it will remove it before setting the new model.  If @model is %NULL,
10722  * then it will unset the old model.
10723  **/
10724 void
10725 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10726                          GtkTreeModel *model)
10727 {
10728   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10729   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10730
10731   if (model == tree_view->priv->model)
10732     return;
10733
10734   if (tree_view->priv->scroll_to_path)
10735     {
10736       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10737       tree_view->priv->scroll_to_path = NULL;
10738     }
10739
10740   if (tree_view->priv->model)
10741     {
10742       GList *tmplist = tree_view->priv->columns;
10743
10744       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10745       gtk_tree_view_stop_editing (tree_view, TRUE);
10746
10747       remove_expand_collapse_timeout (tree_view);
10748
10749       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10750                                             gtk_tree_view_row_changed,
10751                                             tree_view);
10752       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10753                                             gtk_tree_view_row_inserted,
10754                                             tree_view);
10755       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10756                                             gtk_tree_view_row_has_child_toggled,
10757                                             tree_view);
10758       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10759                                             gtk_tree_view_row_deleted,
10760                                             tree_view);
10761       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10762                                             gtk_tree_view_rows_reordered,
10763                                             tree_view);
10764
10765       for (; tmplist; tmplist = tmplist->next)
10766         _gtk_tree_view_column_unset_model (tmplist->data,
10767                                            tree_view->priv->model);
10768
10769       if (tree_view->priv->tree)
10770         gtk_tree_view_free_rbtree (tree_view);
10771
10772       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10773       tree_view->priv->drag_dest_row = NULL;
10774       gtk_tree_row_reference_free (tree_view->priv->cursor);
10775       tree_view->priv->cursor = NULL;
10776       gtk_tree_row_reference_free (tree_view->priv->anchor);
10777       tree_view->priv->anchor = NULL;
10778       gtk_tree_row_reference_free (tree_view->priv->top_row);
10779       tree_view->priv->top_row = NULL;
10780       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10781       tree_view->priv->scroll_to_path = NULL;
10782
10783       tree_view->priv->scroll_to_column = NULL;
10784
10785       g_object_unref (tree_view->priv->model);
10786
10787       tree_view->priv->search_column = -1;
10788       tree_view->priv->fixed_height_check = 0;
10789       tree_view->priv->fixed_height = -1;
10790       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10791       tree_view->priv->last_button_x = -1;
10792       tree_view->priv->last_button_y = -1;
10793     }
10794
10795   tree_view->priv->model = model;
10796
10797   if (tree_view->priv->model)
10798     {
10799       gint i;
10800       GtkTreePath *path;
10801       GtkTreeIter iter;
10802       GtkTreeModelFlags flags;
10803
10804       if (tree_view->priv->search_column == -1)
10805         {
10806           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10807             {
10808               GType type = gtk_tree_model_get_column_type (model, i);
10809
10810               if (g_value_type_transformable (type, G_TYPE_STRING))
10811                 {
10812                   tree_view->priv->search_column = i;
10813                   break;
10814                 }
10815             }
10816         }
10817
10818       g_object_ref (tree_view->priv->model);
10819       g_signal_connect (tree_view->priv->model,
10820                         "row-changed",
10821                         G_CALLBACK (gtk_tree_view_row_changed),
10822                         tree_view);
10823       g_signal_connect (tree_view->priv->model,
10824                         "row-inserted",
10825                         G_CALLBACK (gtk_tree_view_row_inserted),
10826                         tree_view);
10827       g_signal_connect (tree_view->priv->model,
10828                         "row-has-child-toggled",
10829                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10830                         tree_view);
10831       g_signal_connect (tree_view->priv->model,
10832                         "row-deleted",
10833                         G_CALLBACK (gtk_tree_view_row_deleted),
10834                         tree_view);
10835       g_signal_connect (tree_view->priv->model,
10836                         "rows-reordered",
10837                         G_CALLBACK (gtk_tree_view_rows_reordered),
10838                         tree_view);
10839
10840       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10841       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10842         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10843       else
10844         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10845
10846       path = gtk_tree_path_new_first ();
10847       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10848         {
10849           tree_view->priv->tree = _gtk_rbtree_new ();
10850           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10851         }
10852       gtk_tree_path_free (path);
10853
10854       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10855       install_presize_handler (tree_view);
10856     }
10857
10858   g_object_notify (G_OBJECT (tree_view), "model");
10859
10860   if (tree_view->priv->selection)
10861   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10862
10863   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10864     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10865 }
10866
10867 /**
10868  * gtk_tree_view_get_selection:
10869  * @tree_view: A #GtkTreeView.
10870  *
10871  * Gets the #GtkTreeSelection associated with @tree_view.
10872  *
10873  * Return value: (transfer none): A #GtkTreeSelection object.
10874  **/
10875 GtkTreeSelection *
10876 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10877 {
10878   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10879
10880   return tree_view->priv->selection;
10881 }
10882
10883 /**
10884  * gtk_tree_view_get_hadjustment:
10885  * @tree_view: A #GtkTreeView
10886  *
10887  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10888  *
10889  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
10890  *     if none is currently being used.
10891  *
10892  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
10893  **/
10894 GtkAdjustment *
10895 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10896 {
10897   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10898
10899   return tree_view->priv->hadjustment;
10900 }
10901
10902 /**
10903  * gtk_tree_view_set_hadjustment:
10904  * @tree_view: A #GtkTreeView
10905  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10906  *
10907  * Sets the #GtkAdjustment for the current horizontal aspect.
10908  *
10909  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
10910  **/
10911 void
10912 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10913                                GtkAdjustment *adjustment)
10914 {
10915   GtkTreeViewPrivate *priv = tree_view->priv;
10916
10917   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10918   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
10919
10920   if (adjustment && priv->hadjustment == adjustment)
10921     return;
10922
10923   if (priv->hadjustment != NULL)
10924     {
10925       g_signal_handlers_disconnect_by_func (priv->hadjustment,
10926                                             gtk_tree_view_adjustment_changed,
10927                                             tree_view);
10928       g_object_unref (priv->hadjustment);
10929     }
10930
10931   if (adjustment == NULL)
10932     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
10933                                      0.0, 0.0, 0.0);
10934
10935   g_signal_connect (adjustment, "value-changed",
10936                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
10937   priv->hadjustment = g_object_ref_sink (adjustment);
10938   /* FIXME: Adjustment should probably be populated here with fresh values, but
10939    * internal details are too complicated for me to decipher right now.
10940    */
10941   gtk_tree_view_adjustment_changed (NULL, tree_view);
10942
10943   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10944 }
10945
10946 /**
10947  * gtk_tree_view_get_vadjustment:
10948  * @tree_view: A #GtkTreeView
10949  *
10950  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10951  *
10952  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
10953  *     if none is currently being used.
10954  *
10955  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
10956  **/
10957 GtkAdjustment *
10958 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10959 {
10960   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10961
10962   return tree_view->priv->vadjustment;
10963 }
10964
10965 /**
10966  * gtk_tree_view_set_vadjustment:
10967  * @tree_view: A #GtkTreeView
10968  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10969  *
10970  * Sets the #GtkAdjustment for the current vertical aspect.
10971  *
10972  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
10973  **/
10974 void
10975 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10976                                GtkAdjustment *adjustment)
10977 {
10978   GtkTreeViewPrivate *priv = tree_view->priv;
10979
10980   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10981   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
10982
10983   if (adjustment && priv->vadjustment == adjustment)
10984     return;
10985
10986   if (priv->vadjustment != NULL)
10987     {
10988       g_signal_handlers_disconnect_by_func (priv->vadjustment,
10989                                             gtk_tree_view_adjustment_changed,
10990                                             tree_view);
10991       g_object_unref (priv->vadjustment);
10992     }
10993
10994   if (adjustment == NULL)
10995     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
10996                                      0.0, 0.0, 0.0);
10997
10998   g_signal_connect (adjustment, "value-changed",
10999                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11000   priv->vadjustment = g_object_ref_sink (adjustment);
11001   /* FIXME: Adjustment should probably be populated here with fresh values, but
11002    * internal details are too complicated for me to decipher right now.
11003    */
11004   gtk_tree_view_adjustment_changed (NULL, tree_view);
11005   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11006 }
11007
11008 /* Column and header operations */
11009
11010 /**
11011  * gtk_tree_view_get_headers_visible:
11012  * @tree_view: A #GtkTreeView.
11013  *
11014  * Returns %TRUE if the headers on the @tree_view are visible.
11015  *
11016  * Return value: Whether the headers are visible or not.
11017  **/
11018 gboolean
11019 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11020 {
11021   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11022
11023   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11024 }
11025
11026 /**
11027  * gtk_tree_view_set_headers_visible:
11028  * @tree_view: A #GtkTreeView.
11029  * @headers_visible: %TRUE if the headers are visible
11030  *
11031  * Sets the visibility state of the headers.
11032  **/
11033 void
11034 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11035                                    gboolean     headers_visible)
11036 {
11037   gint x, y;
11038   GList *list;
11039   GtkTreeViewColumn *column;
11040   GtkAllocation allocation;
11041
11042   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11043
11044   headers_visible = !! headers_visible;
11045
11046   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
11047     return;
11048
11049   if (headers_visible)
11050     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11051   else
11052     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11053
11054   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11055     {
11056       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11057       if (headers_visible)
11058         {
11059           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11060           gdk_window_move_resize (tree_view->priv->bin_window,
11061                                   x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view),
11062                                   tree_view->priv->width, allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
11063
11064           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11065             gtk_tree_view_map_buttons (tree_view);
11066         }
11067       else
11068         {
11069           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11070
11071           for (list = tree_view->priv->columns; list; list = list->next)
11072             {
11073               column = list->data;
11074               gtk_widget_unmap (column->button);
11075             }
11076           gdk_window_hide (tree_view->priv->header_window);
11077         }
11078     }
11079
11080   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11081   tree_view->priv->vadjustment->page_size = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11082   tree_view->priv->vadjustment->page_increment = (allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11083   tree_view->priv->vadjustment->lower = 0;
11084   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11085   gtk_adjustment_changed (tree_view->priv->vadjustment);
11086
11087   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11088
11089   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11090 }
11091
11092 /**
11093  * gtk_tree_view_columns_autosize:
11094  * @tree_view: A #GtkTreeView.
11095  *
11096  * Resizes all columns to their optimal width. Only works after the
11097  * treeview has been realized.
11098  **/
11099 void
11100 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11101 {
11102   gboolean dirty = FALSE;
11103   GList *list;
11104   GtkTreeViewColumn *column;
11105
11106   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11107
11108   for (list = tree_view->priv->columns; list; list = list->next)
11109     {
11110       column = list->data;
11111       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11112         continue;
11113       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11114       dirty = TRUE;
11115     }
11116
11117   if (dirty)
11118     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11119 }
11120
11121 /**
11122  * gtk_tree_view_set_headers_clickable:
11123  * @tree_view: A #GtkTreeView.
11124  * @setting: %TRUE if the columns are clickable.
11125  *
11126  * Allow the column title buttons to be clicked.
11127  **/
11128 void
11129 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11130                                      gboolean   setting)
11131 {
11132   GList *list;
11133
11134   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11135
11136   for (list = tree_view->priv->columns; list; list = list->next)
11137     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11138
11139   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11140 }
11141
11142
11143 /**
11144  * gtk_tree_view_get_headers_clickable:
11145  * @tree_view: A #GtkTreeView.
11146  *
11147  * Returns whether all header columns are clickable.
11148  *
11149  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11150  *
11151  * Since: 2.10
11152  **/
11153 gboolean 
11154 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11155 {
11156   GList *list;
11157   
11158   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11159
11160   for (list = tree_view->priv->columns; list; list = list->next)
11161     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11162       return FALSE;
11163
11164   return TRUE;
11165 }
11166
11167 /**
11168  * gtk_tree_view_set_rules_hint
11169  * @tree_view: a #GtkTreeView
11170  * @setting: %TRUE if the tree requires reading across rows
11171  *
11172  * This function tells GTK+ that the user interface for your
11173  * application requires users to read across tree rows and associate
11174  * cells with one another. By default, GTK+ will then render the tree
11175  * with alternating row colors. Do <emphasis>not</emphasis> use it
11176  * just because you prefer the appearance of the ruled tree; that's a
11177  * question for the theme. Some themes will draw tree rows in
11178  * alternating colors even when rules are turned off, and users who
11179  * prefer that appearance all the time can choose those themes. You
11180  * should call this function only as a <emphasis>semantic</emphasis>
11181  * hint to the theme engine that your tree makes alternating colors
11182  * useful from a functional standpoint (since it has lots of columns,
11183  * generally).
11184  *
11185  **/
11186 void
11187 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11188                               gboolean      setting)
11189 {
11190   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11191
11192   setting = setting != FALSE;
11193
11194   if (tree_view->priv->has_rules != setting)
11195     {
11196       tree_view->priv->has_rules = setting;
11197       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11198     }
11199
11200   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11201 }
11202
11203 /**
11204  * gtk_tree_view_get_rules_hint
11205  * @tree_view: a #GtkTreeView
11206  *
11207  * Gets the setting set by gtk_tree_view_set_rules_hint().
11208  *
11209  * Return value: %TRUE if rules are useful for the user of this tree
11210  **/
11211 gboolean
11212 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11213 {
11214   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11215
11216   return tree_view->priv->has_rules;
11217 }
11218
11219 /* Public Column functions
11220  */
11221
11222 /**
11223  * gtk_tree_view_append_column:
11224  * @tree_view: A #GtkTreeView.
11225  * @column: The #GtkTreeViewColumn to add.
11226  *
11227  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11228  * mode enabled, then @column must have its "sizing" property set to be
11229  * GTK_TREE_VIEW_COLUMN_FIXED.
11230  *
11231  * Return value: The number of columns in @tree_view after appending.
11232  **/
11233 gint
11234 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11235                              GtkTreeViewColumn *column)
11236 {
11237   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11238   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11239   g_return_val_if_fail (column->tree_view == NULL, -1);
11240
11241   return gtk_tree_view_insert_column (tree_view, column, -1);
11242 }
11243
11244
11245 /**
11246  * gtk_tree_view_remove_column:
11247  * @tree_view: A #GtkTreeView.
11248  * @column: The #GtkTreeViewColumn to remove.
11249  *
11250  * Removes @column from @tree_view.
11251  *
11252  * Return value: The number of columns in @tree_view after removing.
11253  **/
11254 gint
11255 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11256                              GtkTreeViewColumn *column)
11257 {
11258   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11259   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11260   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11261
11262   if (tree_view->priv->focus_column == column)
11263     tree_view->priv->focus_column = NULL;
11264
11265   if (tree_view->priv->edited_column == column)
11266     {
11267       gtk_tree_view_stop_editing (tree_view, TRUE);
11268
11269       /* no need to, but just to be sure ... */
11270       tree_view->priv->edited_column = NULL;
11271     }
11272
11273   if (tree_view->priv->expander_column == column)
11274     tree_view->priv->expander_column = NULL;
11275
11276   g_signal_handlers_disconnect_by_func (column,
11277                                         G_CALLBACK (column_sizing_notify),
11278                                         tree_view);
11279
11280   _gtk_tree_view_column_unset_tree_view (column);
11281
11282   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11283   tree_view->priv->n_columns--;
11284
11285   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11286     {
11287       GList *list;
11288
11289       _gtk_tree_view_column_unrealize_button (column);
11290       for (list = tree_view->priv->columns; list; list = list->next)
11291         {
11292           GtkTreeViewColumn *tmp_column;
11293
11294           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11295           if (tmp_column->visible)
11296             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11297         }
11298
11299       if (tree_view->priv->n_columns == 0 &&
11300           gtk_tree_view_get_headers_visible (tree_view))
11301         gdk_window_hide (tree_view->priv->header_window);
11302
11303       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11304     }
11305
11306   g_object_unref (column);
11307   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11308
11309   return tree_view->priv->n_columns;
11310 }
11311
11312 /**
11313  * gtk_tree_view_insert_column:
11314  * @tree_view: A #GtkTreeView.
11315  * @column: The #GtkTreeViewColumn to be inserted.
11316  * @position: The position to insert @column in.
11317  *
11318  * This inserts the @column into the @tree_view at @position.  If @position is
11319  * -1, then the column is inserted at the end. If @tree_view has
11320  * "fixed_height" mode enabled, then @column must have its "sizing" property
11321  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11322  *
11323  * Return value: The number of columns in @tree_view after insertion.
11324  **/
11325 gint
11326 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11327                              GtkTreeViewColumn *column,
11328                              gint               position)
11329 {
11330   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11331   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11332   g_return_val_if_fail (column->tree_view == NULL, -1);
11333
11334   if (tree_view->priv->fixed_height_mode)
11335     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11336                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11337
11338   g_object_ref_sink (column);
11339
11340   if (tree_view->priv->n_columns == 0 &&
11341       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11342       gtk_tree_view_get_headers_visible (tree_view))
11343     {
11344       gdk_window_show (tree_view->priv->header_window);
11345     }
11346
11347   g_signal_connect (column, "notify::sizing",
11348                     G_CALLBACK (column_sizing_notify), tree_view);
11349
11350   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11351                                             column, position);
11352   tree_view->priv->n_columns++;
11353
11354   _gtk_tree_view_column_set_tree_view (column, tree_view);
11355
11356   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11357     {
11358       GList *list;
11359
11360       _gtk_tree_view_column_realize_button (column);
11361
11362       for (list = tree_view->priv->columns; list; list = list->next)
11363         {
11364           column = GTK_TREE_VIEW_COLUMN (list->data);
11365           if (column->visible)
11366             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11367         }
11368       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11369     }
11370
11371   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11372
11373   return tree_view->priv->n_columns;
11374 }
11375
11376 /**
11377  * gtk_tree_view_insert_column_with_attributes:
11378  * @tree_view: A #GtkTreeView
11379  * @position: The position to insert the new column in.
11380  * @title: The title to set the header to.
11381  * @cell: The #GtkCellRenderer.
11382  * @Varargs: A %NULL-terminated list of attributes.
11383  *
11384  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11385  * @position.  If @position is -1, then the newly created column is inserted at
11386  * the end.  The column is initialized with the attributes given. If @tree_view
11387  * has "fixed_height" mode enabled, then the new column will have its sizing
11388  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11389  *
11390  * Return value: The number of columns in @tree_view after insertion.
11391  **/
11392 gint
11393 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11394                                              gint             position,
11395                                              const gchar     *title,
11396                                              GtkCellRenderer *cell,
11397                                              ...)
11398 {
11399   GtkTreeViewColumn *column;
11400   gchar *attribute;
11401   va_list args;
11402   gint column_id;
11403
11404   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11405
11406   column = gtk_tree_view_column_new ();
11407   if (tree_view->priv->fixed_height_mode)
11408     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11409
11410   gtk_tree_view_column_set_title (column, title);
11411   gtk_tree_view_column_pack_start (column, cell, TRUE);
11412
11413   va_start (args, cell);
11414
11415   attribute = va_arg (args, gchar *);
11416
11417   while (attribute != NULL)
11418     {
11419       column_id = va_arg (args, gint);
11420       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11421       attribute = va_arg (args, gchar *);
11422     }
11423
11424   va_end (args);
11425
11426   gtk_tree_view_insert_column (tree_view, column, position);
11427
11428   return tree_view->priv->n_columns;
11429 }
11430
11431 /**
11432  * gtk_tree_view_insert_column_with_data_func:
11433  * @tree_view: a #GtkTreeView
11434  * @position: Position to insert, -1 for append
11435  * @title: column title
11436  * @cell: cell renderer for column
11437  * @func: function to set attributes of cell renderer
11438  * @data: data for @func
11439  * @dnotify: destroy notifier for @data
11440  *
11441  * Convenience function that inserts a new column into the #GtkTreeView
11442  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11443  * attributes (normally using data from the model). See also
11444  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11445  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11446  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11447  *
11448  * Return value: number of columns in the tree view post-insert
11449  **/
11450 gint
11451 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11452                                              gint                       position,
11453                                              const gchar               *title,
11454                                              GtkCellRenderer           *cell,
11455                                              GtkTreeCellDataFunc        func,
11456                                              gpointer                   data,
11457                                              GDestroyNotify             dnotify)
11458 {
11459   GtkTreeViewColumn *column;
11460
11461   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11462
11463   column = gtk_tree_view_column_new ();
11464   if (tree_view->priv->fixed_height_mode)
11465     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11466
11467   gtk_tree_view_column_set_title (column, title);
11468   gtk_tree_view_column_pack_start (column, cell, TRUE);
11469   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11470
11471   gtk_tree_view_insert_column (tree_view, column, position);
11472
11473   return tree_view->priv->n_columns;
11474 }
11475
11476 /**
11477  * gtk_tree_view_get_column:
11478  * @tree_view: A #GtkTreeView.
11479  * @n: The position of the column, counting from 0.
11480  *
11481  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11482  *
11483  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
11484  *     position is outside the range of columns.
11485  **/
11486 GtkTreeViewColumn *
11487 gtk_tree_view_get_column (GtkTreeView *tree_view,
11488                           gint         n)
11489 {
11490   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11491
11492   if (n < 0 || n >= tree_view->priv->n_columns)
11493     return NULL;
11494
11495   if (tree_view->priv->columns == NULL)
11496     return NULL;
11497
11498   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11499 }
11500
11501 /**
11502  * gtk_tree_view_get_columns:
11503  * @tree_view: A #GtkTreeView
11504  *
11505  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11506  * The returned list must be freed with g_list_free ().
11507  *
11508  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11509  **/
11510 GList *
11511 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11512 {
11513   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11514
11515   return g_list_copy (tree_view->priv->columns);
11516 }
11517
11518 /**
11519  * gtk_tree_view_move_column_after:
11520  * @tree_view: A #GtkTreeView
11521  * @column: The #GtkTreeViewColumn to be moved.
11522  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11523  *
11524  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11525  * @column is placed in the first position.
11526  **/
11527 void
11528 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11529                                  GtkTreeViewColumn *column,
11530                                  GtkTreeViewColumn *base_column)
11531 {
11532   GList *column_list_el, *base_el = NULL;
11533
11534   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11535
11536   column_list_el = g_list_find (tree_view->priv->columns, column);
11537   g_return_if_fail (column_list_el != NULL);
11538
11539   if (base_column)
11540     {
11541       base_el = g_list_find (tree_view->priv->columns, base_column);
11542       g_return_if_fail (base_el != NULL);
11543     }
11544
11545   if (column_list_el->prev == base_el)
11546     return;
11547
11548   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11549   if (base_el == NULL)
11550     {
11551       column_list_el->prev = NULL;
11552       column_list_el->next = tree_view->priv->columns;
11553       if (column_list_el->next)
11554         column_list_el->next->prev = column_list_el;
11555       tree_view->priv->columns = column_list_el;
11556     }
11557   else
11558     {
11559       column_list_el->prev = base_el;
11560       column_list_el->next = base_el->next;
11561       if (column_list_el->next)
11562         column_list_el->next->prev = column_list_el;
11563       base_el->next = column_list_el;
11564     }
11565
11566   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11567     {
11568       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11569       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11570     }
11571
11572   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11573 }
11574
11575 /**
11576  * gtk_tree_view_set_expander_column:
11577  * @tree_view: A #GtkTreeView
11578  * @column: %NULL, or the column to draw the expander arrow at.
11579  *
11580  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11581  * If @column is %NULL, then the expander arrow is always at the first 
11582  * visible column.
11583  *
11584  * If you do not want expander arrow to appear in your tree, set the 
11585  * expander column to a hidden column.
11586  **/
11587 void
11588 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11589                                    GtkTreeViewColumn *column)
11590 {
11591   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11592   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11593
11594   if (tree_view->priv->expander_column != column)
11595     {
11596       GList *list;
11597
11598       if (column)
11599         {
11600           /* Confirm that column is in tree_view */
11601           for (list = tree_view->priv->columns; list; list = list->next)
11602             if (list->data == column)
11603               break;
11604           g_return_if_fail (list != NULL);
11605         }
11606
11607       tree_view->priv->expander_column = column;
11608       g_object_notify (G_OBJECT (tree_view), "expander-column");
11609     }
11610 }
11611
11612 /**
11613  * gtk_tree_view_get_expander_column:
11614  * @tree_view: A #GtkTreeView
11615  *
11616  * Returns the column that is the current expander column.
11617  * This column has the expander arrow drawn next to it.
11618  *
11619  * Return value: (transfer none): The expander column.
11620  **/
11621 GtkTreeViewColumn *
11622 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11623 {
11624   GList *list;
11625
11626   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11627
11628   for (list = tree_view->priv->columns; list; list = list->next)
11629     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11630       return (GtkTreeViewColumn *) list->data;
11631   return NULL;
11632 }
11633
11634
11635 /**
11636  * gtk_tree_view_set_column_drag_function:
11637  * @tree_view: A #GtkTreeView.
11638  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
11639  * @user_data: (allow-none): User data to be passed to @func, or %NULL
11640  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
11641  *
11642  * Sets a user function for determining where a column may be dropped when
11643  * dragged.  This function is called on every column pair in turn at the
11644  * beginning of a column drag to determine where a drop can take place.  The
11645  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11646  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11647  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11648  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11649  * @tree_view reverts to the default behavior of allowing all columns to be
11650  * dropped everywhere.
11651  **/
11652 void
11653 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11654                                         GtkTreeViewColumnDropFunc  func,
11655                                         gpointer                   user_data,
11656                                         GDestroyNotify             destroy)
11657 {
11658   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11659
11660   if (tree_view->priv->column_drop_func_data_destroy)
11661     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11662
11663   tree_view->priv->column_drop_func = func;
11664   tree_view->priv->column_drop_func_data = user_data;
11665   tree_view->priv->column_drop_func_data_destroy = destroy;
11666 }
11667
11668 /**
11669  * gtk_tree_view_scroll_to_point:
11670  * @tree_view: a #GtkTreeView
11671  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11672  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11673  *
11674  * Scrolls the tree view such that the top-left corner of the visible
11675  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11676  * in tree coordinates.  The @tree_view must be realized before
11677  * this function is called.  If it isn't, you probably want to be
11678  * using gtk_tree_view_scroll_to_cell().
11679  *
11680  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11681  **/
11682 void
11683 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11684                                gint         tree_x,
11685                                gint         tree_y)
11686 {
11687   GtkAdjustment *hadj;
11688   GtkAdjustment *vadj;
11689
11690   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11691   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
11692
11693   hadj = tree_view->priv->hadjustment;
11694   vadj = tree_view->priv->vadjustment;
11695
11696   if (tree_x != -1)
11697     gtk_adjustment_set_value (hadj, tree_x);
11698   if (tree_y != -1)
11699     gtk_adjustment_set_value (vadj, tree_y);
11700 }
11701
11702 /**
11703  * gtk_tree_view_scroll_to_cell:
11704  * @tree_view: A #GtkTreeView.
11705  * @path: (allow-none): The path of the row to move to, or %NULL.
11706  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11707  * @use_align: whether to use alignment arguments, or %FALSE.
11708  * @row_align: The vertical alignment of the row specified by @path.
11709  * @col_align: The horizontal alignment of the column specified by @column.
11710  *
11711  * Moves the alignments of @tree_view to the position specified by @column and
11712  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11713  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11714  * or @path need to be non-%NULL.  @row_align determines where the row is
11715  * placed, and @col_align determines where @column is placed.  Both are expected
11716  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11717  * right/bottom alignment, 0.5 means center.
11718  *
11719  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11720  * tree does the minimum amount of work to scroll the cell onto the screen.
11721  * This means that the cell will be scrolled to the edge closest to its current
11722  * position.  If the cell is currently visible on the screen, nothing is done.
11723  *
11724  * This function only works if the model is set, and @path is a valid row on the
11725  * model.  If the model changes before the @tree_view is realized, the centered
11726  * path will be modified to reflect this change.
11727  **/
11728 void
11729 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11730                               GtkTreePath       *path,
11731                               GtkTreeViewColumn *column,
11732                               gboolean           use_align,
11733                               gfloat             row_align,
11734                               gfloat             col_align)
11735 {
11736   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11737   g_return_if_fail (tree_view->priv->model != NULL);
11738   g_return_if_fail (tree_view->priv->tree != NULL);
11739   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11740   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11741   g_return_if_fail (path != NULL || column != NULL);
11742
11743 #if 0
11744   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11745            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11746 #endif
11747   row_align = CLAMP (row_align, 0.0, 1.0);
11748   col_align = CLAMP (col_align, 0.0, 1.0);
11749
11750
11751   /* Note: Despite the benefits that come from having one code path for the
11752    * scrolling code, we short-circuit validate_visible_area's immplementation as
11753    * it is much slower than just going to the point.
11754    */
11755   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
11756       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
11757       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
11758       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11759     {
11760       if (tree_view->priv->scroll_to_path)
11761         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11762
11763       tree_view->priv->scroll_to_path = NULL;
11764       tree_view->priv->scroll_to_column = NULL;
11765
11766       if (path)
11767         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11768       if (column)
11769         tree_view->priv->scroll_to_column = column;
11770       tree_view->priv->scroll_to_use_align = use_align;
11771       tree_view->priv->scroll_to_row_align = row_align;
11772       tree_view->priv->scroll_to_col_align = col_align;
11773
11774       install_presize_handler (tree_view);
11775     }
11776   else
11777     {
11778       GdkRectangle cell_rect;
11779       GdkRectangle vis_rect;
11780       gint dest_x, dest_y;
11781
11782       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11783       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11784
11785       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11786
11787       dest_x = vis_rect.x;
11788       dest_y = vis_rect.y;
11789
11790       if (column)
11791         {
11792           if (use_align)
11793             {
11794               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11795             }
11796           else
11797             {
11798               if (cell_rect.x < vis_rect.x)
11799                 dest_x = cell_rect.x;
11800               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11801                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11802             }
11803         }
11804
11805       if (path)
11806         {
11807           if (use_align)
11808             {
11809               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11810               dest_y = MAX (dest_y, 0);
11811             }
11812           else
11813             {
11814               if (cell_rect.y < vis_rect.y)
11815                 dest_y = cell_rect.y;
11816               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11817                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11818             }
11819         }
11820
11821       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11822     }
11823 }
11824
11825 /**
11826  * gtk_tree_view_row_activated:
11827  * @tree_view: A #GtkTreeView
11828  * @path: The #GtkTreePath to be activated.
11829  * @column: The #GtkTreeViewColumn to be activated.
11830  *
11831  * Activates the cell determined by @path and @column.
11832  **/
11833 void
11834 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11835                              GtkTreePath       *path,
11836                              GtkTreeViewColumn *column)
11837 {
11838   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11839
11840   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11841 }
11842
11843
11844 static void
11845 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11846                                           GtkRBNode *node,
11847                                           gpointer   data)
11848 {
11849   GtkTreeView *tree_view = data;
11850
11851   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11852       node->children)
11853     {
11854       GtkTreePath *path;
11855       GtkTreeIter iter;
11856
11857       path = _gtk_tree_view_find_path (tree_view, tree, node);
11858       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11859
11860       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11861
11862       gtk_tree_path_free (path);
11863     }
11864
11865   if (node->children)
11866     _gtk_rbtree_traverse (node->children,
11867                           node->children->root,
11868                           G_PRE_ORDER,
11869                           gtk_tree_view_expand_all_emission_helper,
11870                           tree_view);
11871 }
11872
11873 /**
11874  * gtk_tree_view_expand_all:
11875  * @tree_view: A #GtkTreeView.
11876  *
11877  * Recursively expands all nodes in the @tree_view.
11878  **/
11879 void
11880 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11881 {
11882   GtkTreePath *path;
11883   GtkRBTree *tree;
11884   GtkRBNode *node;
11885
11886   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11887
11888   if (tree_view->priv->tree == NULL)
11889     return;
11890
11891   path = gtk_tree_path_new_first ();
11892   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11893
11894   while (node)
11895     {
11896       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11897       node = _gtk_rbtree_next (tree, node);
11898       gtk_tree_path_next (path);
11899   }
11900
11901   gtk_tree_path_free (path);
11902 }
11903
11904 /* Timeout to animate the expander during expands and collapses */
11905 static gboolean
11906 expand_collapse_timeout (gpointer data)
11907 {
11908   return do_expand_collapse (data);
11909 }
11910
11911 static void
11912 add_expand_collapse_timeout (GtkTreeView *tree_view,
11913                              GtkRBTree   *tree,
11914                              GtkRBNode   *node,
11915                              gboolean     expand)
11916 {
11917   if (tree_view->priv->expand_collapse_timeout != 0)
11918     return;
11919
11920   tree_view->priv->expand_collapse_timeout =
11921       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11922   tree_view->priv->expanded_collapsed_tree = tree;
11923   tree_view->priv->expanded_collapsed_node = node;
11924
11925   if (expand)
11926     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11927   else
11928     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11929 }
11930
11931 static void
11932 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11933 {
11934   if (tree_view->priv->expand_collapse_timeout)
11935     {
11936       g_source_remove (tree_view->priv->expand_collapse_timeout);
11937       tree_view->priv->expand_collapse_timeout = 0;
11938     }
11939
11940   if (tree_view->priv->expanded_collapsed_node != NULL)
11941     {
11942       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11943       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11944
11945       tree_view->priv->expanded_collapsed_node = NULL;
11946     }
11947 }
11948
11949 static void
11950 cancel_arrow_animation (GtkTreeView *tree_view)
11951 {
11952   if (tree_view->priv->expand_collapse_timeout)
11953     {
11954       while (do_expand_collapse (tree_view));
11955
11956       remove_expand_collapse_timeout (tree_view);
11957     }
11958 }
11959
11960 static gboolean
11961 do_expand_collapse (GtkTreeView *tree_view)
11962 {
11963   GtkRBNode *node;
11964   GtkRBTree *tree;
11965   gboolean expanding;
11966   gboolean redraw;
11967
11968   redraw = FALSE;
11969   expanding = TRUE;
11970
11971   node = tree_view->priv->expanded_collapsed_node;
11972   tree = tree_view->priv->expanded_collapsed_tree;
11973
11974   if (node->children == NULL)
11975     expanding = FALSE;
11976
11977   if (expanding)
11978     {
11979       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11980         {
11981           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11982           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11983
11984           redraw = TRUE;
11985
11986         }
11987       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11988         {
11989           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11990
11991           redraw = TRUE;
11992         }
11993     }
11994   else
11995     {
11996       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11997         {
11998           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11999           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12000
12001           redraw = TRUE;
12002         }
12003       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
12004         {
12005           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12006
12007           redraw = TRUE;
12008
12009         }
12010     }
12011
12012   if (redraw)
12013     {
12014       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
12015
12016       return TRUE;
12017     }
12018
12019   return FALSE;
12020 }
12021
12022 /**
12023  * gtk_tree_view_collapse_all:
12024  * @tree_view: A #GtkTreeView.
12025  *
12026  * Recursively collapses all visible, expanded nodes in @tree_view.
12027  **/
12028 void
12029 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12030 {
12031   GtkRBTree *tree;
12032   GtkRBNode *node;
12033   GtkTreePath *path;
12034   gint *indices;
12035
12036   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12037
12038   if (tree_view->priv->tree == NULL)
12039     return;
12040
12041   path = gtk_tree_path_new ();
12042   gtk_tree_path_down (path);
12043   indices = gtk_tree_path_get_indices (path);
12044
12045   tree = tree_view->priv->tree;
12046   node = tree->root;
12047   while (node && node->left != tree->nil)
12048     node = node->left;
12049
12050   while (node)
12051     {
12052       if (node->children)
12053         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12054       indices[0]++;
12055       node = _gtk_rbtree_next (tree, node);
12056     }
12057
12058   gtk_tree_path_free (path);
12059 }
12060
12061 /**
12062  * gtk_tree_view_expand_to_path:
12063  * @tree_view: A #GtkTreeView.
12064  * @path: path to a row.
12065  *
12066  * Expands the row at @path. This will also expand all parent rows of
12067  * @path as necessary.
12068  *
12069  * Since: 2.2
12070  **/
12071 void
12072 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12073                               GtkTreePath *path)
12074 {
12075   gint i, depth;
12076   gint *indices;
12077   GtkTreePath *tmp;
12078
12079   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12080   g_return_if_fail (path != NULL);
12081
12082   depth = gtk_tree_path_get_depth (path);
12083   indices = gtk_tree_path_get_indices (path);
12084
12085   tmp = gtk_tree_path_new ();
12086   g_return_if_fail (tmp != NULL);
12087
12088   for (i = 0; i < depth; i++)
12089     {
12090       gtk_tree_path_append_index (tmp, indices[i]);
12091       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12092     }
12093
12094   gtk_tree_path_free (tmp);
12095 }
12096
12097 /* FIXME the bool return values for expand_row and collapse_row are
12098  * not analagous; they should be TRUE if the row had children and
12099  * was not already in the requested state.
12100  */
12101
12102
12103 static gboolean
12104 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12105                                GtkTreePath *path,
12106                                GtkRBTree   *tree,
12107                                GtkRBNode   *node,
12108                                gboolean     open_all,
12109                                gboolean     animate)
12110 {
12111   GtkTreeIter iter;
12112   GtkTreeIter temp;
12113   gboolean expand;
12114
12115   if (animate)
12116     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12117                   "gtk-enable-animations", &animate,
12118                   NULL);
12119
12120   remove_auto_expand_timeout (tree_view);
12121
12122   if (node->children && !open_all)
12123     return FALSE;
12124
12125   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12126     return FALSE;
12127
12128   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12129   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12130     return FALSE;
12131
12132
12133    if (node->children && open_all)
12134     {
12135       gboolean retval = FALSE;
12136       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12137
12138       gtk_tree_path_append_index (tmp_path, 0);
12139       tree = node->children;
12140       node = tree->root;
12141       while (node->left != tree->nil)
12142         node = node->left;
12143       /* try to expand the children */
12144       do
12145         {
12146          gboolean t;
12147          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12148                                             TRUE, animate);
12149          if (t)
12150            retval = TRUE;
12151
12152          gtk_tree_path_next (tmp_path);
12153          node = _gtk_rbtree_next (tree, node);
12154        }
12155       while (node != NULL);
12156
12157       gtk_tree_path_free (tmp_path);
12158
12159       return retval;
12160     }
12161
12162   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12163
12164   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12165     return FALSE;
12166
12167   if (expand)
12168     return FALSE;
12169
12170   node->children = _gtk_rbtree_new ();
12171   node->children->parent_tree = tree;
12172   node->children->parent_node = node;
12173
12174   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12175
12176   gtk_tree_view_build_tree (tree_view,
12177                             node->children,
12178                             &temp,
12179                             gtk_tree_path_get_depth (path) + 1,
12180                             open_all);
12181
12182   remove_expand_collapse_timeout (tree_view);
12183
12184   if (animate)
12185     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12186
12187   install_presize_handler (tree_view);
12188
12189   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12190   if (open_all && node->children)
12191     {
12192       _gtk_rbtree_traverse (node->children,
12193                             node->children->root,
12194                             G_PRE_ORDER,
12195                             gtk_tree_view_expand_all_emission_helper,
12196                             tree_view);
12197     }
12198   return TRUE;
12199 }
12200
12201
12202 /**
12203  * gtk_tree_view_expand_row:
12204  * @tree_view: a #GtkTreeView
12205  * @path: path to a row
12206  * @open_all: whether to recursively expand, or just expand immediate children
12207  *
12208  * Opens the row so its children are visible.
12209  *
12210  * Return value: %TRUE if the row existed and had children
12211  **/
12212 gboolean
12213 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12214                           GtkTreePath *path,
12215                           gboolean     open_all)
12216 {
12217   GtkRBTree *tree;
12218   GtkRBNode *node;
12219
12220   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12221   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12222   g_return_val_if_fail (path != NULL, FALSE);
12223
12224   if (_gtk_tree_view_find_node (tree_view,
12225                                 path,
12226                                 &tree,
12227                                 &node))
12228     return FALSE;
12229
12230   if (tree != NULL)
12231     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12232   else
12233     return FALSE;
12234 }
12235
12236 static gboolean
12237 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12238                                  GtkTreePath *path,
12239                                  GtkRBTree   *tree,
12240                                  GtkRBNode   *node,
12241                                  gboolean     animate)
12242 {
12243   GtkTreeIter iter;
12244   GtkTreeIter children;
12245   gboolean collapse;
12246   gint x, y;
12247   GList *list;
12248   GdkWindow *child, *parent;
12249
12250   if (animate)
12251     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12252                   "gtk-enable-animations", &animate,
12253                   NULL);
12254
12255   remove_auto_expand_timeout (tree_view);
12256
12257   if (node->children == NULL)
12258     return FALSE;
12259
12260   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12261
12262   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12263
12264   if (collapse)
12265     return FALSE;
12266
12267   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12268    * a chance to prelight the correct node below */
12269
12270   if (tree_view->priv->prelight_tree)
12271     {
12272       GtkRBTree *parent_tree;
12273       GtkRBNode *parent_node;
12274
12275       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12276       parent_node = tree_view->priv->prelight_tree->parent_node;
12277       while (parent_tree)
12278         {
12279           if (parent_tree == tree && parent_node == node)
12280             {
12281               ensure_unprelighted (tree_view);
12282               break;
12283             }
12284           parent_node = parent_tree->parent_node;
12285           parent_tree = parent_tree->parent_tree;
12286         }
12287     }
12288
12289   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12290
12291   for (list = tree_view->priv->columns; list; list = list->next)
12292     {
12293       GtkTreeViewColumn *column = list->data;
12294
12295       if (column->visible == FALSE)
12296         continue;
12297       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12298         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12299     }
12300
12301   if (tree_view->priv->destroy_count_func)
12302     {
12303       GtkTreePath *child_path;
12304       gint child_count = 0;
12305       child_path = gtk_tree_path_copy (path);
12306       gtk_tree_path_down (child_path);
12307       if (node->children)
12308         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12309       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12310       gtk_tree_path_free (child_path);
12311     }
12312
12313   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12314     {
12315       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12316
12317       if (gtk_tree_path_is_ancestor (path, cursor_path))
12318         {
12319           gtk_tree_row_reference_free (tree_view->priv->cursor);
12320           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12321                                                                       tree_view->priv->model,
12322                                                                       path);
12323         }
12324       gtk_tree_path_free (cursor_path);
12325     }
12326
12327   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12328     {
12329       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12330       if (gtk_tree_path_is_ancestor (path, anchor_path))
12331         {
12332           gtk_tree_row_reference_free (tree_view->priv->anchor);
12333           tree_view->priv->anchor = NULL;
12334         }
12335       gtk_tree_path_free (anchor_path);
12336     }
12337
12338   /* Stop a pending double click */
12339   tree_view->priv->last_button_x = -1;
12340   tree_view->priv->last_button_y = -1;
12341
12342   remove_expand_collapse_timeout (tree_view);
12343
12344   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12345     {
12346       _gtk_rbtree_remove (node->children);
12347       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12348     }
12349   else
12350     _gtk_rbtree_remove (node->children);
12351   
12352   if (animate)
12353     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12354   
12355   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12356     {
12357       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12358     }
12359
12360   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12361
12362   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12363     {
12364       /* now that we've collapsed all rows, we want to try to set the prelight
12365        * again. To do this, we fake a motion event and send it to ourselves. */
12366
12367       child = tree_view->priv->bin_window;
12368       parent = gdk_window_get_parent (child);
12369
12370       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12371         {
12372           GdkEventMotion event;
12373           gint child_x, child_y;
12374
12375           gdk_window_get_position (child, &child_x, &child_y);
12376
12377           event.window = tree_view->priv->bin_window;
12378           event.x = x - child_x;
12379           event.y = y - child_y;
12380
12381           /* despite the fact this isn't a real event, I'm almost positive it will
12382            * never trigger a drag event.  maybe_drag is the only function that uses
12383            * more than just event.x and event.y. */
12384           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12385         }
12386     }
12387
12388   return TRUE;
12389 }
12390
12391 /**
12392  * gtk_tree_view_collapse_row:
12393  * @tree_view: a #GtkTreeView
12394  * @path: path to a row in the @tree_view
12395  *
12396  * Collapses a row (hides its child rows, if they exist).
12397  *
12398  * Return value: %TRUE if the row was collapsed.
12399  **/
12400 gboolean
12401 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12402                             GtkTreePath *path)
12403 {
12404   GtkRBTree *tree;
12405   GtkRBNode *node;
12406
12407   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12408   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12409   g_return_val_if_fail (path != NULL, FALSE);
12410
12411   if (_gtk_tree_view_find_node (tree_view,
12412                                 path,
12413                                 &tree,
12414                                 &node))
12415     return FALSE;
12416
12417   if (tree == NULL || node->children == NULL)
12418     return FALSE;
12419
12420   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12421 }
12422
12423 static void
12424 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12425                                         GtkRBTree              *tree,
12426                                         GtkTreePath            *path,
12427                                         GtkTreeViewMappingFunc  func,
12428                                         gpointer                user_data)
12429 {
12430   GtkRBNode *node;
12431
12432   if (tree == NULL || tree->root == NULL)
12433     return;
12434
12435   node = tree->root;
12436
12437   while (node && node->left != tree->nil)
12438     node = node->left;
12439
12440   while (node)
12441     {
12442       if (node->children)
12443         {
12444           (* func) (tree_view, path, user_data);
12445           gtk_tree_path_down (path);
12446           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12447           gtk_tree_path_up (path);
12448         }
12449       gtk_tree_path_next (path);
12450       node = _gtk_rbtree_next (tree, node);
12451     }
12452 }
12453
12454 /**
12455  * gtk_tree_view_map_expanded_rows:
12456  * @tree_view: A #GtkTreeView
12457  * @func: (scope call): A function to be called
12458  * @data: User data to be passed to the function.
12459  *
12460  * Calls @func on all expanded rows.
12461  **/
12462 void
12463 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12464                                  GtkTreeViewMappingFunc  func,
12465                                  gpointer                user_data)
12466 {
12467   GtkTreePath *path;
12468
12469   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12470   g_return_if_fail (func != NULL);
12471
12472   path = gtk_tree_path_new_first ();
12473
12474   gtk_tree_view_map_expanded_rows_helper (tree_view,
12475                                           tree_view->priv->tree,
12476                                           path, func, user_data);
12477
12478   gtk_tree_path_free (path);
12479 }
12480
12481 /**
12482  * gtk_tree_view_row_expanded:
12483  * @tree_view: A #GtkTreeView.
12484  * @path: A #GtkTreePath to test expansion state.
12485  *
12486  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12487  *
12488  * Return value: %TRUE if #path is expanded.
12489  **/
12490 gboolean
12491 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12492                             GtkTreePath *path)
12493 {
12494   GtkRBTree *tree;
12495   GtkRBNode *node;
12496
12497   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12498   g_return_val_if_fail (path != NULL, FALSE);
12499
12500   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12501
12502   if (node == NULL)
12503     return FALSE;
12504
12505   return (node->children != NULL);
12506 }
12507
12508 /**
12509  * gtk_tree_view_get_reorderable:
12510  * @tree_view: a #GtkTreeView
12511  *
12512  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12513  * gtk_tree_view_set_reorderable().
12514  *
12515  * Return value: %TRUE if the tree can be reordered.
12516  **/
12517 gboolean
12518 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12519 {
12520   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12521
12522   return tree_view->priv->reorderable;
12523 }
12524
12525 /**
12526  * gtk_tree_view_set_reorderable:
12527  * @tree_view: A #GtkTreeView.
12528  * @reorderable: %TRUE, if the tree can be reordered.
12529  *
12530  * This function is a convenience function to allow you to reorder
12531  * models that support the #GtkDragSourceIface and the
12532  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12533  * these.  If @reorderable is %TRUE, then the user can reorder the
12534  * model by dragging and dropping rows. The developer can listen to
12535  * these changes by connecting to the model's row_inserted and
12536  * row_deleted signals. The reordering is implemented by setting up
12537  * the tree view as a drag source and destination. Therefore, drag and
12538  * drop can not be used in a reorderable view for any other purpose.
12539  *
12540  * This function does not give you any degree of control over the order -- any
12541  * reordering is allowed.  If more control is needed, you should probably
12542  * handle drag and drop manually.
12543  **/
12544 void
12545 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12546                                gboolean     reorderable)
12547 {
12548   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12549
12550   reorderable = reorderable != FALSE;
12551
12552   if (tree_view->priv->reorderable == reorderable)
12553     return;
12554
12555   if (reorderable)
12556     {
12557       const GtkTargetEntry row_targets[] = {
12558         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12559       };
12560
12561       gtk_tree_view_enable_model_drag_source (tree_view,
12562                                               GDK_BUTTON1_MASK,
12563                                               row_targets,
12564                                               G_N_ELEMENTS (row_targets),
12565                                               GDK_ACTION_MOVE);
12566       gtk_tree_view_enable_model_drag_dest (tree_view,
12567                                             row_targets,
12568                                             G_N_ELEMENTS (row_targets),
12569                                             GDK_ACTION_MOVE);
12570     }
12571   else
12572     {
12573       gtk_tree_view_unset_rows_drag_source (tree_view);
12574       gtk_tree_view_unset_rows_drag_dest (tree_view);
12575     }
12576
12577   tree_view->priv->reorderable = reorderable;
12578
12579   g_object_notify (G_OBJECT (tree_view), "reorderable");
12580 }
12581
12582 static void
12583 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12584                                GtkTreePath     *path,
12585                                gboolean         clear_and_select,
12586                                gboolean         clamp_node)
12587 {
12588   GtkRBTree *tree = NULL;
12589   GtkRBNode *node = NULL;
12590
12591   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12592     {
12593       GtkTreePath *cursor_path;
12594       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12595       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12596       gtk_tree_path_free (cursor_path);
12597     }
12598
12599   gtk_tree_row_reference_free (tree_view->priv->cursor);
12600   tree_view->priv->cursor = NULL;
12601
12602   /* One cannot set the cursor on a separator.   Also, if
12603    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12604    * before finding the tree and node belonging to path.  The
12605    * path maps to a non-existing path and we will silently bail out.
12606    * We unset tree and node to avoid further processing.
12607    */
12608   if (!row_is_separator (tree_view, NULL, path)
12609       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12610     {
12611       tree_view->priv->cursor =
12612           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12613                                             tree_view->priv->model,
12614                                             path);
12615     }
12616   else
12617     {
12618       tree = NULL;
12619       node = NULL;
12620     }
12621
12622   if (tree != NULL)
12623     {
12624       GtkRBTree *new_tree = NULL;
12625       GtkRBNode *new_node = NULL;
12626
12627       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12628         {
12629           GtkTreeSelectMode mode = 0;
12630
12631           if (tree_view->priv->ctrl_pressed)
12632             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12633           if (tree_view->priv->shift_pressed)
12634             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12635
12636           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12637                                                     node, tree, path, mode,
12638                                                     FALSE);
12639         }
12640
12641       /* We have to re-find tree and node here again, somebody might have
12642        * cleared the node or the whole tree in the GtkTreeSelection::changed
12643        * callback. If the nodes differ we bail out here.
12644        */
12645       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12646
12647       if (tree != new_tree || node != new_node)
12648         return;
12649
12650       if (clamp_node)
12651         {
12652           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12653           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12654         }
12655     }
12656
12657   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12658 }
12659
12660 /**
12661  * gtk_tree_view_get_cursor:
12662  * @tree_view: A #GtkTreeView
12663  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
12664  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
12665  *
12666  * Fills in @path and @focus_column with the current path and focus column.  If
12667  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12668  * currently has focus, then *@focus_column will be %NULL.
12669  *
12670  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12671  * you are done with it.
12672  **/
12673 void
12674 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12675                           GtkTreePath       **path,
12676                           GtkTreeViewColumn **focus_column)
12677 {
12678   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12679
12680   if (path)
12681     {
12682       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12683         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12684       else
12685         *path = NULL;
12686     }
12687
12688   if (focus_column)
12689     {
12690       *focus_column = tree_view->priv->focus_column;
12691     }
12692 }
12693
12694 /**
12695  * gtk_tree_view_set_cursor:
12696  * @tree_view: A #GtkTreeView
12697  * @path: A #GtkTreePath
12698  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12699  * @start_editing: %TRUE if the specified cell should start being edited.
12700  *
12701  * Sets the current keyboard focus to be at @path, and selects it.  This is
12702  * useful when you want to focus the user's attention on a particular row.  If
12703  * @focus_column is not %NULL, then focus is given to the column specified by 
12704  * it. Additionally, if @focus_column is specified, and @start_editing is 
12705  * %TRUE, then editing should be started in the specified cell.  
12706  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12707  * in order to give keyboard focus to the widget.  Please note that editing 
12708  * can only happen when the widget is realized.
12709  *
12710  * If @path is invalid for @model, the current cursor (if any) will be unset
12711  * and the function will return without failing.
12712  **/
12713 void
12714 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12715                           GtkTreePath       *path,
12716                           GtkTreeViewColumn *focus_column,
12717                           gboolean           start_editing)
12718 {
12719   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12720                                     NULL, start_editing);
12721 }
12722
12723 /**
12724  * gtk_tree_view_set_cursor_on_cell:
12725  * @tree_view: A #GtkTreeView
12726  * @path: A #GtkTreePath
12727  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12728  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12729  * @start_editing: %TRUE if the specified cell should start being edited.
12730  *
12731  * Sets the current keyboard focus to be at @path, and selects it.  This is
12732  * useful when you want to focus the user's attention on a particular row.  If
12733  * @focus_column is not %NULL, then focus is given to the column specified by
12734  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12735  * contains 2 or more editable or activatable cells, then focus is given to
12736  * the cell specified by @focus_cell. Additionally, if @focus_column is
12737  * specified, and @start_editing is %TRUE, then editing should be started in
12738  * the specified cell.  This function is often followed by
12739  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12740  * widget.  Please note that editing can only happen when the widget is
12741  * realized.
12742  *
12743  * If @path is invalid for @model, the current cursor (if any) will be unset
12744  * and the function will return without failing.
12745  *
12746  * Since: 2.2
12747  **/
12748 void
12749 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12750                                   GtkTreePath       *path,
12751                                   GtkTreeViewColumn *focus_column,
12752                                   GtkCellRenderer   *focus_cell,
12753                                   gboolean           start_editing)
12754 {
12755   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12756   g_return_if_fail (path != NULL);
12757   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12758
12759   if (!tree_view->priv->model)
12760     return;
12761
12762   if (focus_cell)
12763     {
12764       g_return_if_fail (focus_column);
12765       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12766     }
12767
12768   /* cancel the current editing, if it exists */
12769   if (tree_view->priv->edited_column &&
12770       tree_view->priv->edited_column->editable_widget)
12771     gtk_tree_view_stop_editing (tree_view, TRUE);
12772
12773   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12774
12775   if (focus_column && focus_column->visible)
12776     {
12777       GList *list;
12778       gboolean column_in_tree = FALSE;
12779
12780       for (list = tree_view->priv->columns; list; list = list->next)
12781         if (list->data == focus_column)
12782           {
12783             column_in_tree = TRUE;
12784             break;
12785           }
12786       g_return_if_fail (column_in_tree);
12787       tree_view->priv->focus_column = focus_column;
12788       if (focus_cell)
12789         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12790       if (start_editing)
12791         gtk_tree_view_start_editing (tree_view, path);
12792     }
12793 }
12794
12795 /**
12796  * gtk_tree_view_get_bin_window:
12797  * @tree_view: A #GtkTreeView
12798  *
12799  * Returns the window that @tree_view renders to.
12800  * This is used primarily to compare to <literal>event->window</literal>
12801  * to confirm that the event on @tree_view is on the right window.
12802  *
12803  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
12804  *     hasn't been realized yet
12805  **/
12806 GdkWindow *
12807 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12808 {
12809   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12810
12811   return tree_view->priv->bin_window;
12812 }
12813
12814 /**
12815  * gtk_tree_view_get_path_at_pos:
12816  * @tree_view: A #GtkTreeView.
12817  * @x: The x position to be identified (relative to bin_window).
12818  * @y: The y position to be identified (relative to bin_window).
12819  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12820  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12821  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
12822  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12823  *
12824  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12825  * (please see gtk_tree_view_get_bin_window()).
12826  * That is, @x and @y are relative to an events coordinates. @x and @y must
12827  * come from an event on the @tree_view only where <literal>event->window ==
12828  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12829  * things like popup menus. If @path is non-%NULL, then it will be filled
12830  * with the #GtkTreePath at that point.  This path should be freed with
12831  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12832  * with the column at that point.  @cell_x and @cell_y return the coordinates
12833  * relative to the cell background (i.e. the @background_area passed to
12834  * gtk_cell_renderer_render()).  This function is only meaningful if
12835  * @tree_view is realized.  Therefore this function will always return %FALSE
12836  * if @tree_view is not realized or does not have a model.
12837  *
12838  * For converting widget coordinates (eg. the ones you get from
12839  * GtkWidget::query-tooltip), please see
12840  * gtk_tree_view_convert_widget_to_bin_window_coords().
12841  *
12842  * Return value: %TRUE if a row exists at that coordinate.
12843  **/
12844 gboolean
12845 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12846                                gint                x,
12847                                gint                y,
12848                                GtkTreePath       **path,
12849                                GtkTreeViewColumn **column,
12850                                gint               *cell_x,
12851                                gint               *cell_y)
12852 {
12853   GtkRBTree *tree;
12854   GtkRBNode *node;
12855   gint y_offset;
12856
12857   g_return_val_if_fail (tree_view != NULL, FALSE);
12858
12859   if (path)
12860     *path = NULL;
12861   if (column)
12862     *column = NULL;
12863
12864   if (tree_view->priv->bin_window == NULL)
12865     return FALSE;
12866
12867   if (tree_view->priv->tree == NULL)
12868     return FALSE;
12869
12870   if (x > tree_view->priv->hadjustment->upper)
12871     return FALSE;
12872
12873   if (x < 0 || y < 0)
12874     return FALSE;
12875
12876   if (column || cell_x)
12877     {
12878       GtkTreeViewColumn *tmp_column;
12879       GtkTreeViewColumn *last_column = NULL;
12880       GList *list;
12881       gint remaining_x = x;
12882       gboolean found = FALSE;
12883       gboolean rtl;
12884
12885       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12886       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12887            list;
12888            list = (rtl ? list->prev : list->next))
12889         {
12890           tmp_column = list->data;
12891
12892           if (tmp_column->visible == FALSE)
12893             continue;
12894
12895           last_column = tmp_column;
12896           if (remaining_x <= tmp_column->width)
12897             {
12898               found = TRUE;
12899
12900               if (column)
12901                 *column = tmp_column;
12902
12903               if (cell_x)
12904                 *cell_x = remaining_x;
12905
12906               break;
12907             }
12908           remaining_x -= tmp_column->width;
12909         }
12910
12911       /* If found is FALSE and there is a last_column, then it the remainder
12912        * space is in that area
12913        */
12914       if (!found)
12915         {
12916           if (last_column)
12917             {
12918               if (column)
12919                 *column = last_column;
12920               
12921               if (cell_x)
12922                 *cell_x = last_column->width + remaining_x;
12923             }
12924           else
12925             {
12926               return FALSE;
12927             }
12928         }
12929     }
12930
12931   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12932                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12933                                       &tree, &node);
12934
12935   if (tree == NULL)
12936     return FALSE;
12937
12938   if (cell_y)
12939     *cell_y = y_offset;
12940
12941   if (path)
12942     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12943
12944   return TRUE;
12945 }
12946
12947
12948 /**
12949  * gtk_tree_view_get_cell_area:
12950  * @tree_view: a #GtkTreeView
12951  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12952  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12953  * @rect: rectangle to fill with cell rect
12954  *
12955  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12956  * row specified by @path and the column specified by @column.  If @path is
12957  * %NULL, or points to a path not currently displayed, the @y and @height fields
12958  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12959  * fields will be filled with 0.  The sum of all cell rects does not cover the
12960  * entire tree; there are extra pixels in between rows, for example. The
12961  * returned rectangle is equivalent to the @cell_area passed to
12962  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12963  * realized.
12964  **/
12965 void
12966 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12967                              GtkTreePath        *path,
12968                              GtkTreeViewColumn  *column,
12969                              GdkRectangle       *rect)
12970 {
12971   GtkAllocation allocation;
12972   GtkRBTree *tree = NULL;
12973   GtkRBNode *node = NULL;
12974   gint vertical_separator;
12975   gint horizontal_separator;
12976
12977   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12978   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12979   g_return_if_fail (rect != NULL);
12980   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12981   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12982
12983   gtk_widget_style_get (GTK_WIDGET (tree_view),
12984                         "vertical-separator", &vertical_separator,
12985                         "horizontal-separator", &horizontal_separator,
12986                         NULL);
12987
12988   rect->x = 0;
12989   rect->y = 0;
12990   rect->width = 0;
12991   rect->height = 0;
12992
12993   if (column)
12994     {
12995       gtk_widget_get_allocation (column->button, &allocation);
12996       rect->x = allocation.x + horizontal_separator/2;
12997       rect->width = allocation.width - horizontal_separator;
12998     }
12999
13000   if (path)
13001     {
13002       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13003
13004       /* Get vertical coords */
13005       if ((!ret && tree == NULL) || ret)
13006         return;
13007
13008       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
13009       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
13010
13011       if (column &&
13012           gtk_tree_view_is_expander_column (tree_view, column))
13013         {
13014           gint depth = gtk_tree_path_get_depth (path);
13015           gboolean rtl;
13016
13017           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13018
13019           if (!rtl)
13020             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13021           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13022
13023           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
13024             {
13025               if (!rtl)
13026                 rect->x += depth * tree_view->priv->expander_size;
13027               rect->width -= depth * tree_view->priv->expander_size;
13028             }
13029
13030           rect->width = MAX (rect->width, 0);
13031         }
13032     }
13033 }
13034
13035 /**
13036  * gtk_tree_view_get_background_area:
13037  * @tree_view: a #GtkTreeView
13038  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13039  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13040  * @rect: rectangle to fill with cell background rect
13041  *
13042  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13043  * row specified by @path and the column specified by @column.  If @path is
13044  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13045  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13046  * fields will be filled with 0.  The returned rectangle is equivalent to the
13047  * @background_area passed to gtk_cell_renderer_render().  These background
13048  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13049  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13050  * itself, excluding surrounding borders and the tree expander area.
13051  *
13052  **/
13053 void
13054 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13055                                    GtkTreePath        *path,
13056                                    GtkTreeViewColumn  *column,
13057                                    GdkRectangle       *rect)
13058 {
13059   GtkRBTree *tree = NULL;
13060   GtkRBNode *node = NULL;
13061
13062   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13063   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13064   g_return_if_fail (rect != NULL);
13065
13066   rect->x = 0;
13067   rect->y = 0;
13068   rect->width = 0;
13069   rect->height = 0;
13070
13071   if (path)
13072     {
13073       /* Get vertical coords */
13074
13075       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13076           tree == NULL)
13077         return;
13078
13079       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13080
13081       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13082     }
13083
13084   if (column)
13085     {
13086       gint x2 = 0;
13087
13088       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13089       rect->width = x2 - rect->x;
13090     }
13091 }
13092
13093 /**
13094  * gtk_tree_view_get_visible_rect:
13095  * @tree_view: a #GtkTreeView
13096  * @visible_rect: rectangle to fill
13097  *
13098  * Fills @visible_rect with the currently-visible region of the
13099  * buffer, in tree coordinates. Convert to bin_window coordinates with
13100  * gtk_tree_view_convert_tree_to_bin_window_coords().
13101  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13102  * scrollable area of the tree.
13103  **/
13104 void
13105 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13106                                 GdkRectangle *visible_rect)
13107 {
13108   GtkAllocation allocation;
13109   GtkWidget *widget;
13110
13111   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13112
13113   widget = GTK_WIDGET (tree_view);
13114
13115   if (visible_rect)
13116     {
13117       gtk_widget_get_allocation (widget, &allocation);
13118       visible_rect->x = tree_view->priv->hadjustment->value;
13119       visible_rect->y = tree_view->priv->vadjustment->value;
13120       visible_rect->width = allocation.width;
13121       visible_rect->height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13122     }
13123 }
13124
13125 /**
13126  * gtk_tree_view_convert_widget_to_tree_coords:
13127  * @tree_view: a #GtkTreeView
13128  * @wx: X coordinate relative to the widget
13129  * @wy: Y coordinate relative to the widget
13130  * @tx: return location for tree X coordinate
13131  * @ty: return location for tree Y coordinate
13132  *
13133  * Converts widget coordinates to coordinates for the
13134  * tree (the full scrollable area of the tree).
13135  *
13136  * Since: 2.12
13137  **/
13138 void
13139 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13140                                              gint         wx,
13141                                              gint         wy,
13142                                              gint        *tx,
13143                                              gint        *ty)
13144 {
13145   gint x, y;
13146
13147   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13148
13149   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13150                                                      wx, wy,
13151                                                      &x, &y);
13152   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13153                                                    x, y,
13154                                                    tx, ty);
13155 }
13156
13157 /**
13158  * gtk_tree_view_convert_tree_to_widget_coords:
13159  * @tree_view: a #GtkTreeView
13160  * @tx: X coordinate relative to the tree
13161  * @ty: Y coordinate relative to the tree
13162  * @wx: return location for widget X coordinate
13163  * @wy: return location for widget Y coordinate
13164  *
13165  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13166  * to widget coordinates.
13167  *
13168  * Since: 2.12
13169  **/
13170 void
13171 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13172                                              gint         tx,
13173                                              gint         ty,
13174                                              gint        *wx,
13175                                              gint        *wy)
13176 {
13177   gint x, y;
13178
13179   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13180
13181   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13182                                                    tx, ty,
13183                                                    &x, &y);
13184   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13185                                                      x, y,
13186                                                      wx, wy);
13187 }
13188
13189 /**
13190  * gtk_tree_view_convert_widget_to_bin_window_coords:
13191  * @tree_view: a #GtkTreeView
13192  * @wx: X coordinate relative to the widget
13193  * @wy: Y coordinate relative to the widget
13194  * @bx: return location for bin_window X coordinate
13195  * @by: return location for bin_window Y coordinate
13196  *
13197  * Converts widget coordinates to coordinates for the bin_window
13198  * (see gtk_tree_view_get_bin_window()).
13199  *
13200  * Since: 2.12
13201  **/
13202 void
13203 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13204                                                    gint         wx,
13205                                                    gint         wy,
13206                                                    gint        *bx,
13207                                                    gint        *by)
13208 {
13209   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13210
13211   if (bx)
13212     *bx = wx + tree_view->priv->hadjustment->value;
13213   if (by)
13214     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13215 }
13216
13217 /**
13218  * gtk_tree_view_convert_bin_window_to_widget_coords:
13219  * @tree_view: a #GtkTreeView
13220  * @bx: bin_window X coordinate
13221  * @by: bin_window Y coordinate
13222  * @wx: return location for widget X coordinate
13223  * @wy: return location for widget Y coordinate
13224  *
13225  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13226  * to widget relative coordinates.
13227  *
13228  * Since: 2.12
13229  **/
13230 void
13231 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13232                                                    gint         bx,
13233                                                    gint         by,
13234                                                    gint        *wx,
13235                                                    gint        *wy)
13236 {
13237   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13238
13239   if (wx)
13240     *wx = bx - tree_view->priv->hadjustment->value;
13241   if (wy)
13242     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13243 }
13244
13245 /**
13246  * gtk_tree_view_convert_tree_to_bin_window_coords:
13247  * @tree_view: a #GtkTreeView
13248  * @tx: tree X coordinate
13249  * @ty: tree Y coordinate
13250  * @bx: return location for X coordinate relative to bin_window
13251  * @by: return location for Y coordinate relative to bin_window
13252  *
13253  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13254  * to bin_window coordinates.
13255  *
13256  * Since: 2.12
13257  **/
13258 void
13259 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13260                                                  gint         tx,
13261                                                  gint         ty,
13262                                                  gint        *bx,
13263                                                  gint        *by)
13264 {
13265   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13266
13267   if (bx)
13268     *bx = tx;
13269   if (by)
13270     *by = ty - tree_view->priv->dy;
13271 }
13272
13273 /**
13274  * gtk_tree_view_convert_bin_window_to_tree_coords:
13275  * @tree_view: a #GtkTreeView
13276  * @bx: X coordinate relative to bin_window
13277  * @by: Y coordinate relative to bin_window
13278  * @tx: return location for tree X coordinate
13279  * @ty: return location for tree Y coordinate
13280  *
13281  * Converts bin_window coordinates to coordinates for the
13282  * tree (the full scrollable area of the tree).
13283  *
13284  * Since: 2.12
13285  **/
13286 void
13287 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13288                                                  gint         bx,
13289                                                  gint         by,
13290                                                  gint        *tx,
13291                                                  gint        *ty)
13292 {
13293   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13294
13295   if (tx)
13296     *tx = bx;
13297   if (ty)
13298     *ty = by + tree_view->priv->dy;
13299 }
13300
13301
13302
13303 /**
13304  * gtk_tree_view_get_visible_range:
13305  * @tree_view: A #GtkTreeView
13306  * @start_path: (allow-none): Return location for start of region, or %NULL.
13307  * @end_path: (allow-none): Return location for end of region, or %NULL.
13308  *
13309  * Sets @start_path and @end_path to be the first and last visible path.
13310  * Note that there may be invisible paths in between.
13311  *
13312  * The paths should be freed with gtk_tree_path_free() after use.
13313  *
13314  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13315  *
13316  * Since: 2.8
13317  **/
13318 gboolean
13319 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13320                                  GtkTreePath **start_path,
13321                                  GtkTreePath **end_path)
13322 {
13323   GtkRBTree *tree;
13324   GtkRBNode *node;
13325   gboolean retval;
13326   
13327   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13328
13329   if (!tree_view->priv->tree)
13330     return FALSE;
13331
13332   retval = TRUE;
13333
13334   if (start_path)
13335     {
13336       _gtk_rbtree_find_offset (tree_view->priv->tree,
13337                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13338                                &tree, &node);
13339       if (node)
13340         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13341       else
13342         retval = FALSE;
13343     }
13344
13345   if (end_path)
13346     {
13347       gint y;
13348
13349       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13350         y = tree_view->priv->height - 1;
13351       else
13352         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13353
13354       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13355       if (node)
13356         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13357       else
13358         retval = FALSE;
13359     }
13360
13361   return retval;
13362 }
13363
13364 static void
13365 unset_reorderable (GtkTreeView *tree_view)
13366 {
13367   if (tree_view->priv->reorderable)
13368     {
13369       tree_view->priv->reorderable = FALSE;
13370       g_object_notify (G_OBJECT (tree_view), "reorderable");
13371     }
13372 }
13373
13374 /**
13375  * gtk_tree_view_enable_model_drag_source:
13376  * @tree_view: a #GtkTreeView
13377  * @start_button_mask: Mask of allowed buttons to start drag
13378  * @targets: the table of targets that the drag will support
13379  * @n_targets: the number of items in @targets
13380  * @actions: the bitmask of possible actions for a drag from this
13381  *    widget
13382  *
13383  * Turns @tree_view into a drag source for automatic DND. Calling this
13384  * method sets #GtkTreeView:reorderable to %FALSE.
13385  **/
13386 void
13387 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13388                                         GdkModifierType           start_button_mask,
13389                                         const GtkTargetEntry     *targets,
13390                                         gint                      n_targets,
13391                                         GdkDragAction             actions)
13392 {
13393   TreeViewDragInfo *di;
13394
13395   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13396
13397   gtk_drag_source_set (GTK_WIDGET (tree_view),
13398                        0,
13399                        targets,
13400                        n_targets,
13401                        actions);
13402
13403   di = ensure_info (tree_view);
13404
13405   di->start_button_mask = start_button_mask;
13406   di->source_actions = actions;
13407   di->source_set = TRUE;
13408
13409   unset_reorderable (tree_view);
13410 }
13411
13412 /**
13413  * gtk_tree_view_enable_model_drag_dest:
13414  * @tree_view: a #GtkTreeView
13415  * @targets: the table of targets that the drag will support
13416  * @n_targets: the number of items in @targets
13417  * @actions: the bitmask of possible actions for a drag from this
13418  *    widget
13419  * 
13420  * Turns @tree_view into a drop destination for automatic DND. Calling
13421  * this method sets #GtkTreeView:reorderable to %FALSE.
13422  **/
13423 void
13424 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13425                                       const GtkTargetEntry     *targets,
13426                                       gint                      n_targets,
13427                                       GdkDragAction             actions)
13428 {
13429   TreeViewDragInfo *di;
13430
13431   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13432
13433   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13434                      0,
13435                      targets,
13436                      n_targets,
13437                      actions);
13438
13439   di = ensure_info (tree_view);
13440   di->dest_set = TRUE;
13441
13442   unset_reorderable (tree_view);
13443 }
13444
13445 /**
13446  * gtk_tree_view_unset_rows_drag_source:
13447  * @tree_view: a #GtkTreeView
13448  *
13449  * Undoes the effect of
13450  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13451  * #GtkTreeView:reorderable to %FALSE.
13452  **/
13453 void
13454 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13455 {
13456   TreeViewDragInfo *di;
13457
13458   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13459
13460   di = get_info (tree_view);
13461
13462   if (di)
13463     {
13464       if (di->source_set)
13465         {
13466           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13467           di->source_set = FALSE;
13468         }
13469
13470       if (!di->dest_set && !di->source_set)
13471         remove_info (tree_view);
13472     }
13473   
13474   unset_reorderable (tree_view);
13475 }
13476
13477 /**
13478  * gtk_tree_view_unset_rows_drag_dest:
13479  * @tree_view: a #GtkTreeView
13480  *
13481  * Undoes the effect of
13482  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13483  * #GtkTreeView:reorderable to %FALSE.
13484  **/
13485 void
13486 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13487 {
13488   TreeViewDragInfo *di;
13489
13490   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13491
13492   di = get_info (tree_view);
13493
13494   if (di)
13495     {
13496       if (di->dest_set)
13497         {
13498           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13499           di->dest_set = FALSE;
13500         }
13501
13502       if (!di->dest_set && !di->source_set)
13503         remove_info (tree_view);
13504     }
13505
13506   unset_reorderable (tree_view);
13507 }
13508
13509 /**
13510  * gtk_tree_view_set_drag_dest_row:
13511  * @tree_view: a #GtkTreeView
13512  * @path: (allow-none): The path of the row to highlight, or %NULL.
13513  * @pos: Specifies whether to drop before, after or into the row
13514  * 
13515  * Sets the row that is highlighted for feedback.
13516  **/
13517 void
13518 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13519                                  GtkTreePath            *path,
13520                                  GtkTreeViewDropPosition pos)
13521 {
13522   GtkTreePath *current_dest;
13523
13524   /* Note; this function is exported to allow a custom DND
13525    * implementation, so it can't touch TreeViewDragInfo
13526    */
13527
13528   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13529
13530   current_dest = NULL;
13531
13532   if (tree_view->priv->drag_dest_row)
13533     {
13534       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13535       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13536     }
13537
13538   /* special case a drop on an empty model */
13539   tree_view->priv->empty_view_drop = 0;
13540
13541   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13542       && gtk_tree_path_get_depth (path) == 1
13543       && gtk_tree_path_get_indices (path)[0] == 0)
13544     {
13545       gint n_children;
13546
13547       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13548                                                    NULL);
13549
13550       if (!n_children)
13551         tree_view->priv->empty_view_drop = 1;
13552     }
13553
13554   tree_view->priv->drag_dest_pos = pos;
13555
13556   if (path)
13557     {
13558       tree_view->priv->drag_dest_row =
13559         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13560       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13561     }
13562   else
13563     tree_view->priv->drag_dest_row = NULL;
13564
13565   if (current_dest)
13566     {
13567       GtkRBTree *tree, *new_tree;
13568       GtkRBNode *node, *new_node;
13569
13570       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13571       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13572
13573       if (tree && node)
13574         {
13575           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13576           if (new_tree && new_node)
13577             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13578
13579           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13580           if (new_tree && new_node)
13581             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13582         }
13583       gtk_tree_path_free (current_dest);
13584     }
13585 }
13586
13587 /**
13588  * gtk_tree_view_get_drag_dest_row:
13589  * @tree_view: a #GtkTreeView
13590  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13591  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13592  * 
13593  * Gets information about the row that is highlighted for feedback.
13594  **/
13595 void
13596 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13597                                  GtkTreePath             **path,
13598                                  GtkTreeViewDropPosition  *pos)
13599 {
13600   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13601
13602   if (path)
13603     {
13604       if (tree_view->priv->drag_dest_row)
13605         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13606       else
13607         {
13608           if (tree_view->priv->empty_view_drop)
13609             *path = gtk_tree_path_new_from_indices (0, -1);
13610           else
13611             *path = NULL;
13612         }
13613     }
13614
13615   if (pos)
13616     *pos = tree_view->priv->drag_dest_pos;
13617 }
13618
13619 /**
13620  * gtk_tree_view_get_dest_row_at_pos:
13621  * @tree_view: a #GtkTreeView
13622  * @drag_x: the position to determine the destination row for
13623  * @drag_y: the position to determine the destination row for
13624  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13625  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13626  * 
13627  * Determines the destination row for a given position.  @drag_x and
13628  * @drag_y are expected to be in widget coordinates.  This function is only
13629  * meaningful if @tree_view is realized.  Therefore this function will always
13630  * return %FALSE if @tree_view is not realized or does not have a model.
13631  * 
13632  * Return value: whether there is a row at the given position, %TRUE if this
13633  * is indeed the case.
13634  **/
13635 gboolean
13636 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13637                                    gint                     drag_x,
13638                                    gint                     drag_y,
13639                                    GtkTreePath            **path,
13640                                    GtkTreeViewDropPosition *pos)
13641 {
13642   gint cell_y;
13643   gint bin_x, bin_y;
13644   gdouble offset_into_row;
13645   gdouble third;
13646   GdkRectangle cell;
13647   GtkTreeViewColumn *column = NULL;
13648   GtkTreePath *tmp_path = NULL;
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_val_if_fail (tree_view != NULL, FALSE);
13655   g_return_val_if_fail (drag_x >= 0, FALSE);
13656   g_return_val_if_fail (drag_y >= 0, FALSE);
13657
13658   if (path)
13659     *path = NULL;
13660
13661   if (tree_view->priv->bin_window == NULL)
13662     return FALSE;
13663
13664   if (tree_view->priv->tree == NULL)
13665     return FALSE;
13666
13667   /* If in the top third of a row, we drop before that row; if
13668    * in the bottom third, drop after that row; if in the middle,
13669    * and the row has children, drop into the row.
13670    */
13671   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13672                                                      &bin_x, &bin_y);
13673
13674   if (!gtk_tree_view_get_path_at_pos (tree_view,
13675                                       bin_x,
13676                                       bin_y,
13677                                       &tmp_path,
13678                                       &column,
13679                                       NULL,
13680                                       &cell_y))
13681     return FALSE;
13682
13683   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13684                                      &cell);
13685
13686   offset_into_row = cell_y;
13687
13688   if (path)
13689     *path = tmp_path;
13690   else
13691     gtk_tree_path_free (tmp_path);
13692
13693   tmp_path = NULL;
13694
13695   third = cell.height / 3.0;
13696
13697   if (pos)
13698     {
13699       if (offset_into_row < third)
13700         {
13701           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13702         }
13703       else if (offset_into_row < (cell.height / 2.0))
13704         {
13705           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13706         }
13707       else if (offset_into_row < third * 2.0)
13708         {
13709           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13710         }
13711       else
13712         {
13713           *pos = GTK_TREE_VIEW_DROP_AFTER;
13714         }
13715     }
13716
13717   return TRUE;
13718 }
13719
13720
13721
13722 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13723 /**
13724  * gtk_tree_view_create_row_drag_icon:
13725  * @tree_view: a #GtkTreeView
13726  * @path: a #GtkTreePath in @tree_view
13727  *
13728  * Creates a #cairo_surface_t representation of the row at @path.  
13729  * This image is used for a drag icon.
13730  *
13731  * Return value: (transfer full): a newly-allocated surface of the drag icon.
13732  **/
13733 cairo_surface_t *
13734 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13735                                     GtkTreePath  *path)
13736 {
13737   GtkTreeIter   iter;
13738   GtkRBTree    *tree;
13739   GtkRBNode    *node;
13740   GtkStyle *style;
13741   gint cell_offset;
13742   GList *list;
13743   GdkRectangle background_area;
13744   GtkWidget *widget;
13745   gint depth;
13746   /* start drawing inside the black outline */
13747   gint x = 1, y = 1;
13748   cairo_surface_t *surface;
13749   gint bin_window_width;
13750   gboolean is_separator = FALSE;
13751   gboolean rtl;
13752   cairo_t *cr;
13753
13754   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13755   g_return_val_if_fail (path != NULL, NULL);
13756
13757   widget = GTK_WIDGET (tree_view);
13758
13759   if (!gtk_widget_get_realized (widget))
13760     return NULL;
13761
13762   depth = gtk_tree_path_get_depth (path);
13763
13764   _gtk_tree_view_find_node (tree_view,
13765                             path,
13766                             &tree,
13767                             &node);
13768
13769   if (tree == NULL)
13770     return NULL;
13771
13772   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13773                                 &iter,
13774                                 path))
13775     return NULL;
13776
13777   style = gtk_widget_get_style (widget);
13778
13779   is_separator = row_is_separator (tree_view, &iter, NULL);
13780
13781   cell_offset = x;
13782
13783   background_area.y = y;
13784   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13785
13786   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
13787
13788   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
13789                                                CAIRO_CONTENT_COLOR,
13790                                                bin_window_width + 2,
13791                                                background_area.height + 2);
13792
13793   cr = cairo_create (surface);
13794   gdk_cairo_set_source_color (cr, &style->base [gtk_widget_get_state (widget)]);
13795   cairo_paint (cr);
13796
13797   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13798
13799   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13800       list;
13801       list = (rtl ? list->prev : list->next))
13802     {
13803       GtkTreeViewColumn *column = list->data;
13804       GdkRectangle cell_area;
13805       gint vertical_separator;
13806
13807       if (!column->visible)
13808         continue;
13809
13810       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13811                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13812                                                node->children?TRUE:FALSE);
13813
13814       background_area.x = cell_offset;
13815       background_area.width = column->width;
13816
13817       gtk_widget_style_get (widget,
13818                             "vertical-separator", &vertical_separator,
13819                             NULL);
13820
13821       cell_area = background_area;
13822
13823       cell_area.y += vertical_separator / 2;
13824       cell_area.height -= vertical_separator;
13825
13826       if (gtk_tree_view_is_expander_column (tree_view, column))
13827         {
13828           if (!rtl)
13829             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13830           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13831
13832           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13833             {
13834               if (!rtl)
13835                 cell_area.x += depth * tree_view->priv->expander_size;
13836               cell_area.width -= depth * tree_view->priv->expander_size;
13837             }
13838         }
13839
13840       if (gtk_tree_view_column_cell_is_visible (column))
13841         {
13842           if (is_separator)
13843             gtk_paint_hline (style,
13844                                    cr,
13845                                    GTK_STATE_NORMAL,
13846                                    widget,
13847                                    NULL,
13848                                    cell_area.x,
13849                                    cell_area.x + cell_area.width,
13850                                    cell_area.y + cell_area.height / 2);
13851           else
13852             _gtk_tree_view_column_cell_render (column,
13853                                                cr,
13854                                                &background_area,
13855                                                &cell_area,
13856                                                0);
13857         }
13858       cell_offset += column->width;
13859     }
13860
13861   cairo_set_source_rgb (cr, 0, 0, 0);
13862   cairo_rectangle (cr, 
13863                    0.5, 0.5, 
13864                    bin_window_width + 1,
13865                    background_area.height + 1);
13866   cairo_set_line_width (cr, 1.0);
13867   cairo_stroke (cr);
13868
13869   cairo_destroy (cr);
13870
13871   cairo_surface_set_device_offset (surface, 2, 2);
13872
13873   return surface;
13874 }
13875
13876
13877 /**
13878  * gtk_tree_view_set_destroy_count_func:
13879  * @tree_view: A #GtkTreeView
13880  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
13881  * @data: (allow-none): User data to be passed to @func, or %NULL
13882  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
13883  *
13884  * This function should almost never be used.  It is meant for private use by
13885  * ATK for determining the number of visible children that are removed when the
13886  * user collapses a row, or a row is deleted.
13887  **/
13888 void
13889 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13890                                       GtkTreeDestroyCountFunc  func,
13891                                       gpointer                 data,
13892                                       GDestroyNotify           destroy)
13893 {
13894   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13895
13896   if (tree_view->priv->destroy_count_destroy)
13897     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13898
13899   tree_view->priv->destroy_count_func = func;
13900   tree_view->priv->destroy_count_data = data;
13901   tree_view->priv->destroy_count_destroy = destroy;
13902 }
13903
13904
13905 /*
13906  * Interactive search
13907  */
13908
13909 /**
13910  * gtk_tree_view_set_enable_search:
13911  * @tree_view: A #GtkTreeView
13912  * @enable_search: %TRUE, if the user can search interactively
13913  *
13914  * If @enable_search is set, then the user can type in text to search through
13915  * the tree interactively (this is sometimes called "typeahead find").
13916  * 
13917  * Note that even if this is %FALSE, the user can still initiate a search 
13918  * using the "start-interactive-search" key binding.
13919  */
13920 void
13921 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13922                                  gboolean     enable_search)
13923 {
13924   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13925
13926   enable_search = !!enable_search;
13927   
13928   if (tree_view->priv->enable_search != enable_search)
13929     {
13930        tree_view->priv->enable_search = enable_search;
13931        g_object_notify (G_OBJECT (tree_view), "enable-search");
13932     }
13933 }
13934
13935 /**
13936  * gtk_tree_view_get_enable_search:
13937  * @tree_view: A #GtkTreeView
13938  *
13939  * Returns whether or not the tree allows to start interactive searching 
13940  * by typing in text.
13941  *
13942  * Return value: whether or not to let the user search interactively
13943  */
13944 gboolean
13945 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13946 {
13947   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13948
13949   return tree_view->priv->enable_search;
13950 }
13951
13952
13953 /**
13954  * gtk_tree_view_get_search_column:
13955  * @tree_view: A #GtkTreeView
13956  *
13957  * Gets the column searched on by the interactive search code.
13958  *
13959  * Return value: the column the interactive search code searches in.
13960  */
13961 gint
13962 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13963 {
13964   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13965
13966   return (tree_view->priv->search_column);
13967 }
13968
13969 /**
13970  * gtk_tree_view_set_search_column:
13971  * @tree_view: A #GtkTreeView
13972  * @column: the column of the model to search in, or -1 to disable searching
13973  *
13974  * Sets @column as the column where the interactive search code should
13975  * search in for the current model. 
13976  * 
13977  * If the search column is set, users can use the "start-interactive-search"
13978  * key binding to bring up search popup. The enable-search property controls
13979  * whether simply typing text will also start an interactive search.
13980  *
13981  * Note that @column refers to a column of the current model. The search 
13982  * column is reset to -1 when the model is changed.
13983  */
13984 void
13985 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13986                                  gint         column)
13987 {
13988   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13989   g_return_if_fail (column >= -1);
13990
13991   if (tree_view->priv->search_column == column)
13992     return;
13993
13994   tree_view->priv->search_column = column;
13995   g_object_notify (G_OBJECT (tree_view), "search-column");
13996 }
13997
13998 /**
13999  * gtk_tree_view_get_search_equal_func:
14000  * @tree_view: A #GtkTreeView
14001  *
14002  * Returns the compare function currently in use.
14003  *
14004  * Return value: the currently used compare function for the search code.
14005  */
14006
14007 GtkTreeViewSearchEqualFunc
14008 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14009 {
14010   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14011
14012   return tree_view->priv->search_equal_func;
14013 }
14014
14015 /**
14016  * gtk_tree_view_set_search_equal_func:
14017  * @tree_view: A #GtkTreeView
14018  * @search_equal_func: the compare function to use during the search
14019  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14020  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14021  *
14022  * Sets the compare function for the interactive search capabilities; note
14023  * that somewhat like strcmp() returning 0 for equality
14024  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14025  **/
14026 void
14027 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14028                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14029                                      gpointer                    search_user_data,
14030                                      GDestroyNotify              search_destroy)
14031 {
14032   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14033   g_return_if_fail (search_equal_func != NULL);
14034
14035   if (tree_view->priv->search_destroy)
14036     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14037
14038   tree_view->priv->search_equal_func = search_equal_func;
14039   tree_view->priv->search_user_data = search_user_data;
14040   tree_view->priv->search_destroy = search_destroy;
14041   if (tree_view->priv->search_equal_func == NULL)
14042     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14043 }
14044
14045 /**
14046  * gtk_tree_view_get_search_entry:
14047  * @tree_view: A #GtkTreeView
14048  *
14049  * Returns the #GtkEntry which is currently in use as interactive search
14050  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14051  * will be returned.
14052  *
14053  * Return value: (transfer none): the entry currently in use as search entry.
14054  *
14055  * Since: 2.10
14056  */
14057 GtkEntry *
14058 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14059 {
14060   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14061
14062   if (tree_view->priv->search_custom_entry_set)
14063     return GTK_ENTRY (tree_view->priv->search_entry);
14064
14065   return NULL;
14066 }
14067
14068 /**
14069  * gtk_tree_view_set_search_entry:
14070  * @tree_view: A #GtkTreeView
14071  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14072  *
14073  * Sets the entry which the interactive search code will use for this
14074  * @tree_view.  This is useful when you want to provide a search entry
14075  * in our interface at all time at a fixed position.  Passing %NULL for
14076  * @entry will make the interactive search code use the built-in popup
14077  * entry again.
14078  *
14079  * Since: 2.10
14080  */
14081 void
14082 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14083                                 GtkEntry    *entry)
14084 {
14085   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14086   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14087
14088   if (tree_view->priv->search_custom_entry_set)
14089     {
14090       if (tree_view->priv->search_entry_changed_id)
14091         {
14092           g_signal_handler_disconnect (tree_view->priv->search_entry,
14093                                        tree_view->priv->search_entry_changed_id);
14094           tree_view->priv->search_entry_changed_id = 0;
14095         }
14096       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14097                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14098                                             tree_view);
14099
14100       g_object_unref (tree_view->priv->search_entry);
14101     }
14102   else if (tree_view->priv->search_window)
14103     {
14104       gtk_widget_destroy (tree_view->priv->search_window);
14105
14106       tree_view->priv->search_window = NULL;
14107     }
14108
14109   if (entry)
14110     {
14111       tree_view->priv->search_entry = g_object_ref (entry);
14112       tree_view->priv->search_custom_entry_set = TRUE;
14113
14114       if (tree_view->priv->search_entry_changed_id == 0)
14115         {
14116           tree_view->priv->search_entry_changed_id =
14117             g_signal_connect (tree_view->priv->search_entry, "changed",
14118                               G_CALLBACK (gtk_tree_view_search_init),
14119                               tree_view);
14120         }
14121       
14122         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14123                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14124                           tree_view);
14125
14126         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14127     }
14128   else
14129     {
14130       tree_view->priv->search_entry = NULL;
14131       tree_view->priv->search_custom_entry_set = FALSE;
14132     }
14133 }
14134
14135 /**
14136  * gtk_tree_view_set_search_position_func:
14137  * @tree_view: A #GtkTreeView
14138  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14139  *    to use the default search position function
14140  * @data: (allow-none): user data to pass to @func, or %NULL
14141  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14142  *
14143  * Sets the function to use when positioning the search dialog.
14144  *
14145  * Since: 2.10
14146  **/
14147 void
14148 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14149                                         GtkTreeViewSearchPositionFunc  func,
14150                                         gpointer                       user_data,
14151                                         GDestroyNotify                 destroy)
14152 {
14153   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14154
14155   if (tree_view->priv->search_position_destroy)
14156     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14157
14158   tree_view->priv->search_position_func = func;
14159   tree_view->priv->search_position_user_data = user_data;
14160   tree_view->priv->search_position_destroy = destroy;
14161   if (tree_view->priv->search_position_func == NULL)
14162     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14163 }
14164
14165 /**
14166  * gtk_tree_view_get_search_position_func:
14167  * @tree_view: A #GtkTreeView
14168  *
14169  * Returns the positioning function currently in use.
14170  *
14171  * Return value: the currently used function for positioning the search dialog.
14172  *
14173  * Since: 2.10
14174  */
14175 GtkTreeViewSearchPositionFunc
14176 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14177 {
14178   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14179
14180   return tree_view->priv->search_position_func;
14181 }
14182
14183
14184 static void
14185 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14186                                   GtkTreeView *tree_view,
14187                                   GdkDevice   *device)
14188 {
14189   if (tree_view->priv->disable_popdown)
14190     return;
14191
14192   if (tree_view->priv->search_entry_changed_id)
14193     {
14194       g_signal_handler_disconnect (tree_view->priv->search_entry,
14195                                    tree_view->priv->search_entry_changed_id);
14196       tree_view->priv->search_entry_changed_id = 0;
14197     }
14198   if (tree_view->priv->typeselect_flush_timeout)
14199     {
14200       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14201       tree_view->priv->typeselect_flush_timeout = 0;
14202     }
14203         
14204   if (gtk_widget_get_visible (search_dialog))
14205     {
14206       /* send focus-in event */
14207       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14208       gtk_widget_hide (search_dialog);
14209       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14210       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14211     }
14212 }
14213
14214 static void
14215 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14216                                     GtkWidget   *search_dialog,
14217                                     gpointer     user_data)
14218 {
14219   gint x, y;
14220   gint tree_x, tree_y;
14221   gint tree_width, tree_height;
14222   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14223   GdkScreen *screen = gdk_window_get_screen (tree_window);
14224   GtkRequisition requisition;
14225   gint monitor_num;
14226   GdkRectangle monitor;
14227
14228   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14229   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14230
14231   gtk_widget_realize (search_dialog);
14232
14233   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14234   tree_width = gdk_window_get_width (tree_window);
14235   tree_height = gdk_window_get_height (tree_window);
14236   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14237
14238   if (tree_x + tree_width > gdk_screen_get_width (screen))
14239     x = gdk_screen_get_width (screen) - requisition.width;
14240   else if (tree_x + tree_width - requisition.width < 0)
14241     x = 0;
14242   else
14243     x = tree_x + tree_width - requisition.width;
14244
14245   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14246     y = gdk_screen_get_height (screen) - requisition.height;
14247   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14248     y = 0;
14249   else
14250     y = tree_y + tree_height;
14251
14252   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14253 }
14254
14255 static void
14256 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14257                                       GtkMenu  *menu,
14258                                       gpointer  data)
14259 {
14260   GtkTreeView *tree_view = (GtkTreeView *)data;
14261
14262   tree_view->priv->disable_popdown = 1;
14263   g_signal_connect (menu, "hide",
14264                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14265 }
14266
14267 /* Because we're visible but offscreen, we just set a flag in the preedit
14268  * callback.
14269  */
14270 static void
14271 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14272                                       GtkTreeView  *tree_view)
14273 {
14274   tree_view->priv->imcontext_changed = 1;
14275   if (tree_view->priv->typeselect_flush_timeout)
14276     {
14277       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14278       tree_view->priv->typeselect_flush_timeout =
14279         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14280                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14281                        tree_view);
14282     }
14283
14284 }
14285
14286 static void
14287 gtk_tree_view_search_activate (GtkEntry    *entry,
14288                                GtkTreeView *tree_view)
14289 {
14290   GtkTreePath *path;
14291   GtkRBNode *node;
14292   GtkRBTree *tree;
14293
14294   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14295                                     tree_view,
14296                                     gtk_get_current_event_device ());
14297
14298   /* If we have a row selected and it's the cursor row, we activate
14299    * the row XXX */
14300   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14301     {
14302       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14303       
14304       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14305       
14306       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14307         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14308       
14309       gtk_tree_path_free (path);
14310     }
14311 }
14312
14313 static gboolean
14314 gtk_tree_view_real_search_enable_popdown (gpointer data)
14315 {
14316   GtkTreeView *tree_view = (GtkTreeView *)data;
14317
14318   tree_view->priv->disable_popdown = 0;
14319
14320   return FALSE;
14321 }
14322
14323 static void
14324 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14325                                      gpointer   data)
14326 {
14327   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14328 }
14329
14330 static gboolean
14331 gtk_tree_view_search_delete_event (GtkWidget *widget,
14332                                    GdkEventAny *event,
14333                                    GtkTreeView *tree_view)
14334 {
14335   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14336
14337   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14338
14339   return TRUE;
14340 }
14341
14342 static gboolean
14343 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14344                                          GdkEventButton *event,
14345                                          GtkTreeView *tree_view)
14346 {
14347   GdkDevice *keyb_device;
14348
14349   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14350
14351   keyb_device = gdk_device_get_associated_device (event->device);
14352   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14353
14354   if (event->window == tree_view->priv->bin_window)
14355     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14356
14357   return TRUE;
14358 }
14359
14360 static gboolean
14361 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14362                                    GdkEventScroll *event,
14363                                    GtkTreeView *tree_view)
14364 {
14365   gboolean retval = FALSE;
14366
14367   if (event->direction == GDK_SCROLL_UP)
14368     {
14369       gtk_tree_view_search_move (widget, tree_view, TRUE);
14370       retval = TRUE;
14371     }
14372   else if (event->direction == GDK_SCROLL_DOWN)
14373     {
14374       gtk_tree_view_search_move (widget, tree_view, FALSE);
14375       retval = TRUE;
14376     }
14377
14378   /* renew the flush timeout */
14379   if (retval && tree_view->priv->typeselect_flush_timeout
14380       && !tree_view->priv->search_custom_entry_set)
14381     {
14382       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14383       tree_view->priv->typeselect_flush_timeout =
14384         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14385                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14386                        tree_view);
14387     }
14388
14389   return retval;
14390 }
14391
14392 static gboolean
14393 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14394                                       GdkEventKey *event,
14395                                       GtkTreeView *tree_view)
14396 {
14397   gboolean retval = FALSE;
14398
14399   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14400   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14401
14402   /* close window and cancel the search */
14403   if (!tree_view->priv->search_custom_entry_set
14404       && (event->keyval == GDK_KEY_Escape ||
14405           event->keyval == GDK_KEY_Tab ||
14406             event->keyval == GDK_KEY_KP_Tab ||
14407             event->keyval == GDK_KEY_ISO_Left_Tab))
14408     {
14409       gtk_tree_view_search_dialog_hide (widget, tree_view,
14410                                         gdk_event_get_device ((GdkEvent *) event));
14411       return TRUE;
14412     }
14413
14414   /* select previous matching iter */
14415   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
14416     {
14417       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14418         gtk_widget_error_bell (widget);
14419
14420       retval = TRUE;
14421     }
14422
14423   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14424       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14425     {
14426       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14427         gtk_widget_error_bell (widget);
14428
14429       retval = TRUE;
14430     }
14431
14432   /* select next matching iter */
14433   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
14434     {
14435       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14436         gtk_widget_error_bell (widget);
14437
14438       retval = TRUE;
14439     }
14440
14441   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14442       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14443     {
14444       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14445         gtk_widget_error_bell (widget);
14446
14447       retval = TRUE;
14448     }
14449
14450   /* renew the flush timeout */
14451   if (retval && tree_view->priv->typeselect_flush_timeout
14452       && !tree_view->priv->search_custom_entry_set)
14453     {
14454       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14455       tree_view->priv->typeselect_flush_timeout =
14456         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14457                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14458                        tree_view);
14459     }
14460
14461   return retval;
14462 }
14463
14464 /*  this function returns FALSE if there is a search string but
14465  *  nothing was found, and TRUE otherwise.
14466  */
14467 static gboolean
14468 gtk_tree_view_search_move (GtkWidget   *window,
14469                            GtkTreeView *tree_view,
14470                            gboolean     up)
14471 {
14472   gboolean ret;
14473   gint len;
14474   gint count = 0;
14475   const gchar *text;
14476   GtkTreeIter iter;
14477   GtkTreeModel *model;
14478   GtkTreeSelection *selection;
14479
14480   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14481
14482   g_return_val_if_fail (text != NULL, FALSE);
14483
14484   len = strlen (text);
14485
14486   if (up && tree_view->priv->selected_iter == 1)
14487     return strlen (text) < 1;
14488
14489   len = strlen (text);
14490
14491   if (len < 1)
14492     return TRUE;
14493
14494   model = gtk_tree_view_get_model (tree_view);
14495   selection = gtk_tree_view_get_selection (tree_view);
14496
14497   /* search */
14498   gtk_tree_selection_unselect_all (selection);
14499   if (!gtk_tree_model_get_iter_first (model, &iter))
14500     return TRUE;
14501
14502   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14503                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14504
14505   if (ret)
14506     {
14507       /* found */
14508       tree_view->priv->selected_iter += up?(-1):(1);
14509       return TRUE;
14510     }
14511   else
14512     {
14513       /* return to old iter */
14514       count = 0;
14515       gtk_tree_model_get_iter_first (model, &iter);
14516       gtk_tree_view_search_iter (model, selection,
14517                                  &iter, text,
14518                                  &count, tree_view->priv->selected_iter);
14519       return FALSE;
14520     }
14521 }
14522
14523 static gboolean
14524 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14525                                  gint          column,
14526                                  const gchar  *key,
14527                                  GtkTreeIter  *iter,
14528                                  gpointer      search_data)
14529 {
14530   gboolean retval = TRUE;
14531   const gchar *str;
14532   gchar *normalized_string;
14533   gchar *normalized_key;
14534   gchar *case_normalized_string = NULL;
14535   gchar *case_normalized_key = NULL;
14536   GValue value = {0,};
14537   GValue transformed = {0,};
14538
14539   gtk_tree_model_get_value (model, iter, column, &value);
14540
14541   g_value_init (&transformed, G_TYPE_STRING);
14542
14543   if (!g_value_transform (&value, &transformed))
14544     {
14545       g_value_unset (&value);
14546       return TRUE;
14547     }
14548
14549   g_value_unset (&value);
14550
14551   str = g_value_get_string (&transformed);
14552   if (!str)
14553     {
14554       g_value_unset (&transformed);
14555       return TRUE;
14556     }
14557
14558   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14559   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14560
14561   if (normalized_string && normalized_key)
14562     {
14563       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14564       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14565
14566       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14567         retval = FALSE;
14568     }
14569
14570   g_value_unset (&transformed);
14571   g_free (normalized_key);
14572   g_free (normalized_string);
14573   g_free (case_normalized_key);
14574   g_free (case_normalized_string);
14575
14576   return retval;
14577 }
14578
14579 static gboolean
14580 gtk_tree_view_search_iter (GtkTreeModel     *model,
14581                            GtkTreeSelection *selection,
14582                            GtkTreeIter      *iter,
14583                            const gchar      *text,
14584                            gint             *count,
14585                            gint              n)
14586 {
14587   GtkRBTree *tree = NULL;
14588   GtkRBNode *node = NULL;
14589   GtkTreePath *path;
14590
14591   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14592
14593   path = gtk_tree_model_get_path (model, iter);
14594   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14595
14596   do
14597     {
14598       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14599         {
14600           (*count)++;
14601           if (*count == n)
14602             {
14603               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14604                                             TRUE, 0.5, 0.0);
14605               gtk_tree_selection_select_iter (selection, iter);
14606               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14607
14608               if (path)
14609                 gtk_tree_path_free (path);
14610
14611               return TRUE;
14612             }
14613         }
14614
14615       if (node->children)
14616         {
14617           gboolean has_child;
14618           GtkTreeIter tmp;
14619
14620           tree = node->children;
14621           node = tree->root;
14622
14623           while (node->left != tree->nil)
14624             node = node->left;
14625
14626           tmp = *iter;
14627           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14628           gtk_tree_path_down (path);
14629
14630           /* sanity check */
14631           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14632         }
14633       else
14634         {
14635           gboolean done = FALSE;
14636
14637           do
14638             {
14639               node = _gtk_rbtree_next (tree, node);
14640
14641               if (node)
14642                 {
14643                   gboolean has_next;
14644
14645                   has_next = gtk_tree_model_iter_next (model, iter);
14646
14647                   done = TRUE;
14648                   gtk_tree_path_next (path);
14649
14650                   /* sanity check */
14651                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14652                 }
14653               else
14654                 {
14655                   gboolean has_parent;
14656                   GtkTreeIter tmp_iter = *iter;
14657
14658                   node = tree->parent_node;
14659                   tree = tree->parent_tree;
14660
14661                   if (!tree)
14662                     {
14663                       if (path)
14664                         gtk_tree_path_free (path);
14665
14666                       /* we've run out of tree, done with this func */
14667                       return FALSE;
14668                     }
14669
14670                   has_parent = gtk_tree_model_iter_parent (model,
14671                                                            iter,
14672                                                            &tmp_iter);
14673                   gtk_tree_path_up (path);
14674
14675                   /* sanity check */
14676                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14677                 }
14678             }
14679           while (!done);
14680         }
14681     }
14682   while (1);
14683
14684   return FALSE;
14685 }
14686
14687 static void
14688 gtk_tree_view_search_init (GtkWidget   *entry,
14689                            GtkTreeView *tree_view)
14690 {
14691   gint ret;
14692   gint count = 0;
14693   const gchar *text;
14694   GtkTreeIter iter;
14695   GtkTreeModel *model;
14696   GtkTreeSelection *selection;
14697
14698   g_return_if_fail (GTK_IS_ENTRY (entry));
14699   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14700
14701   text = gtk_entry_get_text (GTK_ENTRY (entry));
14702
14703   model = gtk_tree_view_get_model (tree_view);
14704   selection = gtk_tree_view_get_selection (tree_view);
14705
14706   /* search */
14707   gtk_tree_selection_unselect_all (selection);
14708   if (tree_view->priv->typeselect_flush_timeout
14709       && !tree_view->priv->search_custom_entry_set)
14710     {
14711       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14712       tree_view->priv->typeselect_flush_timeout =
14713         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14714                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14715                        tree_view);
14716     }
14717
14718   if (*text == '\0')
14719     return;
14720
14721   if (!gtk_tree_model_get_iter_first (model, &iter))
14722     return;
14723
14724   ret = gtk_tree_view_search_iter (model, selection,
14725                                    &iter, text,
14726                                    &count, 1);
14727
14728   if (ret)
14729     tree_view->priv->selected_iter = 1;
14730 }
14731
14732 static void
14733 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14734                              GtkTreeView     *tree_view)
14735 {
14736   if (tree_view->priv->edited_column == NULL)
14737     return;
14738
14739   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14740   tree_view->priv->edited_column = NULL;
14741
14742   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
14743     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14744
14745   g_signal_handlers_disconnect_by_func (cell_editable,
14746                                         gtk_tree_view_remove_widget,
14747                                         tree_view);
14748
14749   gtk_container_remove (GTK_CONTAINER (tree_view),
14750                         GTK_WIDGET (cell_editable));  
14751
14752   /* FIXME should only redraw a single node */
14753   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14754 }
14755
14756 static gboolean
14757 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14758                              GtkTreePath *cursor_path)
14759 {
14760   GtkTreeIter iter;
14761   GdkRectangle background_area;
14762   GdkRectangle cell_area;
14763   GtkCellEditable *editable_widget = NULL;
14764   gchar *path_string;
14765   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14766   gint retval = FALSE;
14767   GtkRBTree *cursor_tree;
14768   GtkRBNode *cursor_node;
14769
14770   g_assert (tree_view->priv->focus_column);
14771
14772   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
14773     return FALSE;
14774
14775   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14776       cursor_node == NULL)
14777     return FALSE;
14778
14779   path_string = gtk_tree_path_to_string (cursor_path);
14780   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14781
14782   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14783
14784   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14785                                            tree_view->priv->model,
14786                                            &iter,
14787                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14788                                            cursor_node->children?TRUE:FALSE);
14789   gtk_tree_view_get_background_area (tree_view,
14790                                      cursor_path,
14791                                      tree_view->priv->focus_column,
14792                                      &background_area);
14793   gtk_tree_view_get_cell_area (tree_view,
14794                                cursor_path,
14795                                tree_view->priv->focus_column,
14796                                &cell_area);
14797
14798   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14799                                         &editable_widget,
14800                                         NULL,
14801                                         path_string,
14802                                         &background_area,
14803                                         &cell_area,
14804                                         flags))
14805     {
14806       retval = TRUE;
14807       if (editable_widget != NULL)
14808         {
14809           gint left, right;
14810           GdkRectangle area;
14811           GtkCellRenderer *cell;
14812
14813           area = cell_area;
14814           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14815
14816           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14817
14818           area.x += left;
14819           area.width -= right + left;
14820
14821           gtk_tree_view_real_start_editing (tree_view,
14822                                             tree_view->priv->focus_column,
14823                                             cursor_path,
14824                                             editable_widget,
14825                                             &area,
14826                                             NULL,
14827                                             flags);
14828         }
14829
14830     }
14831   g_free (path_string);
14832   return retval;
14833 }
14834
14835 static void
14836 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14837                                   GtkTreeViewColumn *column,
14838                                   GtkTreePath       *path,
14839                                   GtkCellEditable   *cell_editable,
14840                                   GdkRectangle      *cell_area,
14841                                   GdkEvent          *event,
14842                                   guint              flags)
14843 {
14844   gint pre_val = tree_view->priv->vadjustment->value;
14845   GtkRequisition requisition;
14846
14847   tree_view->priv->edited_column = column;
14848   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14849
14850   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14851   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14852
14853   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
14854                                  &requisition, NULL);
14855
14856   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14857
14858   if (requisition.height < cell_area->height)
14859     {
14860       gint diff = cell_area->height - requisition.height;
14861       gtk_tree_view_put (tree_view,
14862                          GTK_WIDGET (cell_editable),
14863                          cell_area->x, cell_area->y + diff/2,
14864                          cell_area->width, requisition.height);
14865     }
14866   else
14867     {
14868       gtk_tree_view_put (tree_view,
14869                          GTK_WIDGET (cell_editable),
14870                          cell_area->x, cell_area->y,
14871                          cell_area->width, cell_area->height);
14872     }
14873
14874   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14875                                    (GdkEvent *)event);
14876
14877   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14878   g_signal_connect (cell_editable, "remove-widget",
14879                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14880 }
14881
14882 static void
14883 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14884                             gboolean     cancel_editing)
14885 {
14886   GtkTreeViewColumn *column;
14887   GtkCellRenderer *cell;
14888
14889   if (tree_view->priv->edited_column == NULL)
14890     return;
14891
14892   /*
14893    * This is very evil. We need to do this, because
14894    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14895    * later on. If gtk_tree_view_row_changed notices
14896    * tree_view->priv->edited_column != NULL, it'll call
14897    * gtk_tree_view_stop_editing again. Bad things will happen then.
14898    *
14899    * Please read that again if you intend to modify anything here.
14900    */
14901
14902   column = tree_view->priv->edited_column;
14903   tree_view->priv->edited_column = NULL;
14904
14905   cell = _gtk_tree_view_column_get_edited_cell (column);
14906   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14907
14908   if (!cancel_editing)
14909     gtk_cell_editable_editing_done (column->editable_widget);
14910
14911   tree_view->priv->edited_column = column;
14912
14913   gtk_cell_editable_remove_widget (column->editable_widget);
14914 }
14915
14916
14917 /**
14918  * gtk_tree_view_set_hover_selection:
14919  * @tree_view: a #GtkTreeView
14920  * @hover: %TRUE to enable hover selection mode
14921  *
14922  * Enables of disables the hover selection mode of @tree_view.
14923  * Hover selection makes the selected row follow the pointer.
14924  * Currently, this works only for the selection modes 
14925  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14926  * 
14927  * Since: 2.6
14928  **/
14929 void     
14930 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14931                                    gboolean     hover)
14932 {
14933   hover = hover != FALSE;
14934
14935   if (hover != tree_view->priv->hover_selection)
14936     {
14937       tree_view->priv->hover_selection = hover;
14938
14939       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14940     }
14941 }
14942
14943 /**
14944  * gtk_tree_view_get_hover_selection:
14945  * @tree_view: a #GtkTreeView
14946  * 
14947  * Returns whether hover selection mode is turned on for @tree_view.
14948  * 
14949  * Return value: %TRUE if @tree_view is in hover selection mode
14950  *
14951  * Since: 2.6 
14952  **/
14953 gboolean 
14954 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14955 {
14956   return tree_view->priv->hover_selection;
14957 }
14958
14959 /**
14960  * gtk_tree_view_set_hover_expand:
14961  * @tree_view: a #GtkTreeView
14962  * @expand: %TRUE to enable hover selection mode
14963  *
14964  * Enables of disables the hover expansion mode of @tree_view.
14965  * Hover expansion makes rows expand or collapse if the pointer 
14966  * moves over them.
14967  * 
14968  * Since: 2.6
14969  **/
14970 void     
14971 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14972                                 gboolean     expand)
14973 {
14974   expand = expand != FALSE;
14975
14976   if (expand != tree_view->priv->hover_expand)
14977     {
14978       tree_view->priv->hover_expand = expand;
14979
14980       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14981     }
14982 }
14983
14984 /**
14985  * gtk_tree_view_get_hover_expand:
14986  * @tree_view: a #GtkTreeView
14987  * 
14988  * Returns whether hover expansion mode is turned on for @tree_view.
14989  * 
14990  * Return value: %TRUE if @tree_view is in hover expansion mode
14991  *
14992  * Since: 2.6 
14993  **/
14994 gboolean 
14995 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14996 {
14997   return tree_view->priv->hover_expand;
14998 }
14999
15000 /**
15001  * gtk_tree_view_set_rubber_banding:
15002  * @tree_view: a #GtkTreeView
15003  * @enable: %TRUE to enable rubber banding
15004  *
15005  * Enables or disables rubber banding in @tree_view.  If the selection mode
15006  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15007  * multiple rows by dragging the mouse.
15008  * 
15009  * Since: 2.10
15010  **/
15011 void
15012 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15013                                   gboolean     enable)
15014 {
15015   enable = enable != FALSE;
15016
15017   if (enable != tree_view->priv->rubber_banding_enable)
15018     {
15019       tree_view->priv->rubber_banding_enable = enable;
15020
15021       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15022     }
15023 }
15024
15025 /**
15026  * gtk_tree_view_get_rubber_banding:
15027  * @tree_view: a #GtkTreeView
15028  * 
15029  * Returns whether rubber banding is turned on for @tree_view.  If the
15030  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15031  * user to select multiple rows by dragging the mouse.
15032  * 
15033  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15034  *
15035  * Since: 2.10
15036  **/
15037 gboolean
15038 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15039 {
15040   return tree_view->priv->rubber_banding_enable;
15041 }
15042
15043 /**
15044  * gtk_tree_view_is_rubber_banding_active:
15045  * @tree_view: a #GtkTreeView
15046  * 
15047  * Returns whether a rubber banding operation is currently being done
15048  * in @tree_view.
15049  *
15050  * Return value: %TRUE if a rubber banding operation is currently being
15051  * done in @tree_view.
15052  *
15053  * Since: 2.12
15054  **/
15055 gboolean
15056 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15057 {
15058   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15059
15060   if (tree_view->priv->rubber_banding_enable
15061       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15062     return TRUE;
15063
15064   return FALSE;
15065 }
15066
15067 /**
15068  * gtk_tree_view_get_row_separator_func:
15069  * @tree_view: a #GtkTreeView
15070  * 
15071  * Returns the current row separator function.
15072  * 
15073  * Return value: the current row separator function.
15074  *
15075  * Since: 2.6
15076  **/
15077 GtkTreeViewRowSeparatorFunc 
15078 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15079 {
15080   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15081
15082   return tree_view->priv->row_separator_func;
15083 }
15084
15085 /**
15086  * gtk_tree_view_set_row_separator_func:
15087  * @tree_view: a #GtkTreeView
15088  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15089  * @data: (allow-none): user data to pass to @func, or %NULL
15090  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15091  * 
15092  * Sets the row separator function, which is used to determine
15093  * whether a row should be drawn as a separator. If the row separator
15094  * function is %NULL, no separators are drawn. This is the default value.
15095  *
15096  * Since: 2.6
15097  **/
15098 void
15099 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15100                                       GtkTreeViewRowSeparatorFunc  func,
15101                                       gpointer                     data,
15102                                       GDestroyNotify               destroy)
15103 {
15104   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15105
15106   if (tree_view->priv->row_separator_destroy)
15107     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15108
15109   tree_view->priv->row_separator_func = func;
15110   tree_view->priv->row_separator_data = data;
15111   tree_view->priv->row_separator_destroy = destroy;
15112
15113   /* Have the tree recalculate heights */
15114   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15115   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15116 }
15117
15118   
15119 static void
15120 gtk_tree_view_grab_notify (GtkWidget *widget,
15121                            gboolean   was_grabbed)
15122 {
15123   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15124
15125   tree_view->priv->in_grab = !was_grabbed;
15126
15127   if (!was_grabbed)
15128     {
15129       tree_view->priv->pressed_button = -1;
15130
15131       if (tree_view->priv->rubber_band_status)
15132         gtk_tree_view_stop_rubber_band (tree_view);
15133     }
15134 }
15135
15136 static void
15137 gtk_tree_view_state_changed (GtkWidget      *widget,
15138                              GtkStateType    previous_state)
15139 {
15140   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15141
15142   if (gtk_widget_get_realized (widget))
15143     {
15144       gdk_window_set_background (tree_view->priv->bin_window,
15145                                  &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
15146     }
15147
15148   gtk_widget_queue_draw (widget);
15149 }
15150
15151 /**
15152  * gtk_tree_view_get_grid_lines:
15153  * @tree_view: a #GtkTreeView
15154  *
15155  * Returns which grid lines are enabled in @tree_view.
15156  *
15157  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15158  * are enabled.
15159  *
15160  * Since: 2.10
15161  */
15162 GtkTreeViewGridLines
15163 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15164 {
15165   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15166
15167   return tree_view->priv->grid_lines;
15168 }
15169
15170 /**
15171  * gtk_tree_view_set_grid_lines:
15172  * @tree_view: a #GtkTreeView
15173  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15174  * enable.
15175  *
15176  * Sets which grid lines to draw in @tree_view.
15177  *
15178  * Since: 2.10
15179  */
15180 void
15181 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15182                               GtkTreeViewGridLines   grid_lines)
15183 {
15184   GtkTreeViewPrivate *priv;
15185   GtkWidget *widget;
15186   GtkTreeViewGridLines old_grid_lines;
15187
15188   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15189
15190   priv = tree_view->priv;
15191   widget = GTK_WIDGET (tree_view);
15192
15193   old_grid_lines = priv->grid_lines;
15194   priv->grid_lines = grid_lines;
15195   
15196   if (gtk_widget_get_realized (widget))
15197     {
15198       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15199           priv->grid_line_width)
15200         {
15201           priv->grid_line_width = 0;
15202         }
15203       
15204       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15205           !priv->grid_line_width)
15206         {
15207           gint8 *dash_list;
15208
15209           gtk_widget_style_get (widget,
15210                                 "grid-line-width", &priv->grid_line_width,
15211                                 "grid-line-pattern", (gchar *)&dash_list,
15212                                 NULL);
15213       
15214           if (dash_list)
15215             {
15216               priv->grid_line_dashes[0] = dash_list[0];
15217               if (dash_list[0])
15218                 priv->grid_line_dashes[1] = dash_list[1];
15219               
15220               g_free (dash_list);
15221             }
15222           else
15223             {
15224               priv->grid_line_dashes[0] = 1;
15225               priv->grid_line_dashes[1] = 1;
15226             }
15227         }      
15228     }
15229
15230   if (old_grid_lines != grid_lines)
15231     {
15232       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15233       
15234       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15235     }
15236 }
15237
15238 /**
15239  * gtk_tree_view_get_enable_tree_lines:
15240  * @tree_view: a #GtkTreeView.
15241  *
15242  * Returns whether or not tree lines are drawn in @tree_view.
15243  *
15244  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15245  * otherwise.
15246  *
15247  * Since: 2.10
15248  */
15249 gboolean
15250 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15251 {
15252   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15253
15254   return tree_view->priv->tree_lines_enabled;
15255 }
15256
15257 /**
15258  * gtk_tree_view_set_enable_tree_lines:
15259  * @tree_view: a #GtkTreeView
15260  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15261  *
15262  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15263  * This does not have any visible effects for lists.
15264  *
15265  * Since: 2.10
15266  */
15267 void
15268 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15269                                      gboolean     enabled)
15270 {
15271   GtkTreeViewPrivate *priv;
15272   GtkWidget *widget;
15273   gboolean was_enabled;
15274
15275   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15276
15277   enabled = enabled != FALSE;
15278
15279   priv = tree_view->priv;
15280   widget = GTK_WIDGET (tree_view);
15281
15282   was_enabled = priv->tree_lines_enabled;
15283
15284   priv->tree_lines_enabled = enabled;
15285
15286   if (gtk_widget_get_realized (widget))
15287     {
15288       if (!enabled && priv->tree_line_width)
15289         {
15290           priv->tree_line_width = 0;
15291         }
15292       
15293       if (enabled && !priv->tree_line_width)
15294         {
15295           gint8 *dash_list;
15296           gtk_widget_style_get (widget,
15297                                 "tree-line-width", &priv->tree_line_width,
15298                                 "tree-line-pattern", (gchar *)&dash_list,
15299                                 NULL);
15300           
15301           if (dash_list)
15302             {
15303               priv->tree_line_dashes[0] = dash_list[0];
15304               if (dash_list[0])
15305                 priv->tree_line_dashes[1] = dash_list[1];
15306               
15307               g_free (dash_list);
15308             }
15309           else
15310             {
15311               priv->tree_line_dashes[0] = 1;
15312               priv->tree_line_dashes[1] = 1;
15313             }
15314         }
15315     }
15316
15317   if (was_enabled != enabled)
15318     {
15319       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15320
15321       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15322     }
15323 }
15324
15325
15326 /**
15327  * gtk_tree_view_set_show_expanders:
15328  * @tree_view: a #GtkTreeView
15329  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15330  *
15331  * Sets whether to draw and enable expanders and indent child rows in
15332  * @tree_view.  When disabled there will be no expanders visible in trees
15333  * and there will be no way to expand and collapse rows by default.  Also
15334  * note that hiding the expanders will disable the default indentation.  You
15335  * can set a custom indentation in this case using
15336  * gtk_tree_view_set_level_indentation().
15337  * This does not have any visible effects for lists.
15338  *
15339  * Since: 2.12
15340  */
15341 void
15342 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15343                                   gboolean     enabled)
15344 {
15345   gboolean was_enabled;
15346
15347   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15348
15349   enabled = enabled != FALSE;
15350   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15351
15352   if (enabled)
15353     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15354   else
15355     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15356
15357   if (enabled != was_enabled)
15358     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15359 }
15360
15361 /**
15362  * gtk_tree_view_get_show_expanders:
15363  * @tree_view: a #GtkTreeView.
15364  *
15365  * Returns whether or not expanders are drawn in @tree_view.
15366  *
15367  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15368  * otherwise.
15369  *
15370  * Since: 2.12
15371  */
15372 gboolean
15373 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15374 {
15375   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15376
15377   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15378 }
15379
15380 /**
15381  * gtk_tree_view_set_level_indentation:
15382  * @tree_view: a #GtkTreeView
15383  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15384  *
15385  * Sets the amount of extra indentation for child levels to use in @tree_view
15386  * in addition to the default indentation.  The value should be specified in
15387  * pixels, a value of 0 disables this feature and in this case only the default
15388  * indentation will be used.
15389  * This does not have any visible effects for lists.
15390  *
15391  * Since: 2.12
15392  */
15393 void
15394 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15395                                      gint         indentation)
15396 {
15397   tree_view->priv->level_indentation = indentation;
15398
15399   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15400 }
15401
15402 /**
15403  * gtk_tree_view_get_level_indentation:
15404  * @tree_view: a #GtkTreeView.
15405  *
15406  * Returns the amount, in pixels, of extra indentation for child levels
15407  * in @tree_view.
15408  *
15409  * Return value: the amount of extra indentation for child levels in
15410  * @tree_view.  A return value of 0 means that this feature is disabled.
15411  *
15412  * Since: 2.12
15413  */
15414 gint
15415 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15416 {
15417   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15418
15419   return tree_view->priv->level_indentation;
15420 }
15421
15422 /**
15423  * gtk_tree_view_set_tooltip_row:
15424  * @tree_view: a #GtkTreeView
15425  * @tooltip: a #GtkTooltip
15426  * @path: a #GtkTreePath
15427  *
15428  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15429  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15430  * See also gtk_tooltip_set_tip_area().
15431  *
15432  * Since: 2.12
15433  */
15434 void
15435 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15436                                GtkTooltip  *tooltip,
15437                                GtkTreePath *path)
15438 {
15439   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15440   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15441
15442   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15443 }
15444
15445 /**
15446  * gtk_tree_view_set_tooltip_cell:
15447  * @tree_view: a #GtkTreeView
15448  * @tooltip: a #GtkTooltip
15449  * @path: (allow-none): a #GtkTreePath or %NULL
15450  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
15451  * @cell: (allow-none): a #GtkCellRenderer or %NULL
15452  *
15453  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15454  * in common.  For example if @path is %NULL and @column is set, the tip
15455  * area will be set to the full area covered by @column.  See also
15456  * gtk_tooltip_set_tip_area().
15457  *
15458  * Note that if @path is not specified and @cell is set and part of a column
15459  * containing the expander, the tooltip might not show and hide at the correct
15460  * position.  In such cases @path must be set to the current node under the
15461  * mouse cursor for this function to operate correctly.
15462  *
15463  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15464  *
15465  * Since: 2.12
15466  */
15467 void
15468 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15469                                 GtkTooltip        *tooltip,
15470                                 GtkTreePath       *path,
15471                                 GtkTreeViewColumn *column,
15472                                 GtkCellRenderer   *cell)
15473 {
15474   GtkAllocation allocation;
15475   GdkRectangle rect;
15476
15477   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15478   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15479   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15480   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15481
15482   /* Determine x values. */
15483   if (column && cell)
15484     {
15485       GdkRectangle tmp;
15486       gint start, width;
15487
15488       /* We always pass in path here, whether it is NULL or not.
15489        * For cells in expander columns path must be specified so that
15490        * we can correctly account for the indentation.  This also means
15491        * that the tooltip is constrained vertically by the "Determine y
15492        * values" code below; this is not a real problem since cells actually
15493        * don't stretch vertically in constrast to columns.
15494        */
15495       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15496       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15497
15498       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15499                                                          tmp.x + start, 0,
15500                                                          &rect.x, NULL);
15501       rect.width = width;
15502     }
15503   else if (column)
15504     {
15505       GdkRectangle tmp;
15506
15507       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15508       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15509                                                          tmp.x, 0,
15510                                                          &rect.x, NULL);
15511       rect.width = tmp.width;
15512     }
15513   else
15514     {
15515       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
15516       rect.x = 0;
15517       rect.width = allocation.width;
15518     }
15519
15520   /* Determine y values. */
15521   if (path)
15522     {
15523       GdkRectangle tmp;
15524
15525       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15526       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15527                                                          0, tmp.y,
15528                                                          NULL, &rect.y);
15529       rect.height = tmp.height;
15530     }
15531   else
15532     {
15533       rect.y = 0;
15534       rect.height = tree_view->priv->vadjustment->page_size;
15535     }
15536
15537   gtk_tooltip_set_tip_area (tooltip, &rect);
15538 }
15539
15540 /**
15541  * gtk_tree_view_get_tooltip_context:
15542  * @tree_view: a #GtkTreeView
15543  * @x: the x coordinate (relative to widget coordinates)
15544  * @y: the y coordinate (relative to widget coordinates)
15545  * @keyboard_tip: whether this is a keyboard tooltip or not
15546  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
15547  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
15548  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
15549  *
15550  * This function is supposed to be used in a #GtkWidget::query-tooltip
15551  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15552  * which are received in the signal handler, should be passed to this
15553  * function without modification.
15554  *
15555  * The return value indicates whether there is a tree view row at the given
15556  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15557  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15558  * @model, @path and @iter which have been provided will be set to point to
15559  * that row and the corresponding model.  @x and @y will always be converted
15560  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15561  *
15562  * Return value: whether or not the given tooltip context points to a row.
15563  *
15564  * Since: 2.12
15565  */
15566 gboolean
15567 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15568                                    gint          *x,
15569                                    gint          *y,
15570                                    gboolean       keyboard_tip,
15571                                    GtkTreeModel **model,
15572                                    GtkTreePath  **path,
15573                                    GtkTreeIter   *iter)
15574 {
15575   GtkTreePath *tmppath = NULL;
15576
15577   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15578   g_return_val_if_fail (x != NULL, FALSE);
15579   g_return_val_if_fail (y != NULL, FALSE);
15580
15581   if (keyboard_tip)
15582     {
15583       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15584
15585       if (!tmppath)
15586         return FALSE;
15587     }
15588   else
15589     {
15590       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15591                                                          x, y);
15592
15593       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15594                                           &tmppath, NULL, NULL, NULL))
15595         return FALSE;
15596     }
15597
15598   if (model)
15599     *model = gtk_tree_view_get_model (tree_view);
15600
15601   if (iter)
15602     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15603                              iter, tmppath);
15604
15605   if (path)
15606     *path = tmppath;
15607   else
15608     gtk_tree_path_free (tmppath);
15609
15610   return TRUE;
15611 }
15612
15613 static gboolean
15614 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15615                                     gint        x,
15616                                     gint        y,
15617                                     gboolean    keyboard_tip,
15618                                     GtkTooltip *tooltip,
15619                                     gpointer    data)
15620 {
15621   GValue value = { 0, };
15622   GValue transformed = { 0, };
15623   GtkTreeIter iter;
15624   GtkTreePath *path;
15625   GtkTreeModel *model;
15626   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15627
15628   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15629                                           &x, &y,
15630                                           keyboard_tip,
15631                                           &model, &path, &iter))
15632     return FALSE;
15633
15634   gtk_tree_model_get_value (model, &iter,
15635                             tree_view->priv->tooltip_column, &value);
15636
15637   g_value_init (&transformed, G_TYPE_STRING);
15638
15639   if (!g_value_transform (&value, &transformed))
15640     {
15641       g_value_unset (&value);
15642       gtk_tree_path_free (path);
15643
15644       return FALSE;
15645     }
15646
15647   g_value_unset (&value);
15648
15649   if (!g_value_get_string (&transformed))
15650     {
15651       g_value_unset (&transformed);
15652       gtk_tree_path_free (path);
15653
15654       return FALSE;
15655     }
15656
15657   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15658   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15659
15660   gtk_tree_path_free (path);
15661   g_value_unset (&transformed);
15662
15663   return TRUE;
15664 }
15665
15666 /**
15667  * gtk_tree_view_set_tooltip_column:
15668  * @tree_view: a #GtkTreeView
15669  * @column: an integer, which is a valid column number for @tree_view's model
15670  *
15671  * If you only plan to have simple (text-only) tooltips on full rows, you
15672  * can use this function to have #GtkTreeView handle these automatically
15673  * for you. @column should be set to the column in @tree_view's model
15674  * containing the tooltip texts, or -1 to disable this feature.
15675  *
15676  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15677  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15678  *
15679  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15680  * so &amp;, &lt;, etc have to be escaped in the text.
15681  *
15682  * Since: 2.12
15683  */
15684 void
15685 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15686                                   gint         column)
15687 {
15688   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15689
15690   if (column == tree_view->priv->tooltip_column)
15691     return;
15692
15693   if (column == -1)
15694     {
15695       g_signal_handlers_disconnect_by_func (tree_view,
15696                                             gtk_tree_view_set_tooltip_query_cb,
15697                                             NULL);
15698       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15699     }
15700   else
15701     {
15702       if (tree_view->priv->tooltip_column == -1)
15703         {
15704           g_signal_connect (tree_view, "query-tooltip",
15705                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15706           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15707         }
15708     }
15709
15710   tree_view->priv->tooltip_column = column;
15711   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15712 }
15713
15714 /**
15715  * gtk_tree_view_get_tooltip_column:
15716  * @tree_view: a #GtkTreeView
15717  *
15718  * Returns the column of @tree_view's model which is being used for
15719  * displaying tooltips on @tree_view's rows.
15720  *
15721  * Return value: the index of the tooltip column that is currently being
15722  * used, or -1 if this is disabled.
15723  *
15724  * Since: 2.12
15725  */
15726 gint
15727 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15728 {
15729   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15730
15731   return tree_view->priv->tooltip_column;
15732 }