]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Bug 588943 – set correct selection before emitting cursor-changed when searching
[~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 <string.h>
23 #include <gdk/gdkkeysyms.h>
24
25 #include "gtktreeview.h"
26 #include "gtkrbtree.h"
27 #include "gtktreednd.h"
28 #include "gtktreeprivate.h"
29 #include "gtkcellrenderer.h"
30 #include "gtkmain.h"
31 #include "gtkmarshalers.h"
32 #include "gtkbuildable.h"
33 #include "gtkbutton.h"
34 #include "gtkalignment.h"
35 #include "gtklabel.h"
36 #include "gtkhbox.h"
37 #include "gtkvbox.h"
38 #include "gtkarrow.h"
39 #include "gtkintl.h"
40 #include "gtkbindings.h"
41 #include "gtkcontainer.h"
42 #include "gtkentry.h"
43 #include "gtkframe.h"
44 #include "gtktreemodelsort.h"
45 #include "gtktooltip.h"
46 #include "gtkprivate.h"
47 #include "gtkalias.h"
48
49 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
50 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
51 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
52 #define SCROLL_EDGE_SIZE 15
53 #define EXPANDER_EXTRA_PADDING 4
54 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
55 #define AUTO_EXPAND_TIMEOUT 500
56
57 /* The "background" areas of all rows/cells add up to cover the entire tree.
58  * The background includes all inter-row and inter-cell spacing.
59  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
60  * i.e. just the cells, no spacing.
61  */
62
63 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
64 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
65
66 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
67  * vice versa.
68  */
69 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
70 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
71
72 /* This is in bin_window coordinates */
73 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
74 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
75
76 #define ROW_HEIGHT(tree_view,height) \
77   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
78
79
80 typedef struct _GtkTreeViewChild GtkTreeViewChild;
81 struct _GtkTreeViewChild
82 {
83   GtkWidget *widget;
84   gint x;
85   gint y;
86   gint width;
87   gint height;
88 };
89
90
91 typedef struct _TreeViewDragInfo TreeViewDragInfo;
92 struct _TreeViewDragInfo
93 {
94   GdkModifierType start_button_mask;
95   GtkTargetList *_unused_source_target_list;
96   GdkDragAction source_actions;
97
98   GtkTargetList *_unused_dest_target_list;
99
100   guint source_set : 1;
101   guint dest_set : 1;
102 };
103
104
105 /* Signals */
106 enum
107 {
108   ROW_ACTIVATED,
109   TEST_EXPAND_ROW,
110   TEST_COLLAPSE_ROW,
111   ROW_EXPANDED,
112   ROW_COLLAPSED,
113   COLUMNS_CHANGED,
114   CURSOR_CHANGED,
115   MOVE_CURSOR,
116   SELECT_ALL,
117   UNSELECT_ALL,
118   SELECT_CURSOR_ROW,
119   TOGGLE_CURSOR_ROW,
120   EXPAND_COLLAPSE_CURSOR_ROW,
121   SELECT_CURSOR_PARENT,
122   START_INTERACTIVE_SEARCH,
123   LAST_SIGNAL
124 };
125
126 /* Properties */
127 enum {
128   PROP_0,
129   PROP_MODEL,
130   PROP_HADJUSTMENT,
131   PROP_VADJUSTMENT,
132   PROP_HEADERS_VISIBLE,
133   PROP_HEADERS_CLICKABLE,
134   PROP_EXPANDER_COLUMN,
135   PROP_REORDERABLE,
136   PROP_RULES_HINT,
137   PROP_ENABLE_SEARCH,
138   PROP_SEARCH_COLUMN,
139   PROP_FIXED_HEIGHT_MODE,
140   PROP_HOVER_SELECTION,
141   PROP_HOVER_EXPAND,
142   PROP_SHOW_EXPANDERS,
143   PROP_LEVEL_INDENTATION,
144   PROP_RUBBER_BANDING,
145   PROP_ENABLE_GRID_LINES,
146   PROP_ENABLE_TREE_LINES,
147   PROP_TOOLTIP_COLUMN
148 };
149
150 /* object signals */
151 static void     gtk_tree_view_finalize             (GObject          *object);
152 static void     gtk_tree_view_set_property         (GObject         *object,
153                                                     guint            prop_id,
154                                                     const GValue    *value,
155                                                     GParamSpec      *pspec);
156 static void     gtk_tree_view_get_property         (GObject         *object,
157                                                     guint            prop_id,
158                                                     GValue          *value,
159                                                     GParamSpec      *pspec);
160
161 /* gtkobject signals */
162 static void     gtk_tree_view_destroy              (GtkObject        *object);
163
164 /* gtkwidget signals */
165 static void     gtk_tree_view_realize              (GtkWidget        *widget);
166 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
167 static void     gtk_tree_view_map                  (GtkWidget        *widget);
168 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
169                                                     GtkRequisition   *requisition);
170 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
171                                                     GtkAllocation    *allocation);
172 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
173                                                     GdkEventExpose   *event);
174 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
175                                                     GdkEventKey      *event);
176 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
177                                                     GdkEventKey      *event);
178 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
179                                                     GdkEventMotion   *event);
180 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
181                                                     GdkEventCrossing *event);
182 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
183                                                     GdkEventCrossing *event);
184 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
185                                                     GdkEventButton   *event);
186 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
187                                                     GdkEventButton   *event);
188 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
189                                                     GdkEventGrabBroken *event);
190 #if 0
191 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
192                                                     GdkEventConfigure *event);
193 #endif
194
195 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
196                                                     GtkWidget        *child);
197 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
198                                                     GdkEventFocus    *event);
199 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
200                                                     GtkDirectionType  direction);
201 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
202 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
203                                                     GtkStyle         *previous_style);
204 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
205                                                     gboolean          was_grabbed);
206 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
207                                                     GtkStateType      previous_state);
208
209 /* container signals */
210 static void     gtk_tree_view_remove               (GtkContainer     *container,
211                                                     GtkWidget        *widget);
212 static void     gtk_tree_view_forall               (GtkContainer     *container,
213                                                     gboolean          include_internals,
214                                                     GtkCallback       callback,
215                                                     gpointer          callback_data);
216
217 /* Source side drag signals */
218 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
219                                             GdkDragContext   *context);
220 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
221                                             GdkDragContext   *context);
222 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
223                                             GdkDragContext   *context,
224                                             GtkSelectionData *selection_data,
225                                             guint             info,
226                                             guint             time);
227 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
228                                             GdkDragContext   *context);
229
230 /* Target side drag signals */
231 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
232                                                   GdkDragContext   *context,
233                                                   guint             time);
234 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
235                                                   GdkDragContext   *context,
236                                                   gint              x,
237                                                   gint              y,
238                                                   guint             time);
239 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
240                                                   GdkDragContext   *context,
241                                                   gint              x,
242                                                   gint              y,
243                                                   guint             time);
244 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
245                                                   GdkDragContext   *context,
246                                                   gint              x,
247                                                   gint              y,
248                                                   GtkSelectionData *selection_data,
249                                                   guint             info,
250                                                   guint             time);
251
252 /* tree_model signals */
253 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
254                                                            GtkAdjustment   *hadj,
255                                                            GtkAdjustment   *vadj);
256 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
257                                                            GtkMovementStep  step,
258                                                            gint             count);
259 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
260 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
261 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
262                                                            gboolean         start_editing);
263 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
264 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
265                                                                gboolean         logical,
266                                                                gboolean         expand,
267                                                                gboolean         open_all);
268 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
269 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
270                                                            GtkTreePath     *path,
271                                                            GtkTreeIter     *iter,
272                                                            gpointer         data);
273 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
274                                                            GtkTreePath     *path,
275                                                            GtkTreeIter     *iter,
276                                                            gpointer         data);
277 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
278                                                            GtkTreePath     *path,
279                                                            GtkTreeIter     *iter,
280                                                            gpointer         data);
281 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
282                                                            GtkTreePath     *path,
283                                                            gpointer         data);
284 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
285                                                            GtkTreePath     *parent,
286                                                            GtkTreeIter     *iter,
287                                                            gint            *new_order,
288                                                            gpointer         data);
289
290 /* Incremental reflow */
291 static gboolean validate_row             (GtkTreeView *tree_view,
292                                           GtkRBTree   *tree,
293                                           GtkRBNode   *node,
294                                           GtkTreeIter *iter,
295                                           GtkTreePath *path);
296 static void     validate_visible_area    (GtkTreeView *tree_view);
297 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
298 static gboolean do_validate_rows         (GtkTreeView *tree_view,
299                                           gboolean     size_request);
300 static gboolean validate_rows            (GtkTreeView *tree_view);
301 static gboolean presize_handler_callback (gpointer     data);
302 static void     install_presize_handler  (GtkTreeView *tree_view);
303 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
304 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
305                                              GtkTreePath *path,
306                                              gint         offset);
307 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
308 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
309 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
310
311 /* Internal functions */
312 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
313                                                               GtkTreeViewColumn  *column);
314 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
315                                                               guint               keyval,
316                                                               guint               modmask,
317                                                               gboolean            add_shifted_binding,
318                                                               GtkMovementStep     step,
319                                                               gint                count);
320 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
321                                                               GtkRBTree          *tree);
322 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
323                                                               GtkTreePath        *path,
324                                                               const GdkRectangle *clip_rect);
325 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
326                                                               GtkRBTree          *tree,
327                                                               GtkRBNode          *node,
328                                                               const GdkRectangle *clip_rect);
329 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
330                                                               GtkRBTree          *tree,
331                                                               GtkRBNode          *node,
332                                                               gint                x,
333                                                               gint                y);
334 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
335                                                               GtkRBTree          *tree,
336                                                               gint               *x1,
337                                                               gint               *x2);
338 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
339                                                               gint                i,
340                                                               gint               *x);
341 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
342                                                               GtkTreeView        *tree_view);
343 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
344                                                               GtkRBTree          *tree,
345                                                               GtkTreeIter        *iter,
346                                                               gint                depth,
347                                                               gboolean            recurse);
348 static gboolean gtk_tree_view_discover_dirty_iter            (GtkTreeView        *tree_view,
349                                                               GtkTreeIter        *iter,
350                                                               gint                depth,
351                                                               gint               *height,
352                                                               GtkRBNode          *node);
353 static void     gtk_tree_view_discover_dirty                 (GtkTreeView        *tree_view,
354                                                               GtkRBTree          *tree,
355                                                               GtkTreeIter        *iter,
356                                                               gint                depth);
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
403 /* interactive search */
404 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
405 static void     gtk_tree_view_search_dialog_hide     (GtkWidget        *search_dialog,
406                                                          GtkTreeView      *tree_view);
407 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
408                                                          GtkWidget        *search_dialog,
409                                                          gpointer          user_data);
410 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
411                                                          GtkMenu          *menu,
412                                                          gpointer          data);
413 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
414                                                          GtkTreeView      *tree_view);
415 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
416                                                          GtkTreeView      *tree_view);
417 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
418 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
419                                                          gpointer          data);
420 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
421                                                          GdkEventAny      *event,
422                                                          GtkTreeView      *tree_view);
423 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
424                                                          GdkEventButton   *event,
425                                                          GtkTreeView      *tree_view);
426 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
427                                                          GdkEventScroll   *event,
428                                                          GtkTreeView      *tree_view);
429 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
430                                                          GdkEventKey      *event,
431                                                          GtkTreeView      *tree_view);
432 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
433                                                          GtkTreeView      *tree_view,
434                                                          gboolean          up);
435 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
436                                                          gint              column,
437                                                          const gchar      *key,
438                                                          GtkTreeIter      *iter,
439                                                          gpointer          search_data);
440 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
441                                                          GtkTreeSelection *selection,
442                                                          GtkTreeIter      *iter,
443                                                          const gchar      *text,
444                                                          gint             *count,
445                                                          gint              n);
446 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
447                                                          GtkTreeView      *tree_view);
448 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
449                                                          GtkWidget        *child_widget,
450                                                          gint              x,
451                                                          gint              y,
452                                                          gint              width,
453                                                          gint              height);
454 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
455                                                          GtkTreePath      *cursor_path);
456 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
457                                               GtkTreeViewColumn *column,
458                                               GtkTreePath       *path,
459                                               GtkCellEditable   *cell_editable,
460                                               GdkRectangle      *cell_area,
461                                               GdkEvent          *event,
462                                               guint              flags);
463 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
464                                                          gboolean     cancel_editing);
465 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
466                                                              gboolean     keybinding);
467 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
468 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
469                                                          GtkTreeViewColumn *column,
470                                                          gint               drop_position);
471
472 /* GtkBuildable */
473 static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
474                                                GtkBuilder  *builder,
475                                                GObject     *child,
476                                                const gchar *type);
477 static void gtk_tree_view_buildable_init      (GtkBuildableIface *iface);
478
479
480 static gboolean scroll_row_timeout                   (gpointer     data);
481 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
482 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
483
484 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
485
486 \f
487
488 /* GType Methods
489  */
490
491 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
492                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
493                                                 gtk_tree_view_buildable_init))
494
495 static void
496 gtk_tree_view_class_init (GtkTreeViewClass *class)
497 {
498   GObjectClass *o_class;
499   GtkObjectClass *object_class;
500   GtkWidgetClass *widget_class;
501   GtkContainerClass *container_class;
502   GtkBindingSet *binding_set;
503
504   binding_set = gtk_binding_set_by_class (class);
505
506   o_class = (GObjectClass *) class;
507   object_class = (GtkObjectClass *) class;
508   widget_class = (GtkWidgetClass *) class;
509   container_class = (GtkContainerClass *) class;
510
511   /* GObject signals */
512   o_class->set_property = gtk_tree_view_set_property;
513   o_class->get_property = gtk_tree_view_get_property;
514   o_class->finalize = gtk_tree_view_finalize;
515
516   /* GtkObject signals */
517   object_class->destroy = gtk_tree_view_destroy;
518
519   /* GtkWidget signals */
520   widget_class->map = gtk_tree_view_map;
521   widget_class->realize = gtk_tree_view_realize;
522   widget_class->unrealize = gtk_tree_view_unrealize;
523   widget_class->size_request = gtk_tree_view_size_request;
524   widget_class->size_allocate = gtk_tree_view_size_allocate;
525   widget_class->button_press_event = gtk_tree_view_button_press;
526   widget_class->button_release_event = gtk_tree_view_button_release;
527   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
528   /*widget_class->configure_event = gtk_tree_view_configure;*/
529   widget_class->motion_notify_event = gtk_tree_view_motion;
530   widget_class->expose_event = gtk_tree_view_expose;
531   widget_class->key_press_event = gtk_tree_view_key_press;
532   widget_class->key_release_event = gtk_tree_view_key_release;
533   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
534   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
535   widget_class->focus_out_event = gtk_tree_view_focus_out;
536   widget_class->drag_begin = gtk_tree_view_drag_begin;
537   widget_class->drag_end = gtk_tree_view_drag_end;
538   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
539   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
540   widget_class->drag_leave = gtk_tree_view_drag_leave;
541   widget_class->drag_motion = gtk_tree_view_drag_motion;
542   widget_class->drag_drop = gtk_tree_view_drag_drop;
543   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
544   widget_class->focus = gtk_tree_view_focus;
545   widget_class->grab_focus = gtk_tree_view_grab_focus;
546   widget_class->style_set = gtk_tree_view_style_set;
547   widget_class->grab_notify = gtk_tree_view_grab_notify;
548   widget_class->state_changed = gtk_tree_view_state_changed;
549
550   /* GtkContainer signals */
551   container_class->remove = gtk_tree_view_remove;
552   container_class->forall = gtk_tree_view_forall;
553   container_class->set_focus_child = gtk_tree_view_set_focus_child;
554
555   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
556   class->move_cursor = gtk_tree_view_real_move_cursor;
557   class->select_all = gtk_tree_view_real_select_all;
558   class->unselect_all = gtk_tree_view_real_unselect_all;
559   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
560   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
561   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
562   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
563   class->start_interactive_search = gtk_tree_view_start_interactive_search;
564
565   /* Properties */
566
567   g_object_class_install_property (o_class,
568                                    PROP_MODEL,
569                                    g_param_spec_object ("model",
570                                                         P_("TreeView Model"),
571                                                         P_("The model for the tree view"),
572                                                         GTK_TYPE_TREE_MODEL,
573                                                         GTK_PARAM_READWRITE));
574
575   g_object_class_install_property (o_class,
576                                    PROP_HADJUSTMENT,
577                                    g_param_spec_object ("hadjustment",
578                                                         P_("Horizontal Adjustment"),
579                                                         P_("Horizontal Adjustment for the widget"),
580                                                         GTK_TYPE_ADJUSTMENT,
581                                                         GTK_PARAM_READWRITE));
582
583   g_object_class_install_property (o_class,
584                                    PROP_VADJUSTMENT,
585                                    g_param_spec_object ("vadjustment",
586                                                         P_("Vertical Adjustment"),
587                                                         P_("Vertical Adjustment for the widget"),
588                                                         GTK_TYPE_ADJUSTMENT,
589                                                         GTK_PARAM_READWRITE));
590
591   g_object_class_install_property (o_class,
592                                    PROP_HEADERS_VISIBLE,
593                                    g_param_spec_boolean ("headers-visible",
594                                                          P_("Headers Visible"),
595                                                          P_("Show the column header buttons"),
596                                                          TRUE,
597                                                          GTK_PARAM_READWRITE));
598
599   g_object_class_install_property (o_class,
600                                    PROP_HEADERS_CLICKABLE,
601                                    g_param_spec_boolean ("headers-clickable",
602                                                          P_("Headers Clickable"),
603                                                          P_("Column headers respond to click events"),
604                                                          TRUE,
605                                                          GTK_PARAM_READWRITE));
606
607   g_object_class_install_property (o_class,
608                                    PROP_EXPANDER_COLUMN,
609                                    g_param_spec_object ("expander-column",
610                                                         P_("Expander Column"),
611                                                         P_("Set the column for the expander column"),
612                                                         GTK_TYPE_TREE_VIEW_COLUMN,
613                                                         GTK_PARAM_READWRITE));
614
615   g_object_class_install_property (o_class,
616                                    PROP_REORDERABLE,
617                                    g_param_spec_boolean ("reorderable",
618                                                          P_("Reorderable"),
619                                                          P_("View is reorderable"),
620                                                          FALSE,
621                                                          GTK_PARAM_READWRITE));
622
623   g_object_class_install_property (o_class,
624                                    PROP_RULES_HINT,
625                                    g_param_spec_boolean ("rules-hint",
626                                                          P_("Rules Hint"),
627                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
628                                                          FALSE,
629                                                          GTK_PARAM_READWRITE));
630
631     g_object_class_install_property (o_class,
632                                      PROP_ENABLE_SEARCH,
633                                      g_param_spec_boolean ("enable-search",
634                                                            P_("Enable Search"),
635                                                            P_("View allows user to search through columns interactively"),
636                                                            TRUE,
637                                                            GTK_PARAM_READWRITE));
638
639     g_object_class_install_property (o_class,
640                                      PROP_SEARCH_COLUMN,
641                                      g_param_spec_int ("search-column",
642                                                        P_("Search Column"),
643                                                        P_("Model column to search through during interactive search"),
644                                                        -1,
645                                                        G_MAXINT,
646                                                        -1,
647                                                        GTK_PARAM_READWRITE));
648
649     /**
650      * GtkTreeView:fixed-height-mode:
651      *
652      * Setting the ::fixed-height-mode property to %TRUE speeds up 
653      * #GtkTreeView by assuming that all rows have the same height. 
654      * Only enable this option if all rows are the same height.  
655      * Please see gtk_tree_view_set_fixed_height_mode() for more 
656      * information on this option.
657      *
658      * Since: 2.4
659      **/
660     g_object_class_install_property (o_class,
661                                      PROP_FIXED_HEIGHT_MODE,
662                                      g_param_spec_boolean ("fixed-height-mode",
663                                                            P_("Fixed Height Mode"),
664                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
665                                                            FALSE,
666                                                            GTK_PARAM_READWRITE));
667     
668     /**
669      * GtkTreeView:hover-selection:
670      * 
671      * Enables of disables the hover selection mode of @tree_view.
672      * Hover selection makes the selected row follow the pointer.
673      * Currently, this works only for the selection modes 
674      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
675      *
676      * This mode is primarily intended for treeviews in popups, e.g.
677      * in #GtkComboBox or #GtkEntryCompletion.
678      *
679      * Since: 2.6
680      */
681     g_object_class_install_property (o_class,
682                                      PROP_HOVER_SELECTION,
683                                      g_param_spec_boolean ("hover-selection",
684                                                            P_("Hover Selection"),
685                                                            P_("Whether the selection should follow the pointer"),
686                                                            FALSE,
687                                                            GTK_PARAM_READWRITE));
688
689     /**
690      * GtkTreeView:hover-expand:
691      * 
692      * Enables of disables the hover expansion mode of @tree_view.
693      * Hover expansion makes rows expand or collapse if the pointer moves 
694      * over them.
695      *
696      * This mode is primarily intended for treeviews in popups, e.g.
697      * in #GtkComboBox or #GtkEntryCompletion.
698      *
699      * Since: 2.6
700      */
701     g_object_class_install_property (o_class,
702                                      PROP_HOVER_EXPAND,
703                                      g_param_spec_boolean ("hover-expand",
704                                                            P_("Hover Expand"),
705                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
706                                                            FALSE,
707                                                            GTK_PARAM_READWRITE));
708
709     /**
710      * GtkTreeView:show-expanders:
711      *
712      * %TRUE if the view has expanders.
713      *
714      * Since: 2.12
715      */
716     g_object_class_install_property (o_class,
717                                      PROP_SHOW_EXPANDERS,
718                                      g_param_spec_boolean ("show-expanders",
719                                                            P_("Show Expanders"),
720                                                            P_("View has expanders"),
721                                                            TRUE,
722                                                            GTK_PARAM_READWRITE));
723
724     /**
725      * GtkTreeView:level-indentation:
726      *
727      * Extra indentation for each level.
728      *
729      * Since: 2.12
730      */
731     g_object_class_install_property (o_class,
732                                      PROP_LEVEL_INDENTATION,
733                                      g_param_spec_int ("level-indentation",
734                                                        P_("Level Indentation"),
735                                                        P_("Extra indentation for each level"),
736                                                        0,
737                                                        G_MAXINT,
738                                                        0,
739                                                        GTK_PARAM_READWRITE));
740
741     g_object_class_install_property (o_class,
742                                      PROP_RUBBER_BANDING,
743                                      g_param_spec_boolean ("rubber-banding",
744                                                            P_("Rubber Banding"),
745                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
746                                                            FALSE,
747                                                            GTK_PARAM_READWRITE));
748
749     g_object_class_install_property (o_class,
750                                      PROP_ENABLE_GRID_LINES,
751                                      g_param_spec_enum ("enable-grid-lines",
752                                                         P_("Enable Grid Lines"),
753                                                         P_("Whether grid lines should be drawn in the tree view"),
754                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
755                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
756                                                         GTK_PARAM_READWRITE));
757
758     g_object_class_install_property (o_class,
759                                      PROP_ENABLE_TREE_LINES,
760                                      g_param_spec_boolean ("enable-tree-lines",
761                                                            P_("Enable Tree Lines"),
762                                                            P_("Whether tree lines should be drawn in the tree view"),
763                                                            FALSE,
764                                                            GTK_PARAM_READWRITE));
765
766     g_object_class_install_property (o_class,
767                                      PROP_TOOLTIP_COLUMN,
768                                      g_param_spec_int ("tooltip-column",
769                                                        P_("Tooltip Column"),
770                                                        P_("The column in the model containing the tooltip texts for the rows"),
771                                                        -1,
772                                                        G_MAXINT,
773                                                        -1,
774                                                        GTK_PARAM_READWRITE));
775
776   /* Style properties */
777 #define _TREE_VIEW_EXPANDER_SIZE 12
778 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
779 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
780
781   gtk_widget_class_install_style_property (widget_class,
782                                            g_param_spec_int ("expander-size",
783                                                              P_("Expander Size"),
784                                                              P_("Size of the expander arrow"),
785                                                              0,
786                                                              G_MAXINT,
787                                                              _TREE_VIEW_EXPANDER_SIZE,
788                                                              GTK_PARAM_READABLE));
789
790   gtk_widget_class_install_style_property (widget_class,
791                                            g_param_spec_int ("vertical-separator",
792                                                              P_("Vertical Separator Width"),
793                                                              P_("Vertical space between cells.  Must be an even number"),
794                                                              0,
795                                                              G_MAXINT,
796                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
797                                                              GTK_PARAM_READABLE));
798
799   gtk_widget_class_install_style_property (widget_class,
800                                            g_param_spec_int ("horizontal-separator",
801                                                              P_("Horizontal Separator Width"),
802                                                              P_("Horizontal space between cells.  Must be an even number"),
803                                                              0,
804                                                              G_MAXINT,
805                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
806                                                              GTK_PARAM_READABLE));
807
808   gtk_widget_class_install_style_property (widget_class,
809                                            g_param_spec_boolean ("allow-rules",
810                                                                  P_("Allow Rules"),
811                                                                  P_("Allow drawing of alternating color rows"),
812                                                                  TRUE,
813                                                                  GTK_PARAM_READABLE));
814
815   gtk_widget_class_install_style_property (widget_class,
816                                            g_param_spec_boolean ("indent-expanders",
817                                                                  P_("Indent Expanders"),
818                                                                  P_("Make the expanders indented"),
819                                                                  TRUE,
820                                                                  GTK_PARAM_READABLE));
821
822   gtk_widget_class_install_style_property (widget_class,
823                                            g_param_spec_boxed ("even-row-color",
824                                                                P_("Even Row Color"),
825                                                                P_("Color to use for even rows"),
826                                                                GDK_TYPE_COLOR,
827                                                                GTK_PARAM_READABLE));
828
829   gtk_widget_class_install_style_property (widget_class,
830                                            g_param_spec_boxed ("odd-row-color",
831                                                                P_("Odd Row Color"),
832                                                                P_("Color to use for odd rows"),
833                                                                GDK_TYPE_COLOR,
834                                                                GTK_PARAM_READABLE));
835
836   gtk_widget_class_install_style_property (widget_class,
837                                            g_param_spec_boolean ("row-ending-details",
838                                                                  P_("Row Ending details"),
839                                                                  P_("Enable extended row background theming"),
840                                                                  FALSE,
841                                                                  GTK_PARAM_READABLE));
842
843   gtk_widget_class_install_style_property (widget_class,
844                                            g_param_spec_int ("grid-line-width",
845                                                              P_("Grid line width"),
846                                                              P_("Width, in pixels, of the tree view grid lines"),
847                                                              0, G_MAXINT, 1,
848                                                              GTK_PARAM_READABLE));
849
850   gtk_widget_class_install_style_property (widget_class,
851                                            g_param_spec_int ("tree-line-width",
852                                                              P_("Tree line width"),
853                                                              P_("Width, in pixels, of the tree view lines"),
854                                                              0, G_MAXINT, 1,
855                                                              GTK_PARAM_READABLE));
856
857   gtk_widget_class_install_style_property (widget_class,
858                                            g_param_spec_string ("grid-line-pattern",
859                                                                 P_("Grid line pattern"),
860                                                                 P_("Dash pattern used to draw the tree view grid lines"),
861                                                                 "\1\1",
862                                                                 GTK_PARAM_READABLE));
863
864   gtk_widget_class_install_style_property (widget_class,
865                                            g_param_spec_string ("tree-line-pattern",
866                                                                 P_("Tree line pattern"),
867                                                                 P_("Dash pattern used to draw the tree view lines"),
868                                                                 "\1\1",
869                                                                 GTK_PARAM_READABLE));
870
871   /* Signals */
872   /**
873    * GtkTreeView::set-scroll-adjustments
874    * @horizontal: the horizontal #GtkAdjustment
875    * @vertical: the vertical #GtkAdjustment
876    *
877    * Set the scroll adjustments for the tree view. Usually scrolled containers
878    * like #GtkScrolledWindow will emit this signal to connect two instances
879    * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
880    */
881   widget_class->set_scroll_adjustments_signal =
882     g_signal_new (I_("set-scroll-adjustments"),
883                   G_TYPE_FROM_CLASS (o_class),
884                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
885                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
886                   NULL, NULL,
887                   _gtk_marshal_VOID__OBJECT_OBJECT,
888                   G_TYPE_NONE, 2,
889                   GTK_TYPE_ADJUSTMENT,
890                   GTK_TYPE_ADJUSTMENT);
891
892   /**
893    * GtkTreeView::row-activated:
894    * @tree_view: the object on which the signal is emitted
895    * @path: the #GtkTreePath for the activated row
896    * @column: the #GtkTreeViewColumn in which the activation occurred
897    *
898    * The "row-activated" signal is emitted when the method
899    * gtk_tree_view_row_activated() is called or the user double clicks 
900    * a treeview row. It is also emitted when a non-editable row is 
901    * selected and one of the keys: Space, Shift+Space, Return or 
902    * Enter is pressed.
903    * 
904    * For selection handling refer to the <link linkend="TreeWidget">tree 
905    * widget conceptual overview</link> as well as #GtkTreeSelection.
906    */
907   tree_view_signals[ROW_ACTIVATED] =
908     g_signal_new (I_("row-activated"),
909                   G_TYPE_FROM_CLASS (o_class),
910                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
911                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
912                   NULL, NULL,
913                   _gtk_marshal_VOID__BOXED_OBJECT,
914                   G_TYPE_NONE, 2,
915                   GTK_TYPE_TREE_PATH,
916                   GTK_TYPE_TREE_VIEW_COLUMN);
917
918   /**
919    * GtkTreeView::test-expand-row:
920    * @tree_view: the object on which the signal is emitted
921    * @iter: the tree iter of the row to expand
922    * @path: a tree path that points to the row 
923    * 
924    * The given row is about to be expanded (show its children nodes). Use this
925    * signal if you need to control the expandability of individual rows.
926    *
927    * Returns: %FALSE to allow expansion, %TRUE to reject
928    */
929   tree_view_signals[TEST_EXPAND_ROW] =
930     g_signal_new (I_("test-expand-row"),
931                   G_TYPE_FROM_CLASS (o_class),
932                   G_SIGNAL_RUN_LAST,
933                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
934                   _gtk_boolean_handled_accumulator, NULL,
935                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
936                   G_TYPE_BOOLEAN, 2,
937                   GTK_TYPE_TREE_ITER,
938                   GTK_TYPE_TREE_PATH);
939
940   /**
941    * GtkTreeView::test-collapse-row:
942    * @tree_view: the object on which the signal is emitted
943    * @iter: the tree iter of the row to collapse
944    * @path: a tree path that points to the row 
945    * 
946    * The given row is about to be collapsed (hide its children nodes). Use this
947    * signal if you need to control the collapsibility of individual rows.
948    *
949    * Returns: %FALSE to allow collapsing, %TRUE to reject
950    */
951   tree_view_signals[TEST_COLLAPSE_ROW] =
952     g_signal_new (I_("test-collapse-row"),
953                   G_TYPE_FROM_CLASS (o_class),
954                   G_SIGNAL_RUN_LAST,
955                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
956                   _gtk_boolean_handled_accumulator, NULL,
957                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
958                   G_TYPE_BOOLEAN, 2,
959                   GTK_TYPE_TREE_ITER,
960                   GTK_TYPE_TREE_PATH);
961
962   /**
963    * GtkTreeView::row-expanded:
964    * @tree_view: the object on which the signal is emitted
965    * @iter: the tree iter of the expanded row
966    * @path: a tree path that points to the row 
967    * 
968    * The given row has been expanded (child nodes are shown).
969    */
970   tree_view_signals[ROW_EXPANDED] =
971     g_signal_new (I_("row-expanded"),
972                   G_TYPE_FROM_CLASS (o_class),
973                   G_SIGNAL_RUN_LAST,
974                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
975                   NULL, NULL,
976                   _gtk_marshal_VOID__BOXED_BOXED,
977                   G_TYPE_NONE, 2,
978                   GTK_TYPE_TREE_ITER,
979                   GTK_TYPE_TREE_PATH);
980
981   /**
982    * GtkTreeView::row-collapsed:
983    * @tree_view: the object on which the signal is emitted
984    * @iter: the tree iter of the collapsed row
985    * @path: a tree path that points to the row 
986    * 
987    * The given row has been collapsed (child nodes are hidden).
988    */
989   tree_view_signals[ROW_COLLAPSED] =
990     g_signal_new (I_("row-collapsed"),
991                   G_TYPE_FROM_CLASS (o_class),
992                   G_SIGNAL_RUN_LAST,
993                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
994                   NULL, NULL,
995                   _gtk_marshal_VOID__BOXED_BOXED,
996                   G_TYPE_NONE, 2,
997                   GTK_TYPE_TREE_ITER,
998                   GTK_TYPE_TREE_PATH);
999
1000   /**
1001    * GtkTreeView::columns-changed:
1002    * @tree_view: the object on which the signal is emitted 
1003    * 
1004    * The number of columns of the treeview has changed.
1005    */
1006   tree_view_signals[COLUMNS_CHANGED] =
1007     g_signal_new (I_("columns-changed"),
1008                   G_TYPE_FROM_CLASS (o_class),
1009                   G_SIGNAL_RUN_LAST,
1010                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1011                   NULL, NULL,
1012                   _gtk_marshal_VOID__VOID,
1013                   G_TYPE_NONE, 0);
1014
1015   /**
1016    * GtkTreeView::cursor-changed:
1017    * @tree_view: the object on which the signal is emitted
1018    * 
1019    * The position of the cursor (focused cell) has changed.
1020    */
1021   tree_view_signals[CURSOR_CHANGED] =
1022     g_signal_new (I_("cursor-changed"),
1023                   G_TYPE_FROM_CLASS (o_class),
1024                   G_SIGNAL_RUN_LAST,
1025                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1026                   NULL, NULL,
1027                   _gtk_marshal_VOID__VOID,
1028                   G_TYPE_NONE, 0);
1029
1030   tree_view_signals[MOVE_CURSOR] =
1031     g_signal_new (I_("move-cursor"),
1032                   G_TYPE_FROM_CLASS (object_class),
1033                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1034                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1035                   NULL, NULL,
1036                   _gtk_marshal_BOOLEAN__ENUM_INT,
1037                   G_TYPE_BOOLEAN, 2,
1038                   GTK_TYPE_MOVEMENT_STEP,
1039                   G_TYPE_INT);
1040
1041   tree_view_signals[SELECT_ALL] =
1042     g_signal_new (I_("select-all"),
1043                   G_TYPE_FROM_CLASS (object_class),
1044                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1045                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1046                   NULL, NULL,
1047                   _gtk_marshal_BOOLEAN__VOID,
1048                   G_TYPE_BOOLEAN, 0);
1049
1050   tree_view_signals[UNSELECT_ALL] =
1051     g_signal_new (I_("unselect-all"),
1052                   G_TYPE_FROM_CLASS (object_class),
1053                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1054                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1055                   NULL, NULL,
1056                   _gtk_marshal_BOOLEAN__VOID,
1057                   G_TYPE_BOOLEAN, 0);
1058
1059   tree_view_signals[SELECT_CURSOR_ROW] =
1060     g_signal_new (I_("select-cursor-row"),
1061                   G_TYPE_FROM_CLASS (object_class),
1062                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1063                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1064                   NULL, NULL,
1065                   _gtk_marshal_BOOLEAN__BOOLEAN,
1066                   G_TYPE_BOOLEAN, 1,
1067                   G_TYPE_BOOLEAN);
1068
1069   tree_view_signals[TOGGLE_CURSOR_ROW] =
1070     g_signal_new (I_("toggle-cursor-row"),
1071                   G_TYPE_FROM_CLASS (object_class),
1072                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1073                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1074                   NULL, NULL,
1075                   _gtk_marshal_BOOLEAN__VOID,
1076                   G_TYPE_BOOLEAN, 0);
1077
1078   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1079     g_signal_new (I_("expand-collapse-cursor-row"),
1080                   G_TYPE_FROM_CLASS (object_class),
1081                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1082                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1083                   NULL, NULL,
1084                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1085                   G_TYPE_BOOLEAN, 3,
1086                   G_TYPE_BOOLEAN,
1087                   G_TYPE_BOOLEAN,
1088                   G_TYPE_BOOLEAN);
1089
1090   tree_view_signals[SELECT_CURSOR_PARENT] =
1091     g_signal_new (I_("select-cursor-parent"),
1092                   G_TYPE_FROM_CLASS (object_class),
1093                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1094                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1095                   NULL, NULL,
1096                   _gtk_marshal_BOOLEAN__VOID,
1097                   G_TYPE_BOOLEAN, 0);
1098
1099   tree_view_signals[START_INTERACTIVE_SEARCH] =
1100     g_signal_new (I_("start-interactive-search"),
1101                   G_TYPE_FROM_CLASS (object_class),
1102                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1103                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1104                   NULL, NULL,
1105                   _gtk_marshal_BOOLEAN__VOID,
1106                   G_TYPE_BOOLEAN, 0);
1107
1108   /* Key bindings */
1109   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
1110                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1111   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
1112                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1113
1114   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
1115                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1116   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
1117                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1118
1119   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
1120                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1121
1122   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
1123                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1124
1125   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
1126                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1127   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
1128                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1129
1130   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
1131                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1132   gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
1133                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1134
1135   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
1136                                   GTK_MOVEMENT_PAGES, -1);
1137   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
1138                                   GTK_MOVEMENT_PAGES, -1);
1139
1140   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
1141                                   GTK_MOVEMENT_PAGES, 1);
1142   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
1143                                   GTK_MOVEMENT_PAGES, 1);
1144
1145
1146   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move-cursor", 2,
1147                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1148                                 G_TYPE_INT, 1);
1149
1150   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move-cursor", 2,
1151                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1152                                 G_TYPE_INT, -1);
1153
1154   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move-cursor", 2,
1155                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1156                                 G_TYPE_INT, 1);
1157
1158   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move-cursor", 2,
1159                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1160                                 G_TYPE_INT, -1);
1161
1162   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
1163                                 "move-cursor", 2,
1164                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1165                                 G_TYPE_INT, 1);
1166
1167   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
1168                                 "move-cursor", 2,
1169                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1170                                 G_TYPE_INT, -1);
1171
1172   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1173                                 "move-cursor", 2,
1174                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1175                                 G_TYPE_INT, 1);
1176
1177   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
1178                                 "move-cursor", 2,
1179                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1180                                 G_TYPE_INT, -1);
1181
1182   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1183   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1184
1185   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0);
1186   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
1187
1188   gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1189   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1190
1191   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1192                                 G_TYPE_BOOLEAN, TRUE);
1193   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1194                                 G_TYPE_BOOLEAN, TRUE);
1195
1196   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1,
1197                                 G_TYPE_BOOLEAN, TRUE);
1198   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1,
1199                                 G_TYPE_BOOLEAN, TRUE);
1200   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1,
1201                                 G_TYPE_BOOLEAN, TRUE);
1202   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1,
1203                                 G_TYPE_BOOLEAN, TRUE);
1204   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1,
1205                                 G_TYPE_BOOLEAN, TRUE);
1206
1207   /* expand and collapse rows */
1208   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand-collapse-cursor-row", 3,
1209                                 G_TYPE_BOOLEAN, TRUE,
1210                                 G_TYPE_BOOLEAN, TRUE,
1211                                 G_TYPE_BOOLEAN, FALSE);
1212
1213   gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
1214                                 "expand-collapse-cursor-row", 3,
1215                                 G_TYPE_BOOLEAN, TRUE,
1216                                 G_TYPE_BOOLEAN, TRUE,
1217                                 G_TYPE_BOOLEAN, TRUE);
1218   gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
1219                                 "expand-collapse-cursor-row", 3,
1220                                 G_TYPE_BOOLEAN, TRUE,
1221                                 G_TYPE_BOOLEAN, TRUE,
1222                                 G_TYPE_BOOLEAN, TRUE);
1223
1224   gtk_binding_entry_add_signal (binding_set, GDK_slash, 0,
1225                                 "expand-collapse-cursor-row", 3,
1226                                 G_TYPE_BOOLEAN, TRUE,
1227                                 G_TYPE_BOOLEAN, FALSE,
1228                                 G_TYPE_BOOLEAN, FALSE);
1229   gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
1230                                 "expand-collapse-cursor-row", 3,
1231                                 G_TYPE_BOOLEAN, TRUE,
1232                                 G_TYPE_BOOLEAN, FALSE,
1233                                 G_TYPE_BOOLEAN, FALSE);
1234
1235   /* Not doable on US keyboards */
1236   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1237                                 G_TYPE_BOOLEAN, TRUE,
1238                                 G_TYPE_BOOLEAN, TRUE,
1239                                 G_TYPE_BOOLEAN, TRUE);
1240   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand-collapse-cursor-row", 3,
1241                                 G_TYPE_BOOLEAN, TRUE,
1242                                 G_TYPE_BOOLEAN, TRUE,
1243                                 G_TYPE_BOOLEAN, FALSE);
1244   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1245                                 G_TYPE_BOOLEAN, TRUE,
1246                                 G_TYPE_BOOLEAN, TRUE,
1247                                 G_TYPE_BOOLEAN, TRUE);
1248   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1249                                 G_TYPE_BOOLEAN, TRUE,
1250                                 G_TYPE_BOOLEAN, TRUE,
1251                                 G_TYPE_BOOLEAN, TRUE);
1252   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
1253                                 "expand-collapse-cursor-row", 3,
1254                                 G_TYPE_BOOLEAN, FALSE,
1255                                 G_TYPE_BOOLEAN, TRUE,
1256                                 G_TYPE_BOOLEAN, TRUE);
1257   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
1258                                 "expand-collapse-cursor-row", 3,
1259                                 G_TYPE_BOOLEAN, FALSE,
1260                                 G_TYPE_BOOLEAN, TRUE,
1261                                 G_TYPE_BOOLEAN, TRUE);
1262   gtk_binding_entry_add_signal (binding_set, GDK_Right,
1263                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1264                                 "expand-collapse-cursor-row", 3,
1265                                 G_TYPE_BOOLEAN, FALSE,
1266                                 G_TYPE_BOOLEAN, TRUE,
1267                                 G_TYPE_BOOLEAN, TRUE);
1268   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
1269                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1270                                 "expand-collapse-cursor-row", 3,
1271                                 G_TYPE_BOOLEAN, FALSE,
1272                                 G_TYPE_BOOLEAN, TRUE,
1273                                 G_TYPE_BOOLEAN, TRUE);
1274
1275   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand-collapse-cursor-row", 3,
1276                                 G_TYPE_BOOLEAN, TRUE,
1277                                 G_TYPE_BOOLEAN, FALSE,
1278                                 G_TYPE_BOOLEAN, FALSE);
1279   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1280                                 G_TYPE_BOOLEAN, TRUE,
1281                                 G_TYPE_BOOLEAN, FALSE,
1282                                 G_TYPE_BOOLEAN, TRUE);
1283   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1284                                 G_TYPE_BOOLEAN, TRUE,
1285                                 G_TYPE_BOOLEAN, FALSE,
1286                                 G_TYPE_BOOLEAN, FALSE);
1287   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1288                                 G_TYPE_BOOLEAN, TRUE,
1289                                 G_TYPE_BOOLEAN, FALSE,
1290                                 G_TYPE_BOOLEAN, TRUE);
1291   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
1292                                 "expand-collapse-cursor-row", 3,
1293                                 G_TYPE_BOOLEAN, FALSE,
1294                                 G_TYPE_BOOLEAN, FALSE,
1295                                 G_TYPE_BOOLEAN, TRUE);
1296   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
1297                                 "expand-collapse-cursor-row", 3,
1298                                 G_TYPE_BOOLEAN, FALSE,
1299                                 G_TYPE_BOOLEAN, FALSE,
1300                                 G_TYPE_BOOLEAN, TRUE);
1301   gtk_binding_entry_add_signal (binding_set, GDK_Left,
1302                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1303                                 "expand-collapse-cursor-row", 3,
1304                                 G_TYPE_BOOLEAN, FALSE,
1305                                 G_TYPE_BOOLEAN, FALSE,
1306                                 G_TYPE_BOOLEAN, TRUE);
1307   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
1308                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1309                                 "expand-collapse-cursor-row", 3,
1310                                 G_TYPE_BOOLEAN, FALSE,
1311                                 G_TYPE_BOOLEAN, FALSE,
1312                                 G_TYPE_BOOLEAN, TRUE);
1313
1314   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0);
1315   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1316
1317   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1318
1319   gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1320
1321   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1322 }
1323
1324 static void
1325 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1326 {
1327   iface->add_child = gtk_tree_view_buildable_add_child;
1328 }
1329
1330 static void
1331 gtk_tree_view_init (GtkTreeView *tree_view)
1332 {
1333   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1334
1335   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
1336
1337   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1338
1339   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1340                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1341                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1342
1343   /* We need some padding */
1344   tree_view->priv->dy = 0;
1345   tree_view->priv->cursor_offset = 0;
1346   tree_view->priv->n_columns = 0;
1347   tree_view->priv->header_height = 1;
1348   tree_view->priv->x_drag = 0;
1349   tree_view->priv->drag_pos = -1;
1350   tree_view->priv->header_has_focus = FALSE;
1351   tree_view->priv->pressed_button = -1;
1352   tree_view->priv->press_start_x = -1;
1353   tree_view->priv->press_start_y = -1;
1354   tree_view->priv->reorderable = FALSE;
1355   tree_view->priv->presize_handler_timer = 0;
1356   tree_view->priv->scroll_sync_timer = 0;
1357   tree_view->priv->fixed_height = -1;
1358   tree_view->priv->fixed_height_mode = FALSE;
1359   tree_view->priv->fixed_height_check = 0;
1360   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1361   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1362   tree_view->priv->enable_search = TRUE;
1363   tree_view->priv->search_column = -1;
1364   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1365   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1366   tree_view->priv->search_custom_entry_set = FALSE;
1367   tree_view->priv->typeselect_flush_timeout = 0;
1368   tree_view->priv->init_hadjust_value = TRUE;    
1369   tree_view->priv->width = 0;
1370           
1371   tree_view->priv->hover_selection = FALSE;
1372   tree_view->priv->hover_expand = FALSE;
1373
1374   tree_view->priv->level_indentation = 0;
1375
1376   tree_view->priv->rubber_banding_enable = FALSE;
1377
1378   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1379   tree_view->priv->tree_lines_enabled = FALSE;
1380
1381   tree_view->priv->tooltip_column = -1;
1382
1383   tree_view->priv->post_validation_flag = FALSE;
1384 }
1385
1386 \f
1387
1388 /* GObject Methods
1389  */
1390
1391 static void
1392 gtk_tree_view_set_property (GObject         *object,
1393                             guint            prop_id,
1394                             const GValue    *value,
1395                             GParamSpec      *pspec)
1396 {
1397   GtkTreeView *tree_view;
1398
1399   tree_view = GTK_TREE_VIEW (object);
1400
1401   switch (prop_id)
1402     {
1403     case PROP_MODEL:
1404       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1405       break;
1406     case PROP_HADJUSTMENT:
1407       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1408       break;
1409     case PROP_VADJUSTMENT:
1410       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1411       break;
1412     case PROP_HEADERS_VISIBLE:
1413       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1414       break;
1415     case PROP_HEADERS_CLICKABLE:
1416       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1417       break;
1418     case PROP_EXPANDER_COLUMN:
1419       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1420       break;
1421     case PROP_REORDERABLE:
1422       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1423       break;
1424     case PROP_RULES_HINT:
1425       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1426       break;
1427     case PROP_ENABLE_SEARCH:
1428       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1429       break;
1430     case PROP_SEARCH_COLUMN:
1431       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1432       break;
1433     case PROP_FIXED_HEIGHT_MODE:
1434       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1435       break;
1436     case PROP_HOVER_SELECTION:
1437       tree_view->priv->hover_selection = g_value_get_boolean (value);
1438       break;
1439     case PROP_HOVER_EXPAND:
1440       tree_view->priv->hover_expand = g_value_get_boolean (value);
1441       break;
1442     case PROP_SHOW_EXPANDERS:
1443       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1444       break;
1445     case PROP_LEVEL_INDENTATION:
1446       tree_view->priv->level_indentation = g_value_get_int (value);
1447       break;
1448     case PROP_RUBBER_BANDING:
1449       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1450       break;
1451     case PROP_ENABLE_GRID_LINES:
1452       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1453       break;
1454     case PROP_ENABLE_TREE_LINES:
1455       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1456       break;
1457     case PROP_TOOLTIP_COLUMN:
1458       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1459       break;
1460     default:
1461       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1462       break;
1463     }
1464 }
1465
1466 static void
1467 gtk_tree_view_get_property (GObject    *object,
1468                             guint       prop_id,
1469                             GValue     *value,
1470                             GParamSpec *pspec)
1471 {
1472   GtkTreeView *tree_view;
1473
1474   tree_view = GTK_TREE_VIEW (object);
1475
1476   switch (prop_id)
1477     {
1478     case PROP_MODEL:
1479       g_value_set_object (value, tree_view->priv->model);
1480       break;
1481     case PROP_HADJUSTMENT:
1482       g_value_set_object (value, tree_view->priv->hadjustment);
1483       break;
1484     case PROP_VADJUSTMENT:
1485       g_value_set_object (value, tree_view->priv->vadjustment);
1486       break;
1487     case PROP_HEADERS_VISIBLE:
1488       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1489       break;
1490     case PROP_HEADERS_CLICKABLE:
1491       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1492       break;
1493     case PROP_EXPANDER_COLUMN:
1494       g_value_set_object (value, tree_view->priv->expander_column);
1495       break;
1496     case PROP_REORDERABLE:
1497       g_value_set_boolean (value, tree_view->priv->reorderable);
1498       break;
1499     case PROP_RULES_HINT:
1500       g_value_set_boolean (value, tree_view->priv->has_rules);
1501       break;
1502     case PROP_ENABLE_SEARCH:
1503       g_value_set_boolean (value, tree_view->priv->enable_search);
1504       break;
1505     case PROP_SEARCH_COLUMN:
1506       g_value_set_int (value, tree_view->priv->search_column);
1507       break;
1508     case PROP_FIXED_HEIGHT_MODE:
1509       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1510       break;
1511     case PROP_HOVER_SELECTION:
1512       g_value_set_boolean (value, tree_view->priv->hover_selection);
1513       break;
1514     case PROP_HOVER_EXPAND:
1515       g_value_set_boolean (value, tree_view->priv->hover_expand);
1516       break;
1517     case PROP_SHOW_EXPANDERS:
1518       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1519       break;
1520     case PROP_LEVEL_INDENTATION:
1521       g_value_set_int (value, tree_view->priv->level_indentation);
1522       break;
1523     case PROP_RUBBER_BANDING:
1524       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1525       break;
1526     case PROP_ENABLE_GRID_LINES:
1527       g_value_set_enum (value, tree_view->priv->grid_lines);
1528       break;
1529     case PROP_ENABLE_TREE_LINES:
1530       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1531       break;
1532     case PROP_TOOLTIP_COLUMN:
1533       g_value_set_int (value, tree_view->priv->tooltip_column);
1534       break;
1535     default:
1536       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1537       break;
1538     }
1539 }
1540
1541 static void
1542 gtk_tree_view_finalize (GObject *object)
1543 {
1544   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1545 }
1546
1547 \f
1548
1549 static void
1550 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1551                                    GtkBuilder  *builder,
1552                                    GObject     *child,
1553                                    const gchar *type)
1554 {
1555   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1556 }
1557
1558 /* GtkObject Methods
1559  */
1560
1561 static void
1562 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1563 {
1564   _gtk_rbtree_free (tree_view->priv->tree);
1565   
1566   tree_view->priv->tree = NULL;
1567   tree_view->priv->button_pressed_node = NULL;
1568   tree_view->priv->button_pressed_tree = NULL;
1569   tree_view->priv->prelight_tree = NULL;
1570   tree_view->priv->prelight_node = NULL;
1571   tree_view->priv->expanded_collapsed_node = NULL;
1572   tree_view->priv->expanded_collapsed_tree = NULL;
1573 }
1574
1575 static void
1576 gtk_tree_view_destroy (GtkObject *object)
1577 {
1578   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1579   GList *list;
1580
1581   gtk_tree_view_stop_editing (tree_view, TRUE);
1582
1583   if (tree_view->priv->columns != NULL)
1584     {
1585       list = tree_view->priv->columns;
1586       while (list)
1587         {
1588           GtkTreeViewColumn *column;
1589           column = GTK_TREE_VIEW_COLUMN (list->data);
1590           list = list->next;
1591           gtk_tree_view_remove_column (tree_view, column);
1592         }
1593       tree_view->priv->columns = NULL;
1594     }
1595
1596   if (tree_view->priv->tree != NULL)
1597     {
1598       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1599
1600       gtk_tree_view_free_rbtree (tree_view);
1601     }
1602
1603   if (tree_view->priv->selection != NULL)
1604     {
1605       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1606       g_object_unref (tree_view->priv->selection);
1607       tree_view->priv->selection = NULL;
1608     }
1609
1610   if (tree_view->priv->scroll_to_path != NULL)
1611     {
1612       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1613       tree_view->priv->scroll_to_path = NULL;
1614     }
1615
1616   if (tree_view->priv->drag_dest_row != NULL)
1617     {
1618       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1619       tree_view->priv->drag_dest_row = NULL;
1620     }
1621
1622   if (tree_view->priv->last_button_press != NULL)
1623     {
1624       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
1625       tree_view->priv->last_button_press = NULL;
1626     }
1627
1628   if (tree_view->priv->last_button_press_2 != NULL)
1629     {
1630       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
1631       tree_view->priv->last_button_press_2 = NULL;
1632     }
1633
1634   if (tree_view->priv->top_row != NULL)
1635     {
1636       gtk_tree_row_reference_free (tree_view->priv->top_row);
1637       tree_view->priv->top_row = NULL;
1638     }
1639
1640   if (tree_view->priv->column_drop_func_data &&
1641       tree_view->priv->column_drop_func_data_destroy)
1642     {
1643       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1644       tree_view->priv->column_drop_func_data = NULL;
1645     }
1646
1647   if (tree_view->priv->destroy_count_destroy &&
1648       tree_view->priv->destroy_count_data)
1649     {
1650       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1651       tree_view->priv->destroy_count_data = NULL;
1652     }
1653
1654   gtk_tree_row_reference_free (tree_view->priv->cursor);
1655   tree_view->priv->cursor = NULL;
1656
1657   gtk_tree_row_reference_free (tree_view->priv->anchor);
1658   tree_view->priv->anchor = NULL;
1659
1660   /* destroy interactive search dialog */
1661   if (tree_view->priv->search_window)
1662     {
1663       gtk_widget_destroy (tree_view->priv->search_window);
1664       tree_view->priv->search_window = NULL;
1665       tree_view->priv->search_entry = NULL;
1666       if (tree_view->priv->typeselect_flush_timeout)
1667         {
1668           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1669           tree_view->priv->typeselect_flush_timeout = 0;
1670         }
1671     }
1672
1673   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1674     {
1675       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1676       tree_view->priv->search_user_data = NULL;
1677     }
1678
1679   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1680     {
1681       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1682       tree_view->priv->search_position_user_data = NULL;
1683     }
1684
1685   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1686     {
1687       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1688       tree_view->priv->row_separator_data = NULL;
1689     }
1690   
1691   gtk_tree_view_set_model (tree_view, NULL);
1692
1693   if (tree_view->priv->hadjustment)
1694     {
1695       g_object_unref (tree_view->priv->hadjustment);
1696       tree_view->priv->hadjustment = NULL;
1697     }
1698   if (tree_view->priv->vadjustment)
1699     {
1700       g_object_unref (tree_view->priv->vadjustment);
1701       tree_view->priv->vadjustment = NULL;
1702     }
1703
1704   GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy (object);
1705 }
1706
1707 \f
1708
1709 /* GtkWidget Methods
1710  */
1711
1712 /* GtkWidget::map helper */
1713 static void
1714 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1715 {
1716   GList *list;
1717
1718   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1719
1720   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1721     {
1722       GtkTreeViewColumn *column;
1723
1724       for (list = tree_view->priv->columns; list; list = list->next)
1725         {
1726           column = list->data;
1727           if (GTK_WIDGET_VISIBLE (column->button) &&
1728               !GTK_WIDGET_MAPPED (column->button))
1729             gtk_widget_map (column->button);
1730         }
1731       for (list = tree_view->priv->columns; list; list = list->next)
1732         {
1733           column = list->data;
1734           if (column->visible == FALSE)
1735             continue;
1736           if (column->resizable)
1737             {
1738               gdk_window_raise (column->window);
1739               gdk_window_show (column->window);
1740             }
1741           else
1742             gdk_window_hide (column->window);
1743         }
1744       gdk_window_show (tree_view->priv->header_window);
1745     }
1746 }
1747
1748 static void
1749 gtk_tree_view_map (GtkWidget *widget)
1750 {
1751   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1752   GList *tmp_list;
1753
1754   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1755
1756   tmp_list = tree_view->priv->children;
1757   while (tmp_list)
1758     {
1759       GtkTreeViewChild *child = tmp_list->data;
1760       tmp_list = tmp_list->next;
1761
1762       if (GTK_WIDGET_VISIBLE (child->widget))
1763         {
1764           if (!GTK_WIDGET_MAPPED (child->widget))
1765             gtk_widget_map (child->widget);
1766         }
1767     }
1768   gdk_window_show (tree_view->priv->bin_window);
1769
1770   gtk_tree_view_map_buttons (tree_view);
1771
1772   gdk_window_show (widget->window);
1773 }
1774
1775 static void
1776 gtk_tree_view_realize (GtkWidget *widget)
1777 {
1778   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1779   GList *tmp_list;
1780   GdkWindowAttr attributes;
1781   gint attributes_mask;
1782
1783   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1784
1785   /* Make the main, clipping window */
1786   attributes.window_type = GDK_WINDOW_CHILD;
1787   attributes.x = widget->allocation.x;
1788   attributes.y = widget->allocation.y;
1789   attributes.width = widget->allocation.width;
1790   attributes.height = widget->allocation.height;
1791   attributes.wclass = GDK_INPUT_OUTPUT;
1792   attributes.visual = gtk_widget_get_visual (widget);
1793   attributes.colormap = gtk_widget_get_colormap (widget);
1794   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1795
1796   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1797
1798   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1799                                    &attributes, attributes_mask);
1800   gdk_window_set_user_data (widget->window, widget);
1801
1802   /* Make the window for the tree */
1803   attributes.x = 0;
1804   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1805   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1806   attributes.height = widget->allocation.height;
1807   attributes.event_mask = (GDK_EXPOSURE_MASK |
1808                            GDK_SCROLL_MASK |
1809                            GDK_POINTER_MOTION_MASK |
1810                            GDK_ENTER_NOTIFY_MASK |
1811                            GDK_LEAVE_NOTIFY_MASK |
1812                            GDK_BUTTON_PRESS_MASK |
1813                            GDK_BUTTON_RELEASE_MASK |
1814                            gtk_widget_get_events (widget));
1815
1816   tree_view->priv->bin_window = gdk_window_new (widget->window,
1817                                                 &attributes, attributes_mask);
1818   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1819
1820   /* Make the column header window */
1821   attributes.x = 0;
1822   attributes.y = 0;
1823   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1824   attributes.height = tree_view->priv->header_height;
1825   attributes.event_mask = (GDK_EXPOSURE_MASK |
1826                            GDK_SCROLL_MASK |
1827                            GDK_BUTTON_PRESS_MASK |
1828                            GDK_BUTTON_RELEASE_MASK |
1829                            GDK_KEY_PRESS_MASK |
1830                            GDK_KEY_RELEASE_MASK |
1831                            gtk_widget_get_events (widget));
1832
1833   tree_view->priv->header_window = gdk_window_new (widget->window,
1834                                                    &attributes, attributes_mask);
1835   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1836
1837   /* Add them all up. */
1838   widget->style = gtk_style_attach (widget->style, widget->window);
1839   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1840   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1841   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1842
1843   tmp_list = tree_view->priv->children;
1844   while (tmp_list)
1845     {
1846       GtkTreeViewChild *child = tmp_list->data;
1847       tmp_list = tmp_list->next;
1848
1849       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1850     }
1851
1852   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1853     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1854
1855   /* Need to call those here, since they create GCs */
1856   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1857   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1858
1859   install_presize_handler (tree_view); 
1860 }
1861
1862 static void
1863 gtk_tree_view_unrealize (GtkWidget *widget)
1864 {
1865   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1866   GtkTreeViewPrivate *priv = tree_view->priv;
1867   GList *list;
1868
1869   if (priv->scroll_timeout != 0)
1870     {
1871       g_source_remove (priv->scroll_timeout);
1872       priv->scroll_timeout = 0;
1873     }
1874
1875   if (priv->auto_expand_timeout != 0)
1876     {
1877       g_source_remove (priv->auto_expand_timeout);
1878       priv->auto_expand_timeout = 0;
1879     }
1880
1881   if (priv->open_dest_timeout != 0)
1882     {
1883       g_source_remove (priv->open_dest_timeout);
1884       priv->open_dest_timeout = 0;
1885     }
1886
1887   remove_expand_collapse_timeout (tree_view);
1888   
1889   if (priv->presize_handler_timer != 0)
1890     {
1891       g_source_remove (priv->presize_handler_timer);
1892       priv->presize_handler_timer = 0;
1893     }
1894
1895   if (priv->validate_rows_timer != 0)
1896     {
1897       g_source_remove (priv->validate_rows_timer);
1898       priv->validate_rows_timer = 0;
1899     }
1900
1901   if (priv->scroll_sync_timer != 0)
1902     {
1903       g_source_remove (priv->scroll_sync_timer);
1904       priv->scroll_sync_timer = 0;
1905     }
1906
1907   if (priv->typeselect_flush_timeout)
1908     {
1909       g_source_remove (priv->typeselect_flush_timeout);
1910       priv->typeselect_flush_timeout = 0;
1911     }
1912   
1913   for (list = priv->columns; list; list = list->next)
1914     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1915
1916   gdk_window_set_user_data (priv->bin_window, NULL);
1917   gdk_window_destroy (priv->bin_window);
1918   priv->bin_window = NULL;
1919
1920   gdk_window_set_user_data (priv->header_window, NULL);
1921   gdk_window_destroy (priv->header_window);
1922   priv->header_window = NULL;
1923
1924   if (priv->drag_window)
1925     {
1926       gdk_window_set_user_data (priv->drag_window, NULL);
1927       gdk_window_destroy (priv->drag_window);
1928       priv->drag_window = NULL;
1929     }
1930
1931   if (priv->drag_highlight_window)
1932     {
1933       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1934       gdk_window_destroy (priv->drag_highlight_window);
1935       priv->drag_highlight_window = NULL;
1936     }
1937
1938   if (priv->tree_line_gc)
1939     {
1940       g_object_unref (priv->tree_line_gc);
1941       priv->tree_line_gc = NULL;
1942     }
1943
1944   if (priv->grid_line_gc)
1945     {
1946       g_object_unref (priv->grid_line_gc);
1947       priv->grid_line_gc = NULL;
1948     }
1949
1950   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1951 }
1952
1953 /* GtkWidget::size_request helper */
1954 static void
1955 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1956 {
1957   GList *list;
1958
1959   tree_view->priv->header_height = 0;
1960
1961   if (tree_view->priv->model)
1962     {
1963       for (list = tree_view->priv->columns; list; list = list->next)
1964         {
1965           GtkRequisition requisition;
1966           GtkTreeViewColumn *column = list->data;
1967
1968           if (column->button == NULL)
1969             continue;
1970
1971           column = list->data;
1972           
1973           gtk_widget_size_request (column->button, &requisition);
1974           column->button_request = requisition.width;
1975           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1976         }
1977     }
1978 }
1979
1980
1981 /* Called only by ::size_request */
1982 static void
1983 gtk_tree_view_update_size (GtkTreeView *tree_view)
1984 {
1985   GList *list;
1986   GtkTreeViewColumn *column;
1987   gint i;
1988
1989   if (tree_view->priv->model == NULL)
1990     {
1991       tree_view->priv->width = 0;
1992       tree_view->priv->prev_width = 0;                   
1993       tree_view->priv->height = 0;
1994       return;
1995     }
1996
1997   tree_view->priv->prev_width = tree_view->priv->width;  
1998   tree_view->priv->width = 0;
1999
2000   /* keep this in sync with size_allocate below */
2001   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2002     {
2003       gint real_requested_width = 0;
2004       column = list->data;
2005       if (!column->visible)
2006         continue;
2007
2008       if (column->use_resized_width)
2009         {
2010           real_requested_width = column->resized_width;
2011         }
2012       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2013         {
2014           real_requested_width = column->fixed_width;
2015         }
2016       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2017         {
2018           real_requested_width = MAX (column->requested_width, column->button_request);
2019         }
2020       else
2021         {
2022           real_requested_width = column->requested_width;
2023         }
2024
2025       if (column->min_width != -1)
2026         real_requested_width = MAX (real_requested_width, column->min_width);
2027       if (column->max_width != -1)
2028         real_requested_width = MIN (real_requested_width, column->max_width);
2029
2030       tree_view->priv->width += real_requested_width;
2031     }
2032
2033   if (tree_view->priv->tree == NULL)
2034     tree_view->priv->height = 0;
2035   else
2036     tree_view->priv->height = tree_view->priv->tree->root->offset;
2037 }
2038
2039 static void
2040 gtk_tree_view_size_request (GtkWidget      *widget,
2041                             GtkRequisition *requisition)
2042 {
2043   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2044   GList *tmp_list;
2045
2046   /* we validate some rows initially just to make sure we have some size. 
2047    * In practice, with a lot of static lists, this should get a good width.
2048    */
2049   do_validate_rows (tree_view, FALSE);
2050   gtk_tree_view_size_request_columns (tree_view);
2051   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2052
2053   requisition->width = tree_view->priv->width;
2054   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2055
2056   tmp_list = tree_view->priv->children;
2057
2058   while (tmp_list)
2059     {
2060       GtkTreeViewChild *child = tmp_list->data;
2061       GtkRequisition child_requisition;
2062
2063       tmp_list = tmp_list->next;
2064
2065       if (GTK_WIDGET_VISIBLE (child->widget))
2066         gtk_widget_size_request (child->widget, &child_requisition);
2067     }
2068 }
2069
2070
2071 static void
2072 invalidate_column (GtkTreeView       *tree_view,
2073                    GtkTreeViewColumn *column)
2074 {
2075   gint column_offset = 0;
2076   GList *list;
2077   GtkWidget *widget = GTK_WIDGET (tree_view);
2078   gboolean rtl;
2079
2080   if (!GTK_WIDGET_REALIZED (widget))
2081     return;
2082
2083   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2084   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2085        list;
2086        list = (rtl ? list->prev : list->next))
2087     {
2088       GtkTreeViewColumn *tmpcolumn = list->data;
2089       if (tmpcolumn == column)
2090         {
2091           GdkRectangle invalid_rect;
2092           
2093           invalid_rect.x = column_offset;
2094           invalid_rect.y = 0;
2095           invalid_rect.width = column->width;
2096           invalid_rect.height = widget->allocation.height;
2097           
2098           gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
2099           break;
2100         }
2101       
2102       column_offset += tmpcolumn->width;
2103     }
2104 }
2105
2106 static void
2107 invalidate_last_column (GtkTreeView *tree_view)
2108 {
2109   GList *last_column;
2110   gboolean rtl;
2111
2112   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2113
2114   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2115        last_column;
2116        last_column = (rtl ? last_column->next : last_column->prev))
2117     {
2118       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2119         {
2120           invalidate_column (tree_view, last_column->data);
2121           return;
2122         }
2123     }
2124 }
2125
2126 static gint
2127 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2128                                                     GtkTreeViewColumn *column)
2129 {
2130   gint real_requested_width;
2131
2132   if (column->use_resized_width)
2133     {
2134       real_requested_width = column->resized_width;
2135     }
2136   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2137     {
2138       real_requested_width = column->fixed_width;
2139     }
2140   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2141     {
2142       real_requested_width = MAX (column->requested_width, column->button_request);
2143     }
2144   else
2145     {
2146       real_requested_width = column->requested_width;
2147       if (real_requested_width < 0)
2148         real_requested_width = 0;
2149     }
2150
2151   if (column->min_width != -1)
2152     real_requested_width = MAX (real_requested_width, column->min_width);
2153   if (column->max_width != -1)
2154     real_requested_width = MIN (real_requested_width, column->max_width);
2155
2156   return real_requested_width;
2157 }
2158
2159 /* GtkWidget::size_allocate helper */
2160 static void
2161 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2162                                      gboolean  *width_changed)
2163 {
2164   GtkTreeView *tree_view;
2165   GList *list, *first_column, *last_column;
2166   GtkTreeViewColumn *column;
2167   GtkAllocation allocation;
2168   gint width = 0;
2169   gint extra, extra_per_column, extra_for_last;
2170   gint full_requested_width = 0;
2171   gint number_of_expand_columns = 0;
2172   gboolean column_changed = FALSE;
2173   gboolean rtl;
2174   gboolean update_expand;
2175   
2176   tree_view = GTK_TREE_VIEW (widget);
2177
2178   for (last_column = g_list_last (tree_view->priv->columns);
2179        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2180        last_column = last_column->prev)
2181     ;
2182   if (last_column == NULL)
2183     return;
2184
2185   for (first_column = g_list_first (tree_view->priv->columns);
2186        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2187        first_column = first_column->next)
2188     ;
2189
2190   allocation.y = 0;
2191   allocation.height = tree_view->priv->header_height;
2192
2193   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2194
2195   /* find out how many extra space and expandable columns we have */
2196   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2197     {
2198       column = (GtkTreeViewColumn *)list->data;
2199
2200       if (!column->visible)
2201         continue;
2202
2203       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2204
2205       if (column->expand)
2206         number_of_expand_columns++;
2207     }
2208
2209   /* Only update the expand value if the width of the widget has changed,
2210    * or the number of expand columns has changed, or if there are no expand
2211    * columns, or if we didn't have an size-allocation yet after the
2212    * last validated node.
2213    */
2214   update_expand = (width_changed && *width_changed == TRUE)
2215       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2216       || number_of_expand_columns == 0
2217       || tree_view->priv->post_validation_flag == TRUE;
2218
2219   tree_view->priv->post_validation_flag = FALSE;
2220
2221   if (!update_expand)
2222     {
2223       extra = tree_view->priv->last_extra_space;
2224       extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
2225     }
2226   else
2227     {
2228       extra = MAX (widget->allocation.width - full_requested_width, 0);
2229       extra_for_last = 0;
2230
2231       tree_view->priv->last_extra_space = extra;
2232     }
2233
2234   if (number_of_expand_columns > 0)
2235     extra_per_column = extra/number_of_expand_columns;
2236   else
2237     extra_per_column = 0;
2238
2239   if (update_expand)
2240     {
2241       tree_view->priv->last_extra_space_per_column = extra_per_column;
2242       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2243     }
2244
2245   for (list = (rtl ? last_column : first_column); 
2246        list != (rtl ? first_column->prev : last_column->next);
2247        list = (rtl ? list->prev : list->next)) 
2248     {
2249       gint real_requested_width = 0;
2250       gint old_width;
2251
2252       column = list->data;
2253       old_width = column->width;
2254
2255       if (!column->visible)
2256         continue;
2257
2258       /* We need to handle the dragged button specially.
2259        */
2260       if (column == tree_view->priv->drag_column)
2261         {
2262           GtkAllocation drag_allocation;
2263           gdk_drawable_get_size (tree_view->priv->drag_window,
2264                                  &(drag_allocation.width),
2265                                  &(drag_allocation.height));
2266           drag_allocation.x = 0;
2267           drag_allocation.y = 0;
2268           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2269                                     &drag_allocation);
2270           width += drag_allocation.width;
2271           continue;
2272         }
2273
2274       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2275
2276       allocation.x = width;
2277       column->width = real_requested_width;
2278
2279       if (column->expand)
2280         {
2281           if (number_of_expand_columns == 1)
2282             {
2283               /* We add the remander to the last column as
2284                * */
2285               column->width += extra;
2286             }
2287           else
2288             {
2289               column->width += extra_per_column;
2290               extra -= extra_per_column;
2291               number_of_expand_columns --;
2292             }
2293         }
2294       else if (number_of_expand_columns == 0 &&
2295                list == last_column)
2296         {
2297           column->width += extra;
2298         }
2299
2300       /* In addition to expand, the last column can get even more
2301        * extra space so all available space is filled up.
2302        */
2303       if (extra_for_last > 0 && list == last_column)
2304         column->width += extra_for_last;
2305
2306       g_object_notify (G_OBJECT (column), "width");
2307
2308       allocation.width = column->width;
2309       width += column->width;
2310
2311       if (column->width > old_width)
2312         column_changed = TRUE;
2313
2314       gtk_widget_size_allocate (column->button, &allocation);
2315
2316       if (column->window)
2317         gdk_window_move_resize (column->window,
2318                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2319                                 allocation.y,
2320                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2321     }
2322
2323   /* We change the width here.  The user might have been resizing columns,
2324    * so the total width of the tree view changes.
2325    */
2326   tree_view->priv->width = width;
2327   if (width_changed)
2328     *width_changed = TRUE;
2329
2330   if (column_changed)
2331     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2332 }
2333
2334
2335 static void
2336 gtk_tree_view_size_allocate (GtkWidget     *widget,
2337                              GtkAllocation *allocation)
2338 {
2339   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2340   GList *tmp_list;
2341   gboolean width_changed = FALSE;
2342   gint old_width = widget->allocation.width;
2343
2344   if (allocation->width != widget->allocation.width)
2345     width_changed = TRUE;
2346
2347   widget->allocation = *allocation;
2348
2349   tmp_list = tree_view->priv->children;
2350
2351   while (tmp_list)
2352     {
2353       GtkAllocation allocation;
2354
2355       GtkTreeViewChild *child = tmp_list->data;
2356       tmp_list = tmp_list->next;
2357
2358       /* totally ignore our child's requisition */
2359       allocation.x = child->x;
2360       allocation.y = child->y;
2361       allocation.width = child->width;
2362       allocation.height = child->height;
2363       gtk_widget_size_allocate (child->widget, &allocation);
2364     }
2365
2366   /* We size-allocate the columns first because the width of the
2367    * tree view (used in updating the adjustments below) might change.
2368    */
2369   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2370
2371   tree_view->priv->hadjustment->page_size = allocation->width;
2372   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2373   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2374   tree_view->priv->hadjustment->lower = 0;
2375   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2376
2377   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2378     {
2379       if (allocation->width < tree_view->priv->width)
2380         {
2381           if (tree_view->priv->init_hadjust_value)
2382             {
2383               tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2384               tree_view->priv->init_hadjust_value = FALSE;
2385             }
2386           else if (allocation->width != old_width)
2387             {
2388               tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2389             }
2390           else
2391             tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value), 0, tree_view->priv->width - allocation->width);
2392         }
2393       else
2394         {
2395           tree_view->priv->hadjustment->value = 0;
2396           tree_view->priv->init_hadjust_value = TRUE;
2397         }
2398     }
2399   else
2400     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2401       tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2402
2403   gtk_adjustment_changed (tree_view->priv->hadjustment);
2404
2405   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2406   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2407   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2408   tree_view->priv->vadjustment->lower = 0;
2409   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2410
2411   gtk_adjustment_changed (tree_view->priv->vadjustment);
2412
2413   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2414   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2415     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2416   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2417     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2418                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2419   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2420     gtk_tree_view_top_row_to_dy (tree_view);
2421   else
2422     gtk_tree_view_dy_to_top_row (tree_view);
2423   
2424   if (GTK_WIDGET_REALIZED (widget))
2425     {
2426       gdk_window_move_resize (widget->window,
2427                               allocation->x, allocation->y,
2428                               allocation->width, allocation->height);
2429       gdk_window_move_resize (tree_view->priv->header_window,
2430                               - (gint) tree_view->priv->hadjustment->value,
2431                               0,
2432                               MAX (tree_view->priv->width, allocation->width),
2433                               tree_view->priv->header_height);
2434       gdk_window_move_resize (tree_view->priv->bin_window,
2435                               - (gint) tree_view->priv->hadjustment->value,
2436                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2437                               MAX (tree_view->priv->width, allocation->width),
2438                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2439     }
2440
2441   if (tree_view->priv->tree == NULL)
2442     invalidate_empty_focus (tree_view);
2443
2444   if (GTK_WIDGET_REALIZED (widget))
2445     {
2446       gboolean has_expand_column = FALSE;
2447       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2448         {
2449           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2450             {
2451               has_expand_column = TRUE;
2452               break;
2453             }
2454         }
2455
2456       /* This little hack only works if we have an LTR locale, and no column has the  */
2457       if (width_changed)
2458         {
2459           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2460               ! has_expand_column)
2461             invalidate_last_column (tree_view);
2462           else
2463             gtk_widget_queue_draw (widget);
2464         }
2465     }
2466 }
2467
2468 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2469 static void
2470 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2471 {
2472   if (GTK_WIDGET_CAN_FOCUS (tree_view) && !GTK_WIDGET_HAS_FOCUS (tree_view))
2473     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2474   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2475 }
2476
2477 static inline gboolean
2478 row_is_separator (GtkTreeView *tree_view,
2479                   GtkTreeIter *iter,
2480                   GtkTreePath *path)
2481 {
2482   gboolean is_separator = FALSE;
2483
2484   if (tree_view->priv->row_separator_func)
2485     {
2486       GtkTreeIter tmpiter;
2487
2488       if (iter)
2489         tmpiter = *iter;
2490       else
2491         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2492
2493       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2494                                                           &tmpiter,
2495                                                           tree_view->priv->row_separator_data);
2496     }
2497
2498   return is_separator;
2499 }
2500
2501 static gboolean
2502 gtk_tree_view_button_press (GtkWidget      *widget,
2503                             GdkEventButton *event)
2504 {
2505   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2506   GList *list;
2507   GtkTreeViewColumn *column = NULL;
2508   gint i;
2509   GdkRectangle background_area;
2510   GdkRectangle cell_area;
2511   gint vertical_separator;
2512   gint horizontal_separator;
2513   gboolean path_is_selectable;
2514   gboolean rtl;
2515
2516   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2517   gtk_tree_view_stop_editing (tree_view, FALSE);
2518   gtk_widget_style_get (widget,
2519                         "vertical-separator", &vertical_separator,
2520                         "horizontal-separator", &horizontal_separator,
2521                         NULL);
2522
2523
2524   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2525    * we're done handling the button press.
2526    */
2527
2528   if (event->window == tree_view->priv->bin_window)
2529     {
2530       GtkRBNode *node;
2531       GtkRBTree *tree;
2532       GtkTreePath *path;
2533       gchar *path_string;
2534       gint depth;
2535       gint new_y;
2536       gint y_offset;
2537       gint dval;
2538       gint pre_val, aft_val;
2539       GtkTreeViewColumn *column = NULL;
2540       GtkCellRenderer *focus_cell = NULL;
2541       gint column_handled_click = FALSE;
2542       gboolean row_double_click = FALSE;
2543       gboolean rtl;
2544       gboolean node_selected;
2545
2546       /* Empty tree? */
2547       if (tree_view->priv->tree == NULL)
2548         {
2549           grab_focus_and_unset_draw_keyfocus (tree_view);
2550           return TRUE;
2551         }
2552
2553       /* are we in an arrow? */
2554       if (tree_view->priv->prelight_node &&
2555           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2556           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2557         {
2558           if (event->button == 1)
2559             {
2560               gtk_grab_add (widget);
2561               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2562               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2563               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2564                                         tree_view->priv->prelight_tree,
2565                                         tree_view->priv->prelight_node,
2566                                         event->x,
2567                                         event->y);
2568             }
2569
2570           grab_focus_and_unset_draw_keyfocus (tree_view);
2571           return TRUE;
2572         }
2573
2574       /* find the node that was clicked */
2575       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2576       if (new_y < 0)
2577         new_y = 0;
2578       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2579
2580       if (node == NULL)
2581         {
2582           /* We clicked in dead space */
2583           grab_focus_and_unset_draw_keyfocus (tree_view);
2584           return TRUE;
2585         }
2586
2587       /* Get the path and the node */
2588       path = _gtk_tree_view_find_path (tree_view, tree, node);
2589       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2590
2591       if (!path_is_selectable)
2592         {
2593           gtk_tree_path_free (path);
2594           grab_focus_and_unset_draw_keyfocus (tree_view);
2595           return TRUE;
2596         }
2597
2598       depth = gtk_tree_path_get_depth (path);
2599       background_area.y = y_offset + event->y;
2600       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2601       background_area.x = 0;
2602
2603
2604       /* Let the column have a chance at selecting it. */
2605       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2606       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2607            list; list = (rtl ? list->prev : list->next))
2608         {
2609           GtkTreeViewColumn *candidate = list->data;
2610
2611           if (!candidate->visible)
2612             continue;
2613
2614           background_area.width = candidate->width;
2615           if ((background_area.x > (gint) event->x) ||
2616               (background_area.x + background_area.width <= (gint) event->x))
2617             {
2618               background_area.x += background_area.width;
2619               continue;
2620             }
2621
2622           /* we found the focus column */
2623           column = candidate;
2624           cell_area = background_area;
2625           cell_area.width -= horizontal_separator;
2626           cell_area.height -= vertical_separator;
2627           cell_area.x += horizontal_separator/2;
2628           cell_area.y += vertical_separator/2;
2629           if (gtk_tree_view_is_expander_column (tree_view, column))
2630             {
2631               if (!rtl)
2632                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2633               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2634
2635               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2636                 {
2637                   if (!rtl)
2638                     cell_area.x += depth * tree_view->priv->expander_size;
2639                   cell_area.width -= depth * tree_view->priv->expander_size;
2640                 }
2641             }
2642           break;
2643         }
2644
2645       if (column == NULL)
2646         {
2647           gtk_tree_path_free (path);
2648           grab_focus_and_unset_draw_keyfocus (tree_view);
2649           return FALSE;
2650         }
2651
2652       tree_view->priv->focus_column = column;
2653
2654       /* decide if we edit */
2655       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2656           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2657         {
2658           GtkTreePath *anchor;
2659           GtkTreeIter iter;
2660
2661           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2662           gtk_tree_view_column_cell_set_cell_data (column,
2663                                                    tree_view->priv->model,
2664                                                    &iter,
2665                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2666                                                    node->children?TRUE:FALSE);
2667
2668           if (tree_view->priv->anchor)
2669             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2670           else
2671             anchor = NULL;
2672
2673           if ((anchor && !gtk_tree_path_compare (anchor, path))
2674               || !_gtk_tree_view_column_has_editable_cell (column))
2675             {
2676               GtkCellEditable *cell_editable = NULL;
2677
2678               /* FIXME: get the right flags */
2679               guint flags = 0;
2680
2681               path_string = gtk_tree_path_to_string (path);
2682
2683               if (_gtk_tree_view_column_cell_event (column,
2684                                                     &cell_editable,
2685                                                     (GdkEvent *)event,
2686                                                     path_string,
2687                                                     &background_area,
2688                                                     &cell_area, flags))
2689                 {
2690                   if (cell_editable != NULL)
2691                     {
2692                       gint left, right;
2693                       GdkRectangle area;
2694
2695                       area = cell_area;
2696                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2697
2698                       area.x += left;
2699                       area.width -= right + left;
2700
2701                       gtk_tree_view_real_start_editing (tree_view,
2702                                                         column,
2703                                                         path,
2704                                                         cell_editable,
2705                                                         &area,
2706                                                         (GdkEvent *)event,
2707                                                         flags);
2708                       g_free (path_string);
2709                       gtk_tree_path_free (path);
2710                       gtk_tree_path_free (anchor);
2711                       return TRUE;
2712                     }
2713                   column_handled_click = TRUE;
2714                 }
2715               g_free (path_string);
2716             }
2717           if (anchor)
2718             gtk_tree_path_free (anchor);
2719         }
2720
2721       /* select */
2722       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2723       pre_val = tree_view->priv->vadjustment->value;
2724
2725       /* we only handle selection modifications on the first button press
2726        */
2727       if (event->type == GDK_BUTTON_PRESS)
2728         {
2729           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2730             tree_view->priv->ctrl_pressed = TRUE;
2731           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2732             tree_view->priv->shift_pressed = TRUE;
2733
2734           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2735           if (focus_cell)
2736             gtk_tree_view_column_focus_cell (column, focus_cell);
2737
2738           if (event->state & GDK_CONTROL_MASK)
2739             {
2740               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2741               gtk_tree_view_real_toggle_cursor_row (tree_view);
2742             }
2743           else if (event->state & GDK_SHIFT_MASK)
2744             {
2745               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2746               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2747             }
2748           else
2749             {
2750               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2751             }
2752
2753           tree_view->priv->ctrl_pressed = FALSE;
2754           tree_view->priv->shift_pressed = FALSE;
2755         }
2756
2757       /* the treeview may have been scrolled because of _set_cursor,
2758        * correct here
2759        */
2760
2761       aft_val = tree_view->priv->vadjustment->value;
2762       dval = pre_val - aft_val;
2763
2764       cell_area.y += dval;
2765       background_area.y += dval;
2766
2767       /* Save press to possibly begin a drag
2768        */
2769       if (!column_handled_click &&
2770           !tree_view->priv->in_grab &&
2771           tree_view->priv->pressed_button < 0)
2772         {
2773           tree_view->priv->pressed_button = event->button;
2774           tree_view->priv->press_start_x = event->x;
2775           tree_view->priv->press_start_y = event->y;
2776
2777           if (tree_view->priv->rubber_banding_enable
2778               && !node_selected
2779               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2780             {
2781               tree_view->priv->press_start_y += tree_view->priv->dy;
2782               tree_view->priv->rubber_band_x = event->x;
2783               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2784               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2785
2786               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2787                 tree_view->priv->rubber_band_ctrl = TRUE;
2788               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2789                 tree_view->priv->rubber_band_shift = TRUE;
2790             }
2791         }
2792
2793       /* Test if a double click happened on the same row. */
2794       if (event->button == 1)
2795         {
2796           /* We also handle triple clicks here, because a user could have done
2797            * a first click and a second double click on different rows.
2798            */
2799           if ((event->type == GDK_2BUTTON_PRESS
2800                || event->type == GDK_3BUTTON_PRESS)
2801               && tree_view->priv->last_button_press)
2802             {
2803               GtkTreePath *lsc;
2804
2805               lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
2806
2807               if (lsc)
2808                 {
2809                   row_double_click = !gtk_tree_path_compare (lsc, path);
2810                   gtk_tree_path_free (lsc);
2811                 }
2812             }
2813
2814           if (row_double_click)
2815             {
2816               if (tree_view->priv->last_button_press)
2817                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2818               if (tree_view->priv->last_button_press_2)
2819                 gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
2820               tree_view->priv->last_button_press = NULL;
2821               tree_view->priv->last_button_press_2 = NULL;
2822             }
2823           else
2824             {
2825               if (tree_view->priv->last_button_press)
2826                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2827               tree_view->priv->last_button_press = tree_view->priv->last_button_press_2;
2828               tree_view->priv->last_button_press_2 = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
2829             }
2830         }
2831
2832       if (row_double_click)
2833         {
2834           gtk_grab_remove (widget);
2835           gtk_tree_view_row_activated (tree_view, path, column);
2836
2837           if (tree_view->priv->pressed_button == event->button)
2838             tree_view->priv->pressed_button = -1;
2839         }
2840
2841       gtk_tree_path_free (path);
2842
2843       /* If we activated the row through a double click we don't want to grab
2844        * focus back, as moving focus to another widget is pretty common.
2845        */
2846       if (!row_double_click)
2847         grab_focus_and_unset_draw_keyfocus (tree_view);
2848
2849       return TRUE;
2850     }
2851
2852   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2853    */
2854   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2855     {
2856       column = list->data;
2857       if (event->window == column->window &&
2858           column->resizable &&
2859           column->window)
2860         {
2861           gpointer drag_data;
2862
2863           if (event->type == GDK_2BUTTON_PRESS &&
2864               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2865             {
2866               column->use_resized_width = FALSE;
2867               _gtk_tree_view_column_autosize (tree_view, column);
2868               return TRUE;
2869             }
2870
2871           if (gdk_pointer_grab (column->window, FALSE,
2872                                 GDK_POINTER_MOTION_HINT_MASK |
2873                                 GDK_BUTTON1_MOTION_MASK |
2874                                 GDK_BUTTON_RELEASE_MASK,
2875                                 NULL, NULL, event->time))
2876             return FALSE;
2877
2878           gtk_grab_add (widget);
2879           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2880           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2881
2882           /* block attached dnd signal handler */
2883           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2884           if (drag_data)
2885             g_signal_handlers_block_matched (widget,
2886                                              G_SIGNAL_MATCH_DATA,
2887                                              0, 0, NULL, NULL,
2888                                              drag_data);
2889
2890           tree_view->priv->drag_pos = i;
2891           tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
2892
2893           if (!GTK_WIDGET_HAS_FOCUS (widget))
2894             gtk_widget_grab_focus (widget);
2895
2896           return TRUE;
2897         }
2898     }
2899   return FALSE;
2900 }
2901
2902 /* GtkWidget::button_release_event helper */
2903 static gboolean
2904 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2905                                           GdkEventButton *event)
2906 {
2907   GtkTreeView *tree_view;
2908   GList *l;
2909   gboolean rtl;
2910
2911   tree_view = GTK_TREE_VIEW (widget);
2912
2913   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2914   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2915   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2916
2917   /* Move the button back */
2918   g_object_ref (tree_view->priv->drag_column->button);
2919   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2920   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2921   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2922   g_object_unref (tree_view->priv->drag_column->button);
2923   gtk_widget_queue_resize (widget);
2924   if (tree_view->priv->drag_column->resizable)
2925     {
2926       gdk_window_raise (tree_view->priv->drag_column->window);
2927       gdk_window_show (tree_view->priv->drag_column->window);
2928     }
2929   else
2930     gdk_window_hide (tree_view->priv->drag_column->window);
2931
2932   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2933
2934   if (rtl)
2935     {
2936       if (tree_view->priv->cur_reorder &&
2937           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2938         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2939                                          tree_view->priv->cur_reorder->right_column);
2940     }
2941   else
2942     {
2943       if (tree_view->priv->cur_reorder &&
2944           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2945         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2946                                          tree_view->priv->cur_reorder->left_column);
2947     }
2948   tree_view->priv->drag_column = NULL;
2949   gdk_window_hide (tree_view->priv->drag_window);
2950
2951   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
2952     g_slice_free (GtkTreeViewColumnReorder, l->data);
2953   g_list_free (tree_view->priv->column_drag_info);
2954   tree_view->priv->column_drag_info = NULL;
2955   tree_view->priv->cur_reorder = NULL;
2956
2957   if (tree_view->priv->drag_highlight_window)
2958     gdk_window_hide (tree_view->priv->drag_highlight_window);
2959
2960   /* Reset our flags */
2961   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
2962   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
2963
2964   return TRUE;
2965 }
2966
2967 /* GtkWidget::button_release_event helper */
2968 static gboolean
2969 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
2970                                             GdkEventButton *event)
2971 {
2972   GtkTreeView *tree_view;
2973   gpointer drag_data;
2974
2975   tree_view = GTK_TREE_VIEW (widget);
2976
2977   tree_view->priv->drag_pos = -1;
2978
2979   /* unblock attached dnd signal handler */
2980   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2981   if (drag_data)
2982     g_signal_handlers_unblock_matched (widget,
2983                                        G_SIGNAL_MATCH_DATA,
2984                                        0, 0, NULL, NULL,
2985                                        drag_data);
2986
2987   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2988   gtk_grab_remove (widget);
2989   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
2990                               event->time);
2991   return TRUE;
2992 }
2993
2994 static gboolean
2995 gtk_tree_view_button_release (GtkWidget      *widget,
2996                               GdkEventButton *event)
2997 {
2998   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2999
3000   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3001     return gtk_tree_view_button_release_drag_column (widget, event);
3002
3003   if (tree_view->priv->rubber_band_status)
3004     gtk_tree_view_stop_rubber_band (tree_view);
3005
3006   if (tree_view->priv->pressed_button == event->button)
3007     tree_view->priv->pressed_button = -1;
3008
3009   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3010     return gtk_tree_view_button_release_column_resize (widget, event);
3011
3012   if (tree_view->priv->button_pressed_node == NULL)
3013     return FALSE;
3014
3015   if (event->button == 1)
3016     {
3017       gtk_grab_remove (widget);
3018       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3019           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3020         {
3021           GtkTreePath *path = NULL;
3022
3023           path = _gtk_tree_view_find_path (tree_view,
3024                                            tree_view->priv->button_pressed_tree,
3025                                            tree_view->priv->button_pressed_node);
3026           /* Actually activate the node */
3027           if (tree_view->priv->button_pressed_node->children == NULL)
3028             gtk_tree_view_real_expand_row (tree_view, path,
3029                                            tree_view->priv->button_pressed_tree,
3030                                            tree_view->priv->button_pressed_node,
3031                                            FALSE, TRUE);
3032           else
3033             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3034                                              tree_view->priv->button_pressed_tree,
3035                                              tree_view->priv->button_pressed_node, TRUE);
3036           gtk_tree_path_free (path);
3037         }
3038
3039       tree_view->priv->button_pressed_tree = NULL;
3040       tree_view->priv->button_pressed_node = NULL;
3041     }
3042
3043   return TRUE;
3044 }
3045
3046 static gboolean
3047 gtk_tree_view_grab_broken (GtkWidget          *widget,
3048                            GdkEventGrabBroken *event)
3049 {
3050   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3051
3052   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3053     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3054
3055   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3056     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3057
3058   return TRUE;
3059 }
3060
3061 #if 0
3062 static gboolean
3063 gtk_tree_view_configure (GtkWidget *widget,
3064                          GdkEventConfigure *event)
3065 {
3066   GtkTreeView *tree_view;
3067
3068   tree_view = GTK_TREE_VIEW (widget);
3069   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3070
3071   return FALSE;
3072 }
3073 #endif
3074
3075 /* GtkWidget::motion_event function set.
3076  */
3077
3078 static gboolean
3079 coords_are_over_arrow (GtkTreeView *tree_view,
3080                        GtkRBTree   *tree,
3081                        GtkRBNode   *node,
3082                        /* these are in bin window coords */
3083                        gint         x,
3084                        gint         y)
3085 {
3086   GdkRectangle arrow;
3087   gint x2;
3088
3089   if (!GTK_WIDGET_REALIZED (tree_view))
3090     return FALSE;
3091
3092   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3093     return FALSE;
3094
3095   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3096
3097   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3098
3099   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3100
3101   arrow.width = x2 - arrow.x;
3102
3103   return (x >= arrow.x &&
3104           x < (arrow.x + arrow.width) &&
3105           y >= arrow.y &&
3106           y < (arrow.y + arrow.height));
3107 }
3108
3109 static gboolean
3110 auto_expand_timeout (gpointer data)
3111 {
3112   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3113   GtkTreePath *path;
3114
3115   if (tree_view->priv->prelight_node)
3116     {
3117       path = _gtk_tree_view_find_path (tree_view,
3118                                        tree_view->priv->prelight_tree,
3119                                        tree_view->priv->prelight_node);   
3120
3121       if (tree_view->priv->prelight_node->children)
3122         gtk_tree_view_collapse_row (tree_view, path);
3123       else
3124         gtk_tree_view_expand_row (tree_view, path, FALSE);
3125
3126       gtk_tree_path_free (path);
3127     }
3128
3129   tree_view->priv->auto_expand_timeout = 0;
3130
3131   return FALSE;
3132 }
3133
3134 static void
3135 remove_auto_expand_timeout (GtkTreeView *tree_view)
3136 {
3137   if (tree_view->priv->auto_expand_timeout != 0)
3138     {
3139       g_source_remove (tree_view->priv->auto_expand_timeout);
3140       tree_view->priv->auto_expand_timeout = 0;
3141     }
3142 }
3143
3144 static void
3145 do_prelight (GtkTreeView *tree_view,
3146              GtkRBTree   *tree,
3147              GtkRBNode   *node,
3148              /* these are in bin_window coords */
3149              gint         x,
3150              gint         y)
3151 {
3152   if (tree_view->priv->prelight_tree == tree &&
3153       tree_view->priv->prelight_node == node)
3154     {
3155       /*  We are still on the same node,
3156           but we might need to take care of the arrow  */
3157
3158       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3159         {
3160           gboolean over_arrow;
3161           gboolean flag_set;
3162
3163           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3164           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3165                                              GTK_TREE_VIEW_ARROW_PRELIT);
3166
3167           if (over_arrow != flag_set)
3168             {
3169               if (over_arrow)
3170                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3171                                         GTK_TREE_VIEW_ARROW_PRELIT);
3172               else
3173                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3174                                           GTK_TREE_VIEW_ARROW_PRELIT);
3175
3176               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3177             }
3178         }
3179
3180       return;
3181     }
3182
3183   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3184     {
3185       /*  Unprelight the old node and arrow  */
3186
3187       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3188                              GTK_RBNODE_IS_PRELIT);
3189
3190       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3191           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3192         {
3193           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3194           
3195           gtk_tree_view_draw_arrow (tree_view,
3196                                     tree_view->priv->prelight_tree,
3197                                     tree_view->priv->prelight_node,
3198                                     x,
3199                                     y);
3200         }
3201
3202       _gtk_tree_view_queue_draw_node (tree_view,
3203                                       tree_view->priv->prelight_tree,
3204                                       tree_view->priv->prelight_node,
3205                                       NULL);
3206     }
3207
3208
3209   if (tree_view->priv->hover_expand)
3210     remove_auto_expand_timeout (tree_view);
3211
3212   /*  Set the new prelight values  */
3213   tree_view->priv->prelight_node = node;
3214   tree_view->priv->prelight_tree = tree;
3215
3216   if (!node || !tree)
3217     return;
3218
3219   /*  Prelight the new node and arrow  */
3220
3221   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3222       && coords_are_over_arrow (tree_view, tree, node, x, y))
3223     {
3224       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3225
3226       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3227     }
3228
3229   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3230
3231   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3232
3233   if (tree_view->priv->hover_expand)
3234     {
3235       tree_view->priv->auto_expand_timeout = 
3236         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3237     }
3238 }
3239
3240 static void
3241 prelight_or_select (GtkTreeView *tree_view,
3242                     GtkRBTree   *tree,
3243                     GtkRBNode   *node,
3244                     /* these are in bin_window coords */
3245                     gint         x,
3246                     gint         y)
3247 {
3248   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3249   
3250   if (tree_view->priv->hover_selection &&
3251       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3252       !(tree_view->priv->edited_column &&
3253         tree_view->priv->edited_column->editable_widget))
3254     {
3255       if (node)
3256         {
3257           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3258             {
3259               GtkTreePath *path;
3260               
3261               path = _gtk_tree_view_find_path (tree_view, tree, node);
3262               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3263               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3264                 {
3265                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3266                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3267                 }
3268               gtk_tree_path_free (path);
3269             }
3270         }
3271
3272       else if (mode == GTK_SELECTION_SINGLE)
3273         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3274     }
3275
3276     do_prelight (tree_view, tree, node, x, y);
3277 }
3278
3279 static void
3280 ensure_unprelighted (GtkTreeView *tree_view)
3281 {
3282   do_prelight (tree_view,
3283                NULL, NULL,
3284                -1000, -1000); /* coords not possibly over an arrow */
3285
3286   g_assert (tree_view->priv->prelight_node == NULL);
3287 }
3288
3289
3290
3291
3292 /* Our motion arrow is either a box (in the case of the original spot)
3293  * or an arrow.  It is expander_size wide.
3294  */
3295 /*
3296  * 11111111111111
3297  * 01111111111110
3298  * 00111111111100
3299  * 00011111111000
3300  * 00001111110000
3301  * 00000111100000
3302  * 00000111100000
3303  * 00000111100000
3304  * ~ ~ ~ ~ ~ ~ ~
3305  * 00000111100000
3306  * 00000111100000
3307  * 00000111100000
3308  * 00001111110000
3309  * 00011111111000
3310  * 00111111111100
3311  * 01111111111110
3312  * 11111111111111
3313  */
3314
3315 static void
3316 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3317 {
3318   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3319   GtkWidget *widget = GTK_WIDGET (tree_view);
3320   GdkBitmap *mask = NULL;
3321   gint x;
3322   gint y;
3323   gint width;
3324   gint height;
3325   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3326   GdkWindowAttr attributes;
3327   guint attributes_mask;
3328
3329   if (!reorder ||
3330       reorder->left_column == tree_view->priv->drag_column ||
3331       reorder->right_column == tree_view->priv->drag_column)
3332     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3333   else if (reorder->left_column || reorder->right_column)
3334     {
3335       GdkRectangle visible_rect;
3336       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3337       if (reorder->left_column)
3338         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
3339       else
3340         x = reorder->right_column->button->allocation.x;
3341
3342       if (x < visible_rect.x)
3343         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3344       else if (x > visible_rect.x + visible_rect.width)
3345         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3346       else
3347         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3348     }
3349
3350   /* We want to draw the rectangle over the initial location. */
3351   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3352     {
3353       GdkGC *gc;
3354       GdkColor col;
3355
3356       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3357         {
3358           if (tree_view->priv->drag_highlight_window)
3359             {
3360               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3361                                         NULL);
3362               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3363             }
3364
3365           attributes.window_type = GDK_WINDOW_CHILD;
3366           attributes.wclass = GDK_INPUT_OUTPUT;
3367           attributes.x = tree_view->priv->drag_column_x;
3368           attributes.y = 0;
3369           width = attributes.width = tree_view->priv->drag_column->button->allocation.width;
3370           height = attributes.height = tree_view->priv->drag_column->button->allocation.height;
3371           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3372           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3373           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3374           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3375           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3376           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3377
3378           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3379           gc = gdk_gc_new (mask);
3380           col.pixel = 1;
3381           gdk_gc_set_foreground (gc, &col);
3382           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3383           col.pixel = 0;
3384           gdk_gc_set_foreground(gc, &col);
3385           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
3386           g_object_unref (gc);
3387
3388           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3389                                          mask, 0, 0);
3390           if (mask) g_object_unref (mask);
3391           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3392         }
3393     }
3394   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3395     {
3396       gint i, j = 1;
3397       GdkGC *gc;
3398       GdkColor col;
3399
3400       width = tree_view->priv->expander_size;
3401
3402       /* Get x, y, width, height of arrow */
3403       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3404       if (reorder->left_column)
3405         {
3406           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
3407           height = reorder->left_column->button->allocation.height;
3408         }
3409       else
3410         {
3411           x += reorder->right_column->button->allocation.x - width/2;
3412           height = reorder->right_column->button->allocation.height;
3413         }
3414       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3415       height += tree_view->priv->expander_size;
3416
3417       /* Create the new window */
3418       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3419         {
3420           if (tree_view->priv->drag_highlight_window)
3421             {
3422               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3423                                         NULL);
3424               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3425             }
3426
3427           attributes.window_type = GDK_WINDOW_TEMP;
3428           attributes.wclass = GDK_INPUT_OUTPUT;
3429           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3430           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3431           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3432           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3433           attributes.x = x;
3434           attributes.y = y;
3435           attributes.width = width;
3436           attributes.height = height;
3437           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3438                                                                    &attributes, attributes_mask);
3439           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3440
3441           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3442           gc = gdk_gc_new (mask);
3443           col.pixel = 1;
3444           gdk_gc_set_foreground (gc, &col);
3445           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3446
3447           /* Draw the 2 arrows as per above */
3448           col.pixel = 0;
3449           gdk_gc_set_foreground (gc, &col);
3450           for (i = 0; i < width; i ++)
3451             {
3452               if (i == (width/2 - 1))
3453                 continue;
3454               gdk_draw_line (mask, gc, i, j, i, height - j);
3455               if (i < (width/2 - 1))
3456                 j++;
3457               else
3458                 j--;
3459             }
3460           g_object_unref (gc);
3461           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3462                                          mask, 0, 0);
3463           if (mask) g_object_unref (mask);
3464         }
3465
3466       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3467       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3468     }
3469   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3470            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3471     {
3472       gint i, j = 1;
3473       GdkGC *gc;
3474       GdkColor col;
3475
3476       width = tree_view->priv->expander_size;
3477
3478       /* Get x, y, width, height of arrow */
3479       width = width/2; /* remember, the arrow only takes half the available width */
3480       gdk_window_get_origin (widget->window, &x, &y);
3481       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3482         x += widget->allocation.width - width;
3483
3484       if (reorder->left_column)
3485         height = reorder->left_column->button->allocation.height;
3486       else
3487         height = reorder->right_column->button->allocation.height;
3488
3489       y -= tree_view->priv->expander_size;
3490       height += 2*tree_view->priv->expander_size;
3491
3492       /* Create the new window */
3493       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3494           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3495         {
3496           if (tree_view->priv->drag_highlight_window)
3497             {
3498               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3499                                         NULL);
3500               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3501             }
3502
3503           attributes.window_type = GDK_WINDOW_TEMP;
3504           attributes.wclass = GDK_INPUT_OUTPUT;
3505           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3506           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3507           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3508           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3509           attributes.x = x;
3510           attributes.y = y;
3511           attributes.width = width;
3512           attributes.height = height;
3513           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3514           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3515
3516           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3517           gc = gdk_gc_new (mask);
3518           col.pixel = 1;
3519           gdk_gc_set_foreground (gc, &col);
3520           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3521
3522           /* Draw the 2 arrows as per above */
3523           col.pixel = 0;
3524           gdk_gc_set_foreground (gc, &col);
3525           j = tree_view->priv->expander_size;
3526           for (i = 0; i < width; i ++)
3527             {
3528               gint k;
3529               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3530                 k = width - i - 1;
3531               else
3532                 k = i;
3533               gdk_draw_line (mask, gc, k, j, k, height - j);
3534               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
3535               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
3536               j--;
3537             }
3538           g_object_unref (gc);
3539           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3540                                          mask, 0, 0);
3541           if (mask) g_object_unref (mask);
3542         }
3543
3544       tree_view->priv->drag_column_window_state = arrow_type;
3545       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3546    }
3547   else
3548     {
3549       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3550       gdk_window_hide (tree_view->priv->drag_highlight_window);
3551       return;
3552     }
3553
3554   gdk_window_show (tree_view->priv->drag_highlight_window);
3555   gdk_window_raise (tree_view->priv->drag_highlight_window);
3556 }
3557
3558 static gboolean
3559 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3560                                     GdkEventMotion *event)
3561 {
3562   gint x;
3563   gint new_width;
3564   GtkTreeViewColumn *column;
3565   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3566
3567   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3568
3569   if (event->is_hint || event->window != widget->window)
3570     gtk_widget_get_pointer (widget, &x, NULL);
3571   else
3572     x = event->x;
3573
3574   if (tree_view->priv->hadjustment)
3575     x += tree_view->priv->hadjustment->value;
3576
3577   new_width = gtk_tree_view_new_column_width (tree_view,
3578                                               tree_view->priv->drag_pos, &x);
3579   if (x != tree_view->priv->x_drag &&
3580       (new_width != column->fixed_width))
3581     {
3582       column->use_resized_width = TRUE;
3583       column->resized_width = new_width;
3584       if (column->expand)
3585         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3586       gtk_widget_queue_resize (widget);
3587     }
3588
3589   return FALSE;
3590 }
3591
3592
3593 static void
3594 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3595 {
3596   GtkTreeViewColumnReorder *reorder = NULL;
3597   GList *list;
3598   gint mouse_x;
3599
3600   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3601   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3602     {
3603       reorder = (GtkTreeViewColumnReorder *) list->data;
3604       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3605         break;
3606       reorder = NULL;
3607     }
3608
3609   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3610       return;*/
3611
3612   tree_view->priv->cur_reorder = reorder;
3613   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3614 }
3615
3616 static void
3617 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3618 {
3619   GdkRectangle visible_rect;
3620   gint y;
3621   gint offset;
3622   gfloat value;
3623
3624   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3625   y += tree_view->priv->dy;
3626
3627   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3628
3629   /* see if we are near the edge. */
3630   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3631   if (offset > 0)
3632     {
3633       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3634       if (offset < 0)
3635         return;
3636     }
3637
3638   value = CLAMP (tree_view->priv->vadjustment->value + offset, 0.0,
3639                  tree_view->priv->vadjustment->upper - tree_view->priv->vadjustment->page_size);
3640   gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
3641 }
3642
3643 static gboolean
3644 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3645 {
3646   GdkRectangle visible_rect;
3647   gint x;
3648   gint offset;
3649   gfloat value;
3650
3651   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3652
3653   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3654
3655   /* See if we are near the edge. */
3656   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3657   if (offset > 0)
3658     {
3659       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3660       if (offset < 0)
3661         return TRUE;
3662     }
3663   offset = offset/3;
3664
3665   value = CLAMP (tree_view->priv->hadjustment->value + offset,
3666                  0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
3667   gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
3668
3669   return TRUE;
3670
3671 }
3672
3673 static gboolean
3674 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3675                                   GdkEventMotion *event)
3676 {
3677   GtkTreeView *tree_view = (GtkTreeView *) widget;
3678   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3679   gint x, y;
3680
3681   /* Sanity Check */
3682   if ((column == NULL) ||
3683       (event->window != tree_view->priv->drag_window))
3684     return FALSE;
3685
3686   /* Handle moving the header */
3687   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3688   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3689              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
3690   gdk_window_move (tree_view->priv->drag_window, x, y);
3691   
3692   /* autoscroll, if needed */
3693   gtk_tree_view_horizontal_autoscroll (tree_view);
3694   /* Update the current reorder position and arrow; */
3695   gtk_tree_view_update_current_reorder (tree_view);
3696
3697   return TRUE;
3698 }
3699
3700 static void
3701 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3702 {
3703   remove_scroll_timeout (tree_view);
3704   gtk_grab_remove (GTK_WIDGET (tree_view));
3705
3706   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3707     {
3708       GtkTreePath *tmp_path;
3709
3710       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3711
3712       /* The anchor path should be set to the start path */
3713       tmp_path = _gtk_tree_view_find_path (tree_view,
3714                                            tree_view->priv->rubber_band_start_tree,
3715                                            tree_view->priv->rubber_band_start_node);
3716
3717       if (tree_view->priv->anchor)
3718         gtk_tree_row_reference_free (tree_view->priv->anchor);
3719
3720       tree_view->priv->anchor =
3721         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3722                                           tree_view->priv->model,
3723                                           tmp_path);
3724
3725       gtk_tree_path_free (tmp_path);
3726
3727       /* ... and the cursor to the end path */
3728       tmp_path = _gtk_tree_view_find_path (tree_view,
3729                                            tree_view->priv->rubber_band_end_tree,
3730                                            tree_view->priv->rubber_band_end_node);
3731       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3732       gtk_tree_path_free (tmp_path);
3733
3734       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3735     }
3736
3737   /* Clear status variables */
3738   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3739   tree_view->priv->rubber_band_shift = 0;
3740   tree_view->priv->rubber_band_ctrl = 0;
3741
3742   tree_view->priv->rubber_band_start_node = NULL;
3743   tree_view->priv->rubber_band_start_tree = NULL;
3744   tree_view->priv->rubber_band_end_node = NULL;
3745   tree_view->priv->rubber_band_end_tree = NULL;
3746 }
3747
3748 static void
3749 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3750                                                  GtkRBTree   *start_tree,
3751                                                  GtkRBNode   *start_node,
3752                                                  GtkRBTree   *end_tree,
3753                                                  GtkRBNode   *end_node,
3754                                                  gboolean     select,
3755                                                  gboolean     skip_start,
3756                                                  gboolean     skip_end)
3757 {
3758   if (start_node == end_node)
3759     return;
3760
3761   /* We skip the first node and jump inside the loop */
3762   if (skip_start)
3763     goto skip_first;
3764
3765   do
3766     {
3767       /* Small optimization by assuming insensitive nodes are never
3768        * selected.
3769        */
3770       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3771         {
3772           GtkTreePath *path;
3773           gboolean selectable;
3774
3775           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3776           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3777           gtk_tree_path_free (path);
3778
3779           if (!selectable)
3780             goto node_not_selectable;
3781         }
3782
3783       if (select)
3784         {
3785           if (tree_view->priv->rubber_band_shift)
3786             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3787           else if (tree_view->priv->rubber_band_ctrl)
3788             {
3789               /* Toggle the selection state */
3790               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3791                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3792               else
3793                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3794             }
3795           else
3796             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3797         }
3798       else
3799         {
3800           /* Mirror the above */
3801           if (tree_view->priv->rubber_band_shift)
3802             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3803           else if (tree_view->priv->rubber_band_ctrl)
3804             {
3805               /* Toggle the selection state */
3806               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3807                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3808               else
3809                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3810             }
3811           else
3812             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3813         }
3814
3815       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3816
3817 node_not_selectable:
3818       if (start_node == end_node)
3819         break;
3820
3821 skip_first:
3822
3823       if (start_node->children)
3824         {
3825           start_tree = start_node->children;
3826           start_node = start_tree->root;
3827           while (start_node->left != start_tree->nil)
3828             start_node = start_node->left;
3829         }
3830       else
3831         {
3832           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3833
3834           if (!start_tree)
3835             /* Ran out of tree */
3836             break;
3837         }
3838
3839       if (skip_end && start_node == end_node)
3840         break;
3841     }
3842   while (TRUE);
3843 }
3844
3845 static void
3846 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3847 {
3848   GtkRBTree *start_tree, *end_tree;
3849   GtkRBNode *start_node, *end_node;
3850
3851   _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);
3852   _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);
3853
3854   /* Handle the start area first */
3855   if (!tree_view->priv->rubber_band_start_node)
3856     {
3857       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3858                                                        start_tree,
3859                                                        start_node,
3860                                                        end_tree,
3861                                                        end_node,
3862                                                        TRUE,
3863                                                        FALSE,
3864                                                        FALSE);
3865     }
3866   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3867            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3868     {
3869       /* New node is above the old one; selection became bigger */
3870       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3871                                                        start_tree,
3872                                                        start_node,
3873                                                        tree_view->priv->rubber_band_start_tree,
3874                                                        tree_view->priv->rubber_band_start_node,
3875                                                        TRUE,
3876                                                        FALSE,
3877                                                        TRUE);
3878     }
3879   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3880            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3881     {
3882       /* New node is below the old one; selection became smaller */
3883       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3884                                                        tree_view->priv->rubber_band_start_tree,
3885                                                        tree_view->priv->rubber_band_start_node,
3886                                                        start_tree,
3887                                                        start_node,
3888                                                        FALSE,
3889                                                        FALSE,
3890                                                        TRUE);
3891     }
3892
3893   tree_view->priv->rubber_band_start_tree = start_tree;
3894   tree_view->priv->rubber_band_start_node = start_node;
3895
3896   /* Next, handle the end area */
3897   if (!tree_view->priv->rubber_band_end_node)
3898     {
3899       /* In the event this happens, start_node was also NULL; this case is
3900        * handled above.
3901        */
3902     }
3903   else if (!end_node)
3904     {
3905       /* Find the last node in the tree */
3906       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3907                                &end_tree, &end_node);
3908
3909       /* Selection reached end of the tree */
3910       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3911                                                        tree_view->priv->rubber_band_end_tree,
3912                                                        tree_view->priv->rubber_band_end_node,
3913                                                        end_tree,
3914                                                        end_node,
3915                                                        TRUE,
3916                                                        TRUE,
3917                                                        FALSE);
3918     }
3919   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3920            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3921     {
3922       /* New node is below the old one; selection became bigger */
3923       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3924                                                        tree_view->priv->rubber_band_end_tree,
3925                                                        tree_view->priv->rubber_band_end_node,
3926                                                        end_tree,
3927                                                        end_node,
3928                                                        TRUE,
3929                                                        TRUE,
3930                                                        FALSE);
3931     }
3932   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
3933            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3934     {
3935       /* New node is above the old one; selection became smaller */
3936       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3937                                                        end_tree,
3938                                                        end_node,
3939                                                        tree_view->priv->rubber_band_end_tree,
3940                                                        tree_view->priv->rubber_band_end_node,
3941                                                        FALSE,
3942                                                        TRUE,
3943                                                        FALSE);
3944     }
3945
3946   tree_view->priv->rubber_band_end_tree = end_tree;
3947   tree_view->priv->rubber_band_end_node = end_node;
3948 }
3949
3950 static void
3951 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
3952 {
3953   gint x, y;
3954   GdkRectangle old_area;
3955   GdkRectangle new_area;
3956   GdkRectangle common;
3957   GdkRegion *invalid_region;
3958
3959   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
3960   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
3961   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
3962   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
3963
3964   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
3965
3966   x = MAX (x, 0);
3967   y = MAX (y, 0) + tree_view->priv->dy;
3968
3969   new_area.x = MIN (tree_view->priv->press_start_x, x);
3970   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
3971   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
3972   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
3973
3974   invalid_region = gdk_region_rectangle (&old_area);
3975   gdk_region_union_with_rect (invalid_region, &new_area);
3976
3977   gdk_rectangle_intersect (&old_area, &new_area, &common);
3978   if (common.width > 2 && common.height > 2)
3979     {
3980       GdkRegion *common_region;
3981
3982       /* make sure the border is invalidated */
3983       common.x += 1;
3984       common.y += 1;
3985       common.width -= 2;
3986       common.height -= 2;
3987
3988       common_region = gdk_region_rectangle (&common);
3989
3990       gdk_region_subtract (invalid_region, common_region);
3991       gdk_region_destroy (common_region);
3992     }
3993
3994   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
3995
3996   gdk_region_destroy (invalid_region);
3997
3998   tree_view->priv->rubber_band_x = x;
3999   tree_view->priv->rubber_band_y = y;
4000
4001   gtk_tree_view_update_rubber_band_selection (tree_view);
4002 }
4003
4004 static void
4005 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4006                                 GdkRectangle *area)
4007 {
4008   cairo_t *cr;
4009   GdkRectangle rect;
4010   GdkRectangle rubber_rect;
4011
4012   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4013   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4014   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4015   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4016
4017   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
4018     return;
4019
4020   cr = gdk_cairo_create (tree_view->priv->bin_window);
4021   cairo_set_line_width (cr, 1.0);
4022
4023   cairo_set_source_rgba (cr,
4024                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4025                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4026                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
4027                          .25);
4028
4029   gdk_cairo_rectangle (cr, &rect);
4030   cairo_clip (cr);
4031   cairo_paint (cr);
4032
4033   cairo_set_source_rgb (cr,
4034                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4035                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4036                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
4037
4038   cairo_rectangle (cr,
4039                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4040                    rubber_rect.width - 1, rubber_rect.height - 1);
4041   cairo_stroke (cr);
4042
4043   cairo_destroy (cr);
4044 }
4045
4046 static gboolean
4047 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4048                                  GdkEventMotion *event)
4049 {
4050   GtkTreeView *tree_view;
4051   GtkRBTree *tree;
4052   GtkRBNode *node;
4053   gint new_y;
4054
4055   tree_view = (GtkTreeView *) widget;
4056
4057   if (tree_view->priv->tree == NULL)
4058     return FALSE;
4059
4060   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4061     {
4062       gtk_grab_add (GTK_WIDGET (tree_view));
4063       gtk_tree_view_update_rubber_band (tree_view);
4064
4065       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4066     }
4067   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4068     {
4069       gtk_tree_view_update_rubber_band (tree_view);
4070
4071       add_scroll_timeout (tree_view);
4072     }
4073
4074   /* only check for an initiated drag when a button is pressed */
4075   if (tree_view->priv->pressed_button >= 0
4076       && !tree_view->priv->rubber_band_status)
4077     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4078
4079   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4080   if (new_y < 0)
4081     new_y = 0;
4082
4083   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4084
4085   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4086   if ((tree_view->priv->button_pressed_node != NULL) &&
4087       (tree_view->priv->button_pressed_node != node))
4088     node = NULL;
4089
4090   prelight_or_select (tree_view, tree, node, event->x, event->y);
4091
4092   return TRUE;
4093 }
4094
4095 static gboolean
4096 gtk_tree_view_motion (GtkWidget      *widget,
4097                       GdkEventMotion *event)
4098 {
4099   GtkTreeView *tree_view;
4100
4101   tree_view = (GtkTreeView *) widget;
4102
4103   /* Resizing a column */
4104   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4105     return gtk_tree_view_motion_resize_column (widget, event);
4106
4107   /* Drag column */
4108   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4109     return gtk_tree_view_motion_drag_column (widget, event);
4110
4111   /* Sanity check it */
4112   if (event->window == tree_view->priv->bin_window)
4113     return gtk_tree_view_motion_bin_window (widget, event);
4114
4115   return FALSE;
4116 }
4117
4118 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4119  * the tree is empty.
4120  */
4121 static void
4122 invalidate_empty_focus (GtkTreeView *tree_view)
4123 {
4124   GdkRectangle area;
4125
4126   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4127     return;
4128
4129   area.x = 0;
4130   area.y = 0;
4131   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4132   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4133 }
4134
4135 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4136  * is empty.
4137  */
4138 static void
4139 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4140 {
4141   gint w, h;
4142
4143   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4144     return;
4145
4146   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4147
4148   w -= 2;
4149   h -= 2;
4150
4151   if (w > 0 && h > 0)
4152     gtk_paint_focus (GTK_WIDGET (tree_view)->style,
4153                      tree_view->priv->bin_window,
4154                      GTK_WIDGET_STATE (tree_view),
4155                      clip_area,
4156                      GTK_WIDGET (tree_view),
4157                      NULL,
4158                      1, 1, w, h);
4159 }
4160
4161 static void
4162 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4163                                GdkEventExpose *event,
4164                                gint            n_visible_columns)
4165 {
4166   GList *list = tree_view->priv->columns;
4167   gint i = 0;
4168   gint current_x = 0;
4169
4170   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4171       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4172     return;
4173
4174   /* Only draw the lines for visible rows and columns */
4175   for (list = tree_view->priv->columns; list; list = list->next, i++)
4176     {
4177       GtkTreeViewColumn *column = list->data;
4178
4179       /* We don't want a line for the last column */
4180       if (i == n_visible_columns - 1)
4181         break;
4182
4183       if (! column->visible)
4184         continue;
4185
4186       current_x += column->width;
4187
4188       gdk_draw_line (event->window,
4189                      tree_view->priv->grid_line_gc,
4190                      current_x - 1, 0,
4191                      current_x - 1, tree_view->priv->height);
4192     }
4193 }
4194
4195 /* Warning: Very scary function.
4196  * Modify at your own risk
4197  *
4198  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4199  * FIXME: It's not...
4200  */
4201 static gboolean
4202 gtk_tree_view_bin_expose (GtkWidget      *widget,
4203                           GdkEventExpose *event)
4204 {
4205   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4206   GtkTreePath *path;
4207   GtkRBTree *tree;
4208   GList *list;
4209   GtkRBNode *node;
4210   GtkRBNode *cursor = NULL;
4211   GtkRBTree *cursor_tree = NULL;
4212   GtkRBNode *drag_highlight = NULL;
4213   GtkRBTree *drag_highlight_tree = NULL;
4214   GtkTreeIter iter;
4215   gint new_y;
4216   gint y_offset, cell_offset;
4217   gint max_height;
4218   gint depth;
4219   GdkRectangle background_area;
4220   GdkRectangle cell_area;
4221   guint flags;
4222   gint highlight_x;
4223   gint expander_cell_width;
4224   gint bin_window_width;
4225   gint bin_window_height;
4226   GtkTreePath *cursor_path;
4227   GtkTreePath *drag_dest_path;
4228   GList *first_column, *last_column;
4229   gint vertical_separator;
4230   gint horizontal_separator;
4231   gint focus_line_width;
4232   gboolean allow_rules;
4233   gboolean has_special_cell;
4234   gboolean rtl;
4235   gint n_visible_columns;
4236   gint pointer_x, pointer_y;
4237   gint grid_line_width;
4238   gboolean got_pointer = FALSE;
4239   gboolean row_ending_details;
4240   gboolean draw_vgrid_lines, draw_hgrid_lines;
4241
4242   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4243
4244   gtk_widget_style_get (widget,
4245                         "horizontal-separator", &horizontal_separator,
4246                         "vertical-separator", &vertical_separator,
4247                         "allow-rules", &allow_rules,
4248                         "focus-line-width", &focus_line_width,
4249                         "row-ending-details", &row_ending_details,
4250                         NULL);
4251
4252   if (tree_view->priv->tree == NULL)
4253     {
4254       draw_empty_focus (tree_view, &event->area);
4255       return TRUE;
4256     }
4257
4258   /* clip event->area to the visible area */
4259   if (event->area.height < 0)
4260     return TRUE;
4261
4262   validate_visible_area (tree_view);
4263
4264   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4265
4266   if (new_y < 0)
4267     new_y = 0;
4268   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4269   gdk_drawable_get_size (tree_view->priv->bin_window,
4270                          &bin_window_width, &bin_window_height);
4271
4272   if (tree_view->priv->height < bin_window_height)
4273     {
4274       gtk_paint_flat_box (widget->style,
4275                           event->window,
4276                           widget->state,
4277                           GTK_SHADOW_NONE,
4278                           &event->area,
4279                           widget,
4280                           "cell_even",
4281                           0, tree_view->priv->height,
4282                           bin_window_width,
4283                           bin_window_height - tree_view->priv->height);
4284     }
4285
4286   if (node == NULL)
4287     return TRUE;
4288
4289   /* find the path for the node */
4290   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4291                                    tree,
4292                                    node);
4293   gtk_tree_model_get_iter (tree_view->priv->model,
4294                            &iter,
4295                            path);
4296   depth = gtk_tree_path_get_depth (path);
4297   gtk_tree_path_free (path);
4298   
4299   cursor_path = NULL;
4300   drag_dest_path = NULL;
4301
4302   if (tree_view->priv->cursor)
4303     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4304
4305   if (cursor_path)
4306     _gtk_tree_view_find_node (tree_view, cursor_path,
4307                               &cursor_tree, &cursor);
4308
4309   if (tree_view->priv->drag_dest_row)
4310     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4311
4312   if (drag_dest_path)
4313     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4314                               &drag_highlight_tree, &drag_highlight);
4315
4316   draw_vgrid_lines =
4317     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4318     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4319   draw_hgrid_lines =
4320     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4321     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4322
4323   if (draw_vgrid_lines || draw_hgrid_lines)
4324     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4325   
4326   n_visible_columns = 0;
4327   for (list = tree_view->priv->columns; list; list = list->next)
4328     {
4329       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4330         continue;
4331       n_visible_columns ++;
4332     }
4333
4334   /* Find the last column */
4335   for (last_column = g_list_last (tree_view->priv->columns);
4336        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4337        last_column = last_column->prev)
4338     ;
4339
4340   /* and the first */
4341   for (first_column = g_list_first (tree_view->priv->columns);
4342        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4343        first_column = first_column->next)
4344     ;
4345
4346   /* Actually process the expose event.  To do this, we want to
4347    * start at the first node of the event, and walk the tree in
4348    * order, drawing each successive node.
4349    */
4350
4351   do
4352     {
4353       gboolean parity;
4354       gboolean is_separator = FALSE;
4355       gboolean is_first = FALSE;
4356       gboolean is_last = FALSE;
4357       
4358       is_separator = row_is_separator (tree_view, &iter, NULL);
4359
4360       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4361
4362       cell_offset = 0;
4363       highlight_x = 0; /* should match x coord of first cell */
4364       expander_cell_width = 0;
4365
4366       background_area.y = y_offset + event->area.y;
4367       background_area.height = max_height;
4368
4369       flags = 0;
4370
4371       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4372         flags |= GTK_CELL_RENDERER_PRELIT;
4373
4374       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4375         flags |= GTK_CELL_RENDERER_SELECTED;
4376
4377       parity = _gtk_rbtree_node_find_parity (tree, node);
4378
4379       /* we *need* to set cell data on all cells before the call
4380        * to _has_special_cell, else _has_special_cell() does not
4381        * return a correct value.
4382        */
4383       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4384            list;
4385            list = (rtl ? list->prev : list->next))
4386         {
4387           GtkTreeViewColumn *column = list->data;
4388           gtk_tree_view_column_cell_set_cell_data (column,
4389                                                    tree_view->priv->model,
4390                                                    &iter,
4391                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4392                                                    node->children?TRUE:FALSE);
4393         }
4394
4395       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4396
4397       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4398            list;
4399            list = (rtl ? list->prev : list->next))
4400         {
4401           GtkTreeViewColumn *column = list->data;
4402           const gchar *detail = NULL;
4403           GtkStateType state;
4404
4405           if (!column->visible)
4406             continue;
4407
4408           if (cell_offset > event->area.x + event->area.width ||
4409               cell_offset + column->width < event->area.x)
4410             {
4411               cell_offset += column->width;
4412               continue;
4413             }
4414
4415           if (column->show_sort_indicator)
4416             flags |= GTK_CELL_RENDERER_SORTED;
4417           else
4418             flags &= ~GTK_CELL_RENDERER_SORTED;
4419
4420           if (cursor == node)
4421             flags |= GTK_CELL_RENDERER_FOCUSED;
4422           else
4423             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4424
4425           background_area.x = cell_offset;
4426           background_area.width = column->width;
4427
4428           cell_area = background_area;
4429           cell_area.y += vertical_separator / 2;
4430           cell_area.x += horizontal_separator / 2;
4431           cell_area.height -= vertical_separator;
4432           cell_area.width -= horizontal_separator;
4433
4434           if (draw_vgrid_lines)
4435             {
4436               if (list == first_column)
4437                 {
4438                   cell_area.width -= grid_line_width / 2;
4439                 }
4440               else if (list == last_column)
4441                 {
4442                   cell_area.x += grid_line_width / 2;
4443                   cell_area.width -= grid_line_width / 2;
4444                 }
4445               else
4446                 {
4447                   cell_area.x += grid_line_width / 2;
4448                   cell_area.width -= grid_line_width;
4449                 }
4450             }
4451
4452           if (draw_hgrid_lines)
4453             {
4454               cell_area.y += grid_line_width / 2;
4455               cell_area.height -= grid_line_width;
4456             }
4457
4458           if (gdk_region_rect_in (event->region, &background_area) == GDK_OVERLAP_RECTANGLE_OUT)
4459             {
4460               cell_offset += column->width;
4461               continue;
4462             }
4463
4464           gtk_tree_view_column_cell_set_cell_data (column,
4465                                                    tree_view->priv->model,
4466                                                    &iter,
4467                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4468                                                    node->children?TRUE:FALSE);
4469
4470           /* Select the detail for drawing the cell.  relevant
4471            * factors are parity, sortedness, and whether to
4472            * display rules.
4473            */
4474           if (allow_rules && tree_view->priv->has_rules)
4475             {
4476               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4477                   n_visible_columns >= 3)
4478                 {
4479                   if (parity)
4480                     detail = "cell_odd_ruled_sorted";
4481                   else
4482                     detail = "cell_even_ruled_sorted";
4483                 }
4484               else
4485                 {
4486                   if (parity)
4487                     detail = "cell_odd_ruled";
4488                   else
4489                     detail = "cell_even_ruled";
4490                 }
4491             }
4492           else
4493             {
4494               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4495                   n_visible_columns >= 3)
4496                 {
4497                   if (parity)
4498                     detail = "cell_odd_sorted";
4499                   else
4500                     detail = "cell_even_sorted";
4501                 }
4502               else
4503                 {
4504                   if (parity)
4505                     detail = "cell_odd";
4506                   else
4507                     detail = "cell_even";
4508                 }
4509             }
4510
4511           g_assert (detail);
4512
4513           if (widget->state == GTK_STATE_INSENSITIVE)
4514             state = GTK_STATE_INSENSITIVE;          
4515           else if (flags & GTK_CELL_RENDERER_SELECTED)
4516             state = GTK_STATE_SELECTED;
4517           else
4518             state = GTK_STATE_NORMAL;
4519
4520           /* Draw background */
4521           if (row_ending_details)
4522             {
4523               char new_detail[128];
4524
4525               is_first = (rtl ? !list->next : !list->prev);
4526               is_last = (rtl ? !list->prev : !list->next);
4527
4528               /* (I don't like the snprintfs either, but couldn't find a
4529                * less messy way).
4530                */
4531               if (is_first && is_last)
4532                 g_snprintf (new_detail, 127, "%s", detail);
4533               else if (is_first)
4534                 g_snprintf (new_detail, 127, "%s_start", detail);
4535               else if (is_last)
4536                 g_snprintf (new_detail, 127, "%s_end", detail);
4537               else
4538                 g_snprintf (new_detail, 128, "%s_middle", detail);
4539
4540               gtk_paint_flat_box (widget->style,
4541                                   event->window,
4542                                   state,
4543                                   GTK_SHADOW_NONE,
4544                                   &event->area,
4545                                   widget,
4546                                   new_detail,
4547                                   background_area.x,
4548                                   background_area.y,
4549                                   background_area.width,
4550                                   background_area.height);
4551             }
4552           else
4553             {
4554               gtk_paint_flat_box (widget->style,
4555                                   event->window,
4556                                   state,
4557                                   GTK_SHADOW_NONE,
4558                                   &event->area,
4559                                   widget,
4560                                   detail,
4561                                   background_area.x,
4562                                   background_area.y,
4563                                   background_area.width,
4564                                   background_area.height);
4565             }
4566
4567           if (draw_hgrid_lines)
4568             {
4569               if (background_area.y > 0)
4570                 gdk_draw_line (event->window,
4571                                tree_view->priv->grid_line_gc,
4572                                background_area.x, background_area.y,
4573                                background_area.x + background_area.width,
4574                                background_area.y);
4575
4576               if (y_offset + max_height >= event->area.height)
4577                 gdk_draw_line (event->window,
4578                                tree_view->priv->grid_line_gc,
4579                                background_area.x, background_area.y + max_height,
4580                                background_area.x + background_area.width,
4581                                background_area.y + max_height);
4582             }
4583
4584           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4585               tree_view->priv->tree_lines_enabled)
4586             {
4587               gint x = background_area.x;
4588               gint mult = rtl ? -1 : 1;
4589               gint y0 = background_area.y;
4590               gint y1 = background_area.y + background_area.height/2;
4591               gint y2 = background_area.y + background_area.height;
4592
4593               if (rtl)
4594                 x += background_area.width - 1;
4595
4596               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4597                   && depth > 1)
4598                 {
4599                   gdk_draw_line (event->window,
4600                                  tree_view->priv->tree_line_gc,
4601                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4602                                  y1,
4603                                  x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4604                                  y1);
4605                 }
4606               else if (depth > 1)
4607                 {
4608                   gdk_draw_line (event->window,
4609                                  tree_view->priv->tree_line_gc,
4610                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4611                                  y1,
4612                                  x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4613                                  y1);
4614                 }
4615
4616               if (depth > 1)
4617                 {
4618                   gint i;
4619                   GtkRBNode *tmp_node;
4620                   GtkRBTree *tmp_tree;
4621
4622                   if (!_gtk_rbtree_next (tree, node))
4623                     gdk_draw_line (event->window,
4624                                    tree_view->priv->tree_line_gc,
4625                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4626                                    y0,
4627                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4628                                    y1);
4629                   else
4630                     gdk_draw_line (event->window,
4631                                    tree_view->priv->tree_line_gc,
4632                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4633                                    y0,
4634                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4635                                    y2);
4636
4637                   tmp_node = tree->parent_node;
4638                   tmp_tree = tree->parent_tree;
4639
4640                   for (i = depth - 2; i > 0; i--)
4641                     {
4642                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4643                         gdk_draw_line (event->window,
4644                                        tree_view->priv->tree_line_gc,
4645                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4646                                        y0,
4647                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4648                                        y2);
4649
4650                       tmp_node = tmp_tree->parent_node;
4651                       tmp_tree = tmp_tree->parent_tree;
4652                     }
4653                 }
4654             }
4655
4656           if (gtk_tree_view_is_expander_column (tree_view, column))
4657             {
4658               if (!rtl)
4659                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4660               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4661
4662               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4663                 {
4664                   if (!rtl)
4665                     cell_area.x += depth * tree_view->priv->expander_size;
4666                   cell_area.width -= depth * tree_view->priv->expander_size;
4667                 }
4668
4669               /* If we have an expander column, the highlight underline
4670                * starts with that column, so that it indicates which
4671                * level of the tree we're dropping at.
4672                */
4673               highlight_x = cell_area.x;
4674               expander_cell_width = cell_area.width;
4675
4676               if (is_separator)
4677                 gtk_paint_hline (widget->style,
4678                                  event->window,
4679                                  state,
4680                                  &cell_area,
4681                                  widget,
4682                                  NULL,
4683                                  cell_area.x,
4684                                  cell_area.x + cell_area.width,
4685                                  cell_area.y + cell_area.height / 2);
4686               else
4687                 _gtk_tree_view_column_cell_render (column,
4688                                                    event->window,
4689                                                    &background_area,
4690                                                    &cell_area,
4691                                                    &event->area,
4692                                                    flags);
4693               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4694                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4695                 {
4696                   if (!got_pointer)
4697                     {
4698                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4699                                               &pointer_x, &pointer_y, NULL);
4700                       got_pointer = TRUE;
4701                     }
4702
4703                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4704                                             tree,
4705                                             node,
4706                                             pointer_x, pointer_y);
4707                 }
4708             }
4709           else
4710             {
4711               if (is_separator)
4712                 gtk_paint_hline (widget->style,
4713                                  event->window,
4714                                  state,
4715                                  &cell_area,
4716                                  widget,
4717                                  NULL,
4718                                  cell_area.x,
4719                                  cell_area.x + cell_area.width,
4720                                  cell_area.y + cell_area.height / 2);
4721               else
4722                 _gtk_tree_view_column_cell_render (column,
4723                                                    event->window,
4724                                                    &background_area,
4725                                                    &cell_area,
4726                                                    &event->area,
4727                                                    flags);
4728             }
4729           if (node == cursor && has_special_cell &&
4730               ((column == tree_view->priv->focus_column &&
4731                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4732                 GTK_WIDGET_HAS_FOCUS (widget)) ||
4733                (column == tree_view->priv->edited_column)))
4734             {
4735               _gtk_tree_view_column_cell_draw_focus (column,
4736                                                      event->window,
4737                                                      &background_area,
4738                                                      &cell_area,
4739                                                      &event->area,
4740                                                      flags);
4741             }
4742           cell_offset += column->width;
4743         }
4744
4745       if (node == drag_highlight)
4746         {
4747           /* Draw indicator for the drop
4748            */
4749           gint highlight_y = -1;
4750           GtkRBTree *tree = NULL;
4751           GtkRBNode *node = NULL;
4752           gint width;
4753
4754           switch (tree_view->priv->drag_dest_pos)
4755             {
4756             case GTK_TREE_VIEW_DROP_BEFORE:
4757               highlight_y = background_area.y - 1;
4758               if (highlight_y < 0)
4759                       highlight_y = 0;
4760               break;
4761
4762             case GTK_TREE_VIEW_DROP_AFTER:
4763               highlight_y = background_area.y + background_area.height - 1;
4764               break;
4765
4766             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4767             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4768               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4769
4770               if (tree == NULL)
4771                 break;
4772               gdk_drawable_get_size (tree_view->priv->bin_window,
4773                                      &width, NULL);
4774
4775               if (row_ending_details)
4776                 gtk_paint_focus (widget->style,
4777                                  tree_view->priv->bin_window,
4778                                  GTK_WIDGET_STATE (widget),
4779                                  &event->area,
4780                                  widget,
4781                                  (is_first
4782                                   ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4783                                   : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4784                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4785                                  - focus_line_width / 2,
4786                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4787                                - focus_line_width + 1);
4788               else
4789                 gtk_paint_focus (widget->style,
4790                                  tree_view->priv->bin_window,
4791                                  GTK_WIDGET_STATE (widget),
4792                                  &event->area,
4793                                  widget,
4794                                  "treeview-drop-indicator",
4795                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4796                                  - focus_line_width / 2,
4797                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4798                                  - focus_line_width + 1);
4799               break;
4800             }
4801
4802           if (highlight_y >= 0)
4803             {
4804               gdk_draw_line (event->window,
4805                              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
4806                              rtl ? highlight_x + expander_cell_width : highlight_x,
4807                              highlight_y,
4808                              rtl ? 0 : bin_window_width,
4809                              highlight_y);
4810             }
4811         }
4812
4813       /* draw the big row-spanning focus rectangle, if needed */
4814       if (!has_special_cell && node == cursor &&
4815           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4816           GTK_WIDGET_HAS_FOCUS (widget))
4817         {
4818           gint tmp_y, tmp_height;
4819           gint width;
4820           GtkStateType focus_rect_state;
4821
4822           focus_rect_state =
4823             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4824             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4825              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4826               GTK_STATE_NORMAL));
4827
4828           gdk_drawable_get_size (tree_view->priv->bin_window,
4829                                  &width, NULL);
4830           
4831           if (draw_hgrid_lines)
4832             {
4833               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4834               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4835             }
4836           else
4837             {
4838               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4839               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4840             }
4841
4842           if (row_ending_details)
4843             gtk_paint_focus (widget->style,
4844                              tree_view->priv->bin_window,
4845                              focus_rect_state,
4846                              &event->area,
4847                              widget,
4848                              (is_first
4849                               ? (is_last ? "treeview" : "treeview-left" )
4850                               : (is_last ? "treeview-right" : "treeview-middle" )),
4851                              0, tmp_y,
4852                              width, tmp_height);
4853           else
4854             gtk_paint_focus (widget->style,
4855                              tree_view->priv->bin_window,
4856                              focus_rect_state,
4857                              &event->area,
4858                              widget,
4859                              "treeview",
4860                              0, tmp_y,
4861                              width, tmp_height);
4862         }
4863
4864       y_offset += max_height;
4865       if (node->children)
4866         {
4867           GtkTreeIter parent = iter;
4868           gboolean has_child;
4869
4870           tree = node->children;
4871           node = tree->root;
4872
4873           g_assert (node != tree->nil);
4874
4875           while (node->left != tree->nil)
4876             node = node->left;
4877           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4878                                                     &iter,
4879                                                     &parent);
4880           depth++;
4881
4882           /* Sanity Check! */
4883           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4884         }
4885       else
4886         {
4887           gboolean done = FALSE;
4888
4889           do
4890             {
4891               node = _gtk_rbtree_next (tree, node);
4892               if (node != NULL)
4893                 {
4894                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4895                   done = TRUE;
4896
4897                   /* Sanity Check! */
4898                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4899                 }
4900               else
4901                 {
4902                   GtkTreeIter parent_iter = iter;
4903                   gboolean has_parent;
4904
4905                   node = tree->parent_node;
4906                   tree = tree->parent_tree;
4907                   if (tree == NULL)
4908                     /* we should go to done to free some memory */
4909                     goto done;
4910                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4911                                                            &iter,
4912                                                            &parent_iter);
4913                   depth--;
4914
4915                   /* Sanity check */
4916                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
4917                 }
4918             }
4919           while (!done);
4920         }
4921     }
4922   while (y_offset < event->area.height);
4923
4924 done:
4925   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
4926
4927  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4928    {
4929      GdkRectangle *rectangles;
4930      gint n_rectangles;
4931
4932      gdk_region_get_rectangles (event->region,
4933                                 &rectangles,
4934                                 &n_rectangles);
4935
4936      while (n_rectangles--)
4937        gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
4938
4939      g_free (rectangles);
4940    }
4941
4942   if (cursor_path)
4943     gtk_tree_path_free (cursor_path);
4944
4945   if (drag_dest_path)
4946     gtk_tree_path_free (drag_dest_path);
4947
4948   return FALSE;
4949 }
4950
4951 static gboolean
4952 gtk_tree_view_expose (GtkWidget      *widget,
4953                       GdkEventExpose *event)
4954 {
4955   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4956
4957   if (event->window == tree_view->priv->bin_window)
4958     {
4959       gboolean retval;
4960       GList *tmp_list;
4961
4962       retval = gtk_tree_view_bin_expose (widget, event);
4963
4964       /* We can't just chain up to Container::expose as it will try to send the
4965        * event to the headers, so we handle propagating it to our children
4966        * (eg. widgets being edited) ourselves.
4967        */
4968       tmp_list = tree_view->priv->children;
4969       while (tmp_list)
4970         {
4971           GtkTreeViewChild *child = tmp_list->data;
4972           tmp_list = tmp_list->next;
4973
4974           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
4975         }
4976
4977       return retval;
4978     }
4979
4980   else if (event->window == tree_view->priv->header_window)
4981     {
4982       GList *list;
4983       
4984       for (list = tree_view->priv->columns; list != NULL; list = list->next)
4985         {
4986           GtkTreeViewColumn *column = list->data;
4987
4988           if (column == tree_view->priv->drag_column)
4989             continue;
4990
4991           if (column->visible)
4992             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4993                                             column->button,
4994                                             event);
4995         }
4996     }
4997   else if (event->window == tree_view->priv->drag_window)
4998     {
4999       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5000                                       tree_view->priv->drag_column->button,
5001                                       event);
5002     }
5003   return TRUE;
5004 }
5005
5006 enum
5007 {
5008   DROP_HOME,
5009   DROP_RIGHT,
5010   DROP_LEFT,
5011   DROP_END
5012 };
5013
5014 /* returns 0x1 when no column has been found -- yes it's hackish */
5015 static GtkTreeViewColumn *
5016 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5017                                GtkTreeViewColumn *column,
5018                                gint               drop_position)
5019 {
5020   GtkTreeViewColumn *left_column = NULL;
5021   GtkTreeViewColumn *cur_column = NULL;
5022   GList *tmp_list;
5023
5024   if (!column->reorderable)
5025     return (GtkTreeViewColumn *)0x1;
5026
5027   switch (drop_position)
5028     {
5029       case DROP_HOME:
5030         /* find first column where we can drop */
5031         tmp_list = tree_view->priv->columns;
5032         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5033           return (GtkTreeViewColumn *)0x1;
5034
5035         while (tmp_list)
5036           {
5037             g_assert (tmp_list);
5038
5039             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5040             tmp_list = tmp_list->next;
5041
5042             if (left_column && left_column->visible == FALSE)
5043               continue;
5044
5045             if (!tree_view->priv->column_drop_func)
5046               return left_column;
5047
5048             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5049               {
5050                 left_column = cur_column;
5051                 continue;
5052               }
5053
5054             return left_column;
5055           }
5056
5057         if (!tree_view->priv->column_drop_func)
5058           return left_column;
5059
5060         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5061           return left_column;
5062         else
5063           return (GtkTreeViewColumn *)0x1;
5064         break;
5065
5066       case DROP_RIGHT:
5067         /* find first column after column where we can drop */
5068         tmp_list = tree_view->priv->columns;
5069
5070         for (; tmp_list; tmp_list = tmp_list->next)
5071           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5072             break;
5073
5074         if (!tmp_list || !tmp_list->next)
5075           return (GtkTreeViewColumn *)0x1;
5076
5077         tmp_list = tmp_list->next;
5078         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5079         tmp_list = tmp_list->next;
5080
5081         while (tmp_list)
5082           {
5083             g_assert (tmp_list);
5084
5085             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5086             tmp_list = tmp_list->next;
5087
5088             if (left_column && left_column->visible == FALSE)
5089               {
5090                 left_column = cur_column;
5091                 if (tmp_list)
5092                   tmp_list = tmp_list->next;
5093                 continue;
5094               }
5095
5096             if (!tree_view->priv->column_drop_func)
5097               return left_column;
5098
5099             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5100               {
5101                 left_column = cur_column;
5102                 continue;
5103               }
5104
5105             return left_column;
5106           }
5107
5108         if (!tree_view->priv->column_drop_func)
5109           return left_column;
5110
5111         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5112           return left_column;
5113         else
5114           return (GtkTreeViewColumn *)0x1;
5115         break;
5116
5117       case DROP_LEFT:
5118         /* find first column before column where we can drop */
5119         tmp_list = tree_view->priv->columns;
5120
5121         for (; tmp_list; tmp_list = tmp_list->next)
5122           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5123             break;
5124
5125         if (!tmp_list || !tmp_list->prev)
5126           return (GtkTreeViewColumn *)0x1;
5127
5128         tmp_list = tmp_list->prev;
5129         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5130         tmp_list = tmp_list->prev;
5131
5132         while (tmp_list)
5133           {
5134             g_assert (tmp_list);
5135
5136             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5137
5138             if (left_column && !left_column->visible)
5139               {
5140                 /*if (!tmp_list->prev)
5141                   return (GtkTreeViewColumn *)0x1;
5142                   */
5143 /*
5144                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5145                 tmp_list = tmp_list->prev->prev;
5146                 continue;*/
5147
5148                 cur_column = left_column;
5149                 if (tmp_list)
5150                   tmp_list = tmp_list->prev;
5151                 continue;
5152               }
5153
5154             if (!tree_view->priv->column_drop_func)
5155               return left_column;
5156
5157             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5158               return left_column;
5159
5160             cur_column = left_column;
5161             tmp_list = tmp_list->prev;
5162           }
5163
5164         if (!tree_view->priv->column_drop_func)
5165           return NULL;
5166
5167         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5168           return NULL;
5169         else
5170           return (GtkTreeViewColumn *)0x1;
5171         break;
5172
5173       case DROP_END:
5174         /* same as DROP_HOME case, but doing it backwards */
5175         tmp_list = g_list_last (tree_view->priv->columns);
5176         cur_column = NULL;
5177
5178         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5179           return (GtkTreeViewColumn *)0x1;
5180
5181         while (tmp_list)
5182           {
5183             g_assert (tmp_list);
5184
5185             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5186
5187             if (left_column && !left_column->visible)
5188               {
5189                 cur_column = left_column;
5190                 tmp_list = tmp_list->prev;
5191               }
5192
5193             if (!tree_view->priv->column_drop_func)
5194               return left_column;
5195
5196             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5197               return left_column;
5198
5199             cur_column = left_column;
5200             tmp_list = tmp_list->prev;
5201           }
5202
5203         if (!tree_view->priv->column_drop_func)
5204           return NULL;
5205
5206         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5207           return NULL;
5208         else
5209           return (GtkTreeViewColumn *)0x1;
5210         break;
5211     }
5212
5213   return (GtkTreeViewColumn *)0x1;
5214 }
5215
5216 static gboolean
5217 gtk_tree_view_key_press (GtkWidget   *widget,
5218                          GdkEventKey *event)
5219 {
5220   GtkTreeView *tree_view = (GtkTreeView *) widget;
5221
5222   if (tree_view->priv->rubber_band_status)
5223     {
5224       if (event->keyval == GDK_Escape)
5225         gtk_tree_view_stop_rubber_band (tree_view);
5226
5227       return TRUE;
5228     }
5229
5230   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5231     {
5232       if (event->keyval == GDK_Escape)
5233         {
5234           tree_view->priv->cur_reorder = NULL;
5235           gtk_tree_view_button_release_drag_column (widget, NULL);
5236         }
5237       return TRUE;
5238     }
5239
5240   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5241     {
5242       GList *focus_column;
5243       gboolean rtl;
5244
5245       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5246
5247       for (focus_column = tree_view->priv->columns;
5248            focus_column;
5249            focus_column = focus_column->next)
5250         {
5251           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5252
5253           if (GTK_WIDGET_HAS_FOCUS (column->button))
5254             break;
5255         }
5256
5257       if (focus_column &&
5258           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5259           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5260            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
5261         {
5262           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5263
5264           if (!column->resizable)
5265             {
5266               gtk_widget_error_bell (widget);
5267               return TRUE;
5268             }
5269
5270           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5271               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5272             {
5273               gint old_width = column->resized_width;
5274
5275               column->resized_width = MAX (column->resized_width,
5276                                            column->width);
5277               column->resized_width -= 2;
5278               if (column->resized_width < 0)
5279                 column->resized_width = 0;
5280
5281               if (column->min_width == -1)
5282                 column->resized_width = MAX (column->button->requisition.width,
5283                                              column->resized_width);
5284               else
5285                 column->resized_width = MAX (column->min_width,
5286                                              column->resized_width);
5287
5288               if (column->max_width != -1)
5289                 column->resized_width = MIN (column->resized_width,
5290                                              column->max_width);
5291
5292               column->use_resized_width = TRUE;
5293
5294               if (column->resized_width != old_width)
5295                 gtk_widget_queue_resize (widget);
5296               else
5297                 gtk_widget_error_bell (widget);
5298             }
5299           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5300                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5301             {
5302               gint old_width = column->resized_width;
5303
5304               column->resized_width = MAX (column->resized_width,
5305                                            column->width);
5306               column->resized_width += 2;
5307
5308               if (column->max_width != -1)
5309                 column->resized_width = MIN (column->resized_width,
5310                                              column->max_width);
5311
5312               column->use_resized_width = TRUE;
5313
5314               if (column->resized_width != old_width)
5315                 gtk_widget_queue_resize (widget);
5316               else
5317                 gtk_widget_error_bell (widget);
5318             }
5319
5320           return TRUE;
5321         }
5322
5323       if (focus_column &&
5324           (event->state & GDK_MOD1_MASK) &&
5325           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5326            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
5327            || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
5328            || event->keyval == GDK_End || event->keyval == GDK_KP_End))
5329         {
5330           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5331
5332           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5333               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5334             {
5335               GtkTreeViewColumn *col;
5336               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5337               if (col != (GtkTreeViewColumn *)0x1)
5338                 gtk_tree_view_move_column_after (tree_view, column, col);
5339               else
5340                 gtk_widget_error_bell (widget);
5341             }
5342           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5343                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5344             {
5345               GtkTreeViewColumn *col;
5346               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5347               if (col != (GtkTreeViewColumn *)0x1)
5348                 gtk_tree_view_move_column_after (tree_view, column, col);
5349               else
5350                 gtk_widget_error_bell (widget);
5351             }
5352           else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
5353             {
5354               GtkTreeViewColumn *col;
5355               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5356               if (col != (GtkTreeViewColumn *)0x1)
5357                 gtk_tree_view_move_column_after (tree_view, column, col);
5358               else
5359                 gtk_widget_error_bell (widget);
5360             }
5361           else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
5362             {
5363               GtkTreeViewColumn *col;
5364               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5365               if (col != (GtkTreeViewColumn *)0x1)
5366                 gtk_tree_view_move_column_after (tree_view, column, col);
5367               else
5368                 gtk_widget_error_bell (widget);
5369             }
5370
5371           return TRUE;
5372         }
5373     }
5374
5375   /* Chain up to the parent class.  It handles the keybindings. */
5376   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5377     return TRUE;
5378
5379   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5380     {
5381       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5382       return FALSE;
5383     }
5384
5385   /* We pass the event to the search_entry.  If its text changes, then we start
5386    * the typeahead find capabilities. */
5387   if (GTK_WIDGET_HAS_FOCUS (tree_view)
5388       && tree_view->priv->enable_search
5389       && !tree_view->priv->search_custom_entry_set)
5390     {
5391       GdkEvent *new_event;
5392       char *old_text;
5393       const char *new_text;
5394       gboolean retval;
5395       GdkScreen *screen;
5396       gboolean text_modified;
5397       gulong popup_menu_id;
5398
5399       gtk_tree_view_ensure_interactive_directory (tree_view);
5400
5401       /* Make a copy of the current text */
5402       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5403       new_event = gdk_event_copy ((GdkEvent *) event);
5404       g_object_unref (((GdkEventKey *) new_event)->window);
5405       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5406       gtk_widget_realize (tree_view->priv->search_window);
5407
5408       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5409                                         "popup-menu", G_CALLBACK (gtk_true),
5410                                         NULL);
5411
5412       /* Move the entry off screen */
5413       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5414       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5415                        gdk_screen_get_width (screen) + 1,
5416                        gdk_screen_get_height (screen) + 1);
5417       gtk_widget_show (tree_view->priv->search_window);
5418
5419       /* Send the event to the window.  If the preedit_changed signal is emitted
5420        * during this event, we will set priv->imcontext_changed  */
5421       tree_view->priv->imcontext_changed = FALSE;
5422       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5423       gdk_event_free (new_event);
5424       gtk_widget_hide (tree_view->priv->search_window);
5425
5426       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5427                                    popup_menu_id);
5428
5429       /* We check to make sure that the entry tried to handle the text, and that
5430        * the text has changed.
5431        */
5432       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5433       text_modified = strcmp (old_text, new_text) != 0;
5434       g_free (old_text);
5435       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5436           (retval && text_modified))               /* ...or the text was modified */
5437         {
5438           if (gtk_tree_view_real_start_interactive_search (tree_view, FALSE))
5439             {
5440               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5441               return TRUE;
5442             }
5443           else
5444             {
5445               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5446               return FALSE;
5447             }
5448         }
5449     }
5450
5451   return FALSE;
5452 }
5453
5454 static gboolean
5455 gtk_tree_view_key_release (GtkWidget   *widget,
5456                            GdkEventKey *event)
5457 {
5458   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5459
5460   if (tree_view->priv->rubber_band_status)
5461     return TRUE;
5462
5463   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5464 }
5465
5466 /* FIXME Is this function necessary? Can I get an enter_notify event
5467  * w/o either an expose event or a mouse motion event?
5468  */
5469 static gboolean
5470 gtk_tree_view_enter_notify (GtkWidget        *widget,
5471                             GdkEventCrossing *event)
5472 {
5473   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5474   GtkRBTree *tree;
5475   GtkRBNode *node;
5476   gint new_y;
5477
5478   /* Sanity check it */
5479   if (event->window != tree_view->priv->bin_window)
5480     return FALSE;
5481
5482   if (tree_view->priv->tree == NULL)
5483     return FALSE;
5484
5485   /* find the node internally */
5486   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5487   if (new_y < 0)
5488     new_y = 0;
5489   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5490
5491   if ((tree_view->priv->button_pressed_node == NULL) ||
5492       (tree_view->priv->button_pressed_node == node))
5493     prelight_or_select (tree_view, tree, node, event->x, event->y);
5494
5495   return TRUE;
5496 }
5497
5498 static gboolean
5499 gtk_tree_view_leave_notify (GtkWidget        *widget,
5500                             GdkEventCrossing *event)
5501 {
5502   GtkTreeView *tree_view;
5503
5504   if (event->mode == GDK_CROSSING_GRAB)
5505     return TRUE;
5506
5507   tree_view = GTK_TREE_VIEW (widget);
5508
5509   if (tree_view->priv->prelight_node)
5510     _gtk_tree_view_queue_draw_node (tree_view,
5511                                    tree_view->priv->prelight_tree,
5512                                    tree_view->priv->prelight_node,
5513                                    NULL);
5514
5515   prelight_or_select (tree_view,
5516                       NULL, NULL,
5517                       -1000, -1000); /* coords not possibly over an arrow */
5518
5519   return TRUE;
5520 }
5521
5522
5523 static gint
5524 gtk_tree_view_focus_out (GtkWidget     *widget,
5525                          GdkEventFocus *event)
5526 {
5527   GtkTreeView *tree_view;
5528
5529   tree_view = GTK_TREE_VIEW (widget);
5530
5531   gtk_widget_queue_draw (widget);
5532
5533   /* destroy interactive search dialog */
5534   if (tree_view->priv->search_window)
5535     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
5536
5537   return FALSE;
5538 }
5539
5540
5541 /* Incremental Reflow
5542  */
5543
5544 static void
5545 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5546                                  GtkRBTree   *tree,
5547                                  GtkRBNode   *node)
5548 {
5549   gint y;
5550
5551   y = _gtk_rbtree_node_find_offset (tree, node)
5552     - tree_view->priv->vadjustment->value
5553     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5554
5555   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5556                               0, y,
5557                               GTK_WIDGET (tree_view)->allocation.width,
5558                               GTK_RBNODE_GET_HEIGHT (node));
5559 }
5560
5561 static gboolean
5562 node_is_visible (GtkTreeView *tree_view,
5563                  GtkRBTree   *tree,
5564                  GtkRBNode   *node)
5565 {
5566   int y;
5567   int height;
5568
5569   y = _gtk_rbtree_node_find_offset (tree, node);
5570   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5571
5572   if (y >= tree_view->priv->vadjustment->value &&
5573       y + height <= (tree_view->priv->vadjustment->value
5574                      + tree_view->priv->vadjustment->page_size))
5575     return TRUE;
5576
5577   return FALSE;
5578 }
5579
5580 /* Returns TRUE if it updated the size
5581  */
5582 static gboolean
5583 validate_row (GtkTreeView *tree_view,
5584               GtkRBTree   *tree,
5585               GtkRBNode   *node,
5586               GtkTreeIter *iter,
5587               GtkTreePath *path)
5588 {
5589   GtkTreeViewColumn *column;
5590   GList *list, *first_column, *last_column;
5591   gint height = 0;
5592   gint horizontal_separator;
5593   gint vertical_separator;
5594   gint focus_line_width;
5595   gint depth = gtk_tree_path_get_depth (path);
5596   gboolean retval = FALSE;
5597   gboolean is_separator = FALSE;
5598   gboolean draw_vgrid_lines, draw_hgrid_lines;
5599   gint focus_pad;
5600   gint grid_line_width;
5601   gboolean wide_separators;
5602   gint separator_height;
5603
5604   /* double check the row needs validating */
5605   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5606       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5607     return FALSE;
5608
5609   is_separator = row_is_separator (tree_view, iter, NULL);
5610
5611   gtk_widget_style_get (GTK_WIDGET (tree_view),
5612                         "focus-padding", &focus_pad,
5613                         "focus-line-width", &focus_line_width,
5614                         "horizontal-separator", &horizontal_separator,
5615                         "vertical-separator", &vertical_separator,
5616                         "grid-line-width", &grid_line_width,
5617                         "wide-separators",  &wide_separators,
5618                         "separator-height", &separator_height,
5619                         NULL);
5620   
5621   draw_vgrid_lines =
5622     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5623     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5624   draw_hgrid_lines =
5625     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5626     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5627
5628   for (last_column = g_list_last (tree_view->priv->columns);
5629        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5630        last_column = last_column->prev)
5631     ;
5632
5633   for (first_column = g_list_first (tree_view->priv->columns);
5634        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5635        first_column = first_column->next)
5636     ;
5637
5638   for (list = tree_view->priv->columns; list; list = list->next)
5639     {
5640       gint tmp_width;
5641       gint tmp_height;
5642
5643       column = list->data;
5644
5645       if (! column->visible)
5646         continue;
5647
5648       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5649         continue;
5650
5651       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5652                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5653                                                node->children?TRUE:FALSE);
5654       gtk_tree_view_column_cell_get_size (column,
5655                                           NULL, NULL, NULL,
5656                                           &tmp_width, &tmp_height);
5657
5658       if (!is_separator)
5659         {
5660           tmp_height += vertical_separator;
5661           height = MAX (height, tmp_height);
5662           height = MAX (height, tree_view->priv->expander_size);
5663         }
5664       else
5665         {
5666           if (wide_separators)
5667             height = separator_height + 2 * focus_pad;
5668           else
5669             height = 2 + 2 * focus_pad;
5670         }
5671
5672       if (gtk_tree_view_is_expander_column (tree_view, column))
5673         {
5674           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5675
5676           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5677             tmp_width += depth * tree_view->priv->expander_size;
5678         }
5679       else
5680         tmp_width = tmp_width + horizontal_separator;
5681
5682       if (draw_vgrid_lines)
5683         {
5684           if (list->data == first_column || list->data == last_column)
5685             tmp_width += grid_line_width / 2.0;
5686           else
5687             tmp_width += grid_line_width;
5688         }
5689
5690       if (tmp_width > column->requested_width)
5691         {
5692           retval = TRUE;
5693           column->requested_width = tmp_width;
5694         }
5695     }
5696
5697   if (draw_hgrid_lines)
5698     height += grid_line_width;
5699
5700   if (height != GTK_RBNODE_GET_HEIGHT (node))
5701     {
5702       retval = TRUE;
5703       _gtk_rbtree_node_set_height (tree, node, height);
5704     }
5705   _gtk_rbtree_node_mark_valid (tree, node);
5706   tree_view->priv->post_validation_flag = TRUE;
5707
5708   return retval;
5709 }
5710
5711
5712 static void
5713 validate_visible_area (GtkTreeView *tree_view)
5714 {
5715   GtkTreePath *path = NULL;
5716   GtkTreePath *above_path = NULL;
5717   GtkTreeIter iter;
5718   GtkRBTree *tree = NULL;
5719   GtkRBNode *node = NULL;
5720   gboolean need_redraw = FALSE;
5721   gboolean size_changed = FALSE;
5722   gint total_height;
5723   gint area_above = 0;
5724   gint area_below = 0;
5725
5726   if (tree_view->priv->tree == NULL)
5727     return;
5728
5729   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5730       tree_view->priv->scroll_to_path == NULL)
5731     return;
5732
5733   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5734
5735   if (total_height == 0)
5736     return;
5737
5738   /* First, we check to see if we need to scroll anywhere
5739    */
5740   if (tree_view->priv->scroll_to_path)
5741     {
5742       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5743       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5744         {
5745           /* we are going to scroll, and will update dy */
5746           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5747           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5748               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5749             {
5750               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5751               if (validate_row (tree_view, tree, node, &iter, path))
5752                 size_changed = TRUE;
5753             }
5754
5755           if (tree_view->priv->scroll_to_use_align)
5756             {
5757               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5758               area_above = (total_height - height) *
5759                 tree_view->priv->scroll_to_row_align;
5760               area_below = total_height - area_above - height;
5761               area_above = MAX (area_above, 0);
5762               area_below = MAX (area_below, 0);
5763             }
5764           else
5765             {
5766               /* two cases:
5767                * 1) row not visible
5768                * 2) row visible
5769                */
5770               gint dy;
5771               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5772
5773               dy = _gtk_rbtree_node_find_offset (tree, node);
5774
5775               if (dy >= tree_view->priv->vadjustment->value &&
5776                   dy + height <= (tree_view->priv->vadjustment->value
5777                                   + tree_view->priv->vadjustment->page_size))
5778                 {
5779                   /* row visible: keep the row at the same position */
5780                   area_above = dy - tree_view->priv->vadjustment->value;
5781                   area_below = (tree_view->priv->vadjustment->value +
5782                                 tree_view->priv->vadjustment->page_size)
5783                                - dy - height;
5784                 }
5785               else
5786                 {
5787                   /* row not visible */
5788                   if (dy >= 0
5789                       && dy + height <= tree_view->priv->vadjustment->page_size)
5790                     {
5791                       /* row at the beginning -- fixed */
5792                       area_above = dy;
5793                       area_below = tree_view->priv->vadjustment->page_size
5794                                    - area_above - height;
5795                     }
5796                   else if (dy >= (tree_view->priv->vadjustment->upper -
5797                                   tree_view->priv->vadjustment->page_size))
5798                     {
5799                       /* row at the end -- fixed */
5800                       area_above = dy - (tree_view->priv->vadjustment->upper -
5801                                    tree_view->priv->vadjustment->page_size);
5802                       area_below = tree_view->priv->vadjustment->page_size -
5803                                    area_above - height;
5804
5805                       if (area_below < 0)
5806                         {
5807                           area_above = tree_view->priv->vadjustment->page_size - height;
5808                           area_below = 0;
5809                         }
5810                     }
5811                   else
5812                     {
5813                       /* row somewhere in the middle, bring it to the top
5814                        * of the view
5815                        */
5816                       area_above = 0;
5817                       area_below = total_height - height;
5818                     }
5819                 }
5820             }
5821         }
5822       else
5823         /* the scroll to isn't valid; ignore it.
5824          */
5825         {
5826           if (tree_view->priv->scroll_to_path && !path)
5827             {
5828               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5829               tree_view->priv->scroll_to_path = NULL;
5830             }
5831           if (path)
5832             gtk_tree_path_free (path);
5833           path = NULL;
5834         }      
5835     }
5836
5837   /* We didn't have a scroll_to set, so we just handle things normally
5838    */
5839   if (path == NULL)
5840     {
5841       gint offset;
5842
5843       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5844                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5845                                         &tree, &node);
5846       if (node == NULL)
5847         {
5848           /* In this case, nothing has been validated */
5849           path = gtk_tree_path_new_first ();
5850           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5851         }
5852       else
5853         {
5854           path = _gtk_tree_view_find_path (tree_view, tree, node);
5855           total_height += offset;
5856         }
5857
5858       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5859
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       area_above = 0;
5868       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5869     }
5870
5871   above_path = gtk_tree_path_copy (path);
5872
5873   /* if we do not validate any row above the new top_row, we will make sure
5874    * that the row immediately above top_row has been validated. (if we do not
5875    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5876    * when invalidated that row's height will be zero. and this will mess up
5877    * scrolling).
5878    */
5879   if (area_above == 0)
5880     {
5881       GtkRBTree *tmptree;
5882       GtkRBNode *tmpnode;
5883
5884       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5885       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5886
5887       if (tmpnode)
5888         {
5889           GtkTreePath *tmppath;
5890           GtkTreeIter tmpiter;
5891
5892           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5893           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5894
5895           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
5896               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
5897             {
5898               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
5899               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
5900                 size_changed = TRUE;
5901             }
5902
5903           gtk_tree_path_free (tmppath);
5904         }
5905     }
5906
5907   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
5908    * backwards is much slower then forward, as there is no iter_prev function.
5909    * We go forwards first in case we run out of tree.  Then we go backwards to
5910    * fill out the top.
5911    */
5912   while (node && area_below > 0)
5913     {
5914       if (node->children)
5915         {
5916           GtkTreeIter parent = iter;
5917           gboolean has_child;
5918
5919           tree = node->children;
5920           node = tree->root;
5921
5922           g_assert (node != tree->nil);
5923
5924           while (node->left != tree->nil)
5925             node = node->left;
5926           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5927                                                     &iter,
5928                                                     &parent);
5929           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
5930           gtk_tree_path_down (path);
5931         }
5932       else
5933         {
5934           gboolean done = FALSE;
5935           do
5936             {
5937               node = _gtk_rbtree_next (tree, node);
5938               if (node != NULL)
5939                 {
5940                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5941                   done = TRUE;
5942                   gtk_tree_path_next (path);
5943
5944                   /* Sanity Check! */
5945                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
5946                 }
5947               else
5948                 {
5949                   GtkTreeIter parent_iter = iter;
5950                   gboolean has_parent;
5951
5952                   node = tree->parent_node;
5953                   tree = tree->parent_tree;
5954                   if (tree == NULL)
5955                     break;
5956                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5957                                                            &iter,
5958                                                            &parent_iter);
5959                   gtk_tree_path_up (path);
5960
5961                   /* Sanity check */
5962                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
5963                 }
5964             }
5965           while (!done);
5966         }
5967
5968       if (!node)
5969         break;
5970
5971       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5972           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5973         {
5974           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5975           if (validate_row (tree_view, tree, node, &iter, path))
5976               size_changed = TRUE;
5977         }
5978
5979       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5980     }
5981   gtk_tree_path_free (path);
5982
5983   /* If we ran out of tree, and have extra area_below left, we need to add it
5984    * to area_above */
5985   if (area_below > 0)
5986     area_above += area_below;
5987
5988   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
5989
5990   /* We walk backwards */
5991   while (area_above > 0)
5992     {
5993       _gtk_rbtree_prev_full (tree, node, &tree, &node);
5994       if (! gtk_tree_path_prev (above_path) && node != NULL)
5995         {
5996           gtk_tree_path_free (above_path);
5997           above_path = _gtk_tree_view_find_path (tree_view, tree, node);
5998         }
5999       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6000
6001       if (node == NULL)
6002         break;
6003
6004       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6005           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6006         {
6007           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6008           if (validate_row (tree_view, tree, node, &iter, above_path))
6009             size_changed = TRUE;
6010         }
6011       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6012     }
6013
6014   /* if we scrolled to a path, we need to set the dy here,
6015    * and sync the top row accordingly
6016    */
6017   if (tree_view->priv->scroll_to_path)
6018     {
6019       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6020       gtk_tree_view_top_row_to_dy (tree_view);
6021
6022       need_redraw = TRUE;
6023     }
6024   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6025     {
6026       /* when we are not scrolling, we should never set dy to something
6027        * else than zero. we update top_row to be in sync with dy = 0.
6028        */
6029       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6030       gtk_tree_view_dy_to_top_row (tree_view);
6031     }
6032   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6033     {
6034       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6035       gtk_tree_view_dy_to_top_row (tree_view);
6036     }
6037   else
6038     gtk_tree_view_top_row_to_dy (tree_view);
6039
6040   /* update width/height and queue a resize */
6041   if (size_changed)
6042     {
6043       GtkRequisition requisition;
6044
6045       /* We temporarily guess a size, under the assumption that it will be the
6046        * same when we get our next size_allocate.  If we don't do this, we'll be
6047        * in an inconsistent state if we call top_row_to_dy. */
6048
6049       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6050       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6051       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6052       gtk_adjustment_changed (tree_view->priv->hadjustment);
6053       gtk_adjustment_changed (tree_view->priv->vadjustment);
6054       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6055     }
6056
6057   if (tree_view->priv->scroll_to_path)
6058     {
6059       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6060       tree_view->priv->scroll_to_path = NULL;
6061     }
6062
6063   if (above_path)
6064     gtk_tree_path_free (above_path);
6065
6066   if (tree_view->priv->scroll_to_column)
6067     {
6068       tree_view->priv->scroll_to_column = NULL;
6069     }
6070   if (need_redraw)
6071     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6072 }
6073
6074 static void
6075 initialize_fixed_height_mode (GtkTreeView *tree_view)
6076 {
6077   if (!tree_view->priv->tree)
6078     return;
6079
6080   if (tree_view->priv->fixed_height < 0)
6081     {
6082       GtkTreeIter iter;
6083       GtkTreePath *path;
6084
6085       GtkRBTree *tree = NULL;
6086       GtkRBNode *node = NULL;
6087
6088       tree = tree_view->priv->tree;
6089       node = tree->root;
6090
6091       path = _gtk_tree_view_find_path (tree_view, tree, node);
6092       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6093
6094       validate_row (tree_view, tree, node, &iter, path);
6095
6096       gtk_tree_path_free (path);
6097
6098       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6099     }
6100
6101    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6102                                  tree_view->priv->fixed_height, TRUE);
6103 }
6104
6105 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6106  * the left-most uninvalidated node.  We then try walking right, validating
6107  * nodes.  Once we find a valid node, we repeat the previous process of finding
6108  * the first invalid node.
6109  */
6110
6111 static gboolean
6112 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6113 {
6114   GtkRBTree *tree = NULL;
6115   GtkRBNode *node = NULL;
6116   gboolean validated_area = FALSE;
6117   gint retval = TRUE;
6118   GtkTreePath *path = NULL;
6119   GtkTreeIter iter;
6120   GTimer *timer;
6121   gint i = 0;
6122
6123   gint prev_height = -1;
6124   gboolean fixed_height = TRUE;
6125
6126   g_assert (tree_view);
6127
6128   if (tree_view->priv->tree == NULL)
6129       return FALSE;
6130
6131   if (tree_view->priv->fixed_height_mode)
6132     {
6133       if (tree_view->priv->fixed_height < 0)
6134         initialize_fixed_height_mode (tree_view);
6135
6136       return FALSE;
6137     }
6138
6139   timer = g_timer_new ();
6140   g_timer_start (timer);
6141
6142   do
6143     {
6144       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6145         {
6146           retval = FALSE;
6147           goto done;
6148         }
6149
6150       if (path != NULL)
6151         {
6152           node = _gtk_rbtree_next (tree, node);
6153           if (node != NULL)
6154             {
6155               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6156               gtk_tree_path_next (path);
6157             }
6158           else
6159             {
6160               gtk_tree_path_free (path);
6161               path = NULL;
6162             }
6163         }
6164
6165       if (path == NULL)
6166         {
6167           tree = tree_view->priv->tree;
6168           node = tree_view->priv->tree->root;
6169
6170           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6171
6172           do
6173             {
6174               if (node->left != tree->nil &&
6175                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6176                 {
6177                   node = node->left;
6178                 }
6179               else if (node->right != tree->nil &&
6180                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6181                 {
6182                   node = node->right;
6183                 }
6184               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6185                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6186                 {
6187                   break;
6188                 }
6189               else if (node->children != NULL)
6190                 {
6191                   tree = node->children;
6192                   node = tree->root;
6193                 }
6194               else
6195                 /* RBTree corruption!  All bad */
6196                 g_assert_not_reached ();
6197             }
6198           while (TRUE);
6199           path = _gtk_tree_view_find_path (tree_view, tree, node);
6200           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6201         }
6202
6203       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6204                        validated_area;
6205
6206       if (!tree_view->priv->fixed_height_check)
6207         {
6208           gint height;
6209
6210           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6211           if (prev_height < 0)
6212             prev_height = height;
6213           else if (prev_height != height)
6214             fixed_height = FALSE;
6215         }
6216
6217       i++;
6218     }
6219   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6220
6221   if (!tree_view->priv->fixed_height_check)
6222    {
6223      if (fixed_height)
6224        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6225
6226      tree_view->priv->fixed_height_check = 1;
6227    }
6228   
6229  done:
6230   if (validated_area)
6231     {
6232       GtkRequisition requisition;
6233       /* We temporarily guess a size, under the assumption that it will be the
6234        * same when we get our next size_allocate.  If we don't do this, we'll be
6235        * in an inconsistent state when we call top_row_to_dy. */
6236
6237       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6238       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6239       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6240       gtk_adjustment_changed (tree_view->priv->hadjustment);
6241       gtk_adjustment_changed (tree_view->priv->vadjustment);
6242
6243       if (queue_resize)
6244         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6245     }
6246
6247   if (path) gtk_tree_path_free (path);
6248   g_timer_destroy (timer);
6249
6250   return retval;
6251 }
6252
6253 static gboolean
6254 validate_rows (GtkTreeView *tree_view)
6255 {
6256   gboolean retval;
6257   
6258   retval = do_validate_rows (tree_view, TRUE);
6259   
6260   if (! retval && tree_view->priv->validate_rows_timer)
6261     {
6262       g_source_remove (tree_view->priv->validate_rows_timer);
6263       tree_view->priv->validate_rows_timer = 0;
6264     }
6265
6266   return retval;
6267 }
6268
6269 static gboolean
6270 validate_rows_handler (GtkTreeView *tree_view)
6271 {
6272   gboolean retval;
6273
6274   retval = do_validate_rows (tree_view, TRUE);
6275   if (! retval && tree_view->priv->validate_rows_timer)
6276     {
6277       g_source_remove (tree_view->priv->validate_rows_timer);
6278       tree_view->priv->validate_rows_timer = 0;
6279     }
6280
6281   return retval;
6282 }
6283
6284 static gboolean
6285 do_presize_handler (GtkTreeView *tree_view)
6286 {
6287   if (tree_view->priv->mark_rows_col_dirty)
6288     {
6289       if (tree_view->priv->tree)
6290         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6291       tree_view->priv->mark_rows_col_dirty = FALSE;
6292     }
6293   validate_visible_area (tree_view);
6294   tree_view->priv->presize_handler_timer = 0;
6295
6296   if (tree_view->priv->fixed_height_mode)
6297     {
6298       GtkRequisition requisition;
6299
6300       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6301
6302       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6303       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6304       gtk_adjustment_changed (tree_view->priv->hadjustment);
6305       gtk_adjustment_changed (tree_view->priv->vadjustment);
6306       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6307     }
6308                    
6309   return FALSE;
6310 }
6311
6312 static gboolean
6313 presize_handler_callback (gpointer data)
6314 {
6315   do_presize_handler (GTK_TREE_VIEW (data));
6316                    
6317   return FALSE;
6318 }
6319
6320 static void
6321 install_presize_handler (GtkTreeView *tree_view)
6322 {
6323   if (! GTK_WIDGET_REALIZED (tree_view))
6324     return;
6325
6326   if (! tree_view->priv->presize_handler_timer)
6327     {
6328       tree_view->priv->presize_handler_timer =
6329         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6330     }
6331   if (! tree_view->priv->validate_rows_timer)
6332     {
6333       tree_view->priv->validate_rows_timer =
6334         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6335     }
6336 }
6337
6338 static gboolean
6339 scroll_sync_handler (GtkTreeView *tree_view)
6340 {
6341   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6342     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6343   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6344     gtk_tree_view_top_row_to_dy (tree_view);
6345   else
6346     gtk_tree_view_dy_to_top_row (tree_view);
6347
6348   tree_view->priv->scroll_sync_timer = 0;
6349
6350   return FALSE;
6351 }
6352
6353 static void
6354 install_scroll_sync_handler (GtkTreeView *tree_view)
6355 {
6356   if (! GTK_WIDGET_REALIZED (tree_view))
6357     return;
6358
6359   if (!tree_view->priv->scroll_sync_timer)
6360     {
6361       tree_view->priv->scroll_sync_timer =
6362         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6363     }
6364 }
6365
6366 static void
6367 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6368                            GtkTreePath *path,
6369                            gint         offset)
6370 {
6371   gtk_tree_row_reference_free (tree_view->priv->top_row);
6372
6373   if (!path)
6374     {
6375       tree_view->priv->top_row = NULL;
6376       tree_view->priv->top_row_dy = 0;
6377     }
6378   else
6379     {
6380       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6381       tree_view->priv->top_row_dy = offset;
6382     }
6383 }
6384
6385 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6386  * it's set to be NULL, and top_row_dy is 0;
6387  */
6388 static void
6389 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6390 {
6391   gint offset;
6392   GtkTreePath *path;
6393   GtkRBTree *tree;
6394   GtkRBNode *node;
6395
6396   if (tree_view->priv->tree == NULL)
6397     {
6398       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6399     }
6400   else
6401     {
6402       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6403                                         tree_view->priv->dy,
6404                                         &tree, &node);
6405
6406       if (tree == NULL)
6407         {
6408           tree_view->priv->top_row = NULL;
6409           tree_view->priv->top_row_dy = 0;
6410         }
6411       else
6412         {
6413           path = _gtk_tree_view_find_path (tree_view, tree, node);
6414           gtk_tree_view_set_top_row (tree_view, path, offset);
6415           gtk_tree_path_free (path);
6416         }
6417     }
6418 }
6419
6420 static void
6421 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6422 {
6423   GtkTreePath *path;
6424   GtkRBTree *tree;
6425   GtkRBNode *node;
6426   int new_dy;
6427
6428   if (tree_view->priv->top_row)
6429     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6430   else
6431     path = NULL;
6432
6433   if (!path)
6434     tree = NULL;
6435   else
6436     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6437
6438   if (path)
6439     gtk_tree_path_free (path);
6440
6441   if (tree == NULL)
6442     {
6443       /* keep dy and set new toprow */
6444       gtk_tree_row_reference_free (tree_view->priv->top_row);
6445       tree_view->priv->top_row = NULL;
6446       tree_view->priv->top_row_dy = 0;
6447       /* DO NOT install the idle handler */
6448       gtk_tree_view_dy_to_top_row (tree_view);
6449       return;
6450     }
6451
6452   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6453       < tree_view->priv->top_row_dy)
6454     {
6455       /* new top row -- do NOT install the idle handler */
6456       gtk_tree_view_dy_to_top_row (tree_view);
6457       return;
6458     }
6459
6460   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6461   new_dy += tree_view->priv->top_row_dy;
6462
6463   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6464     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6465
6466   new_dy = MAX (0, new_dy);
6467
6468   tree_view->priv->in_top_row_to_dy = TRUE;
6469   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6470   tree_view->priv->in_top_row_to_dy = FALSE;
6471 }
6472
6473
6474 void
6475 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6476 {
6477   tree_view->priv->mark_rows_col_dirty = TRUE;
6478
6479   install_presize_handler (tree_view);
6480 }
6481
6482 /*
6483  * This function works synchronously (due to the while (validate_rows...)
6484  * loop).
6485  *
6486  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6487  * here. You now need to check that yourself.
6488  */
6489 void
6490 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6491                                 GtkTreeViewColumn *column)
6492 {
6493   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6494   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6495
6496   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6497
6498   do_presize_handler (tree_view);
6499   while (validate_rows (tree_view));
6500
6501   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6502 }
6503
6504 /* Drag-and-drop */
6505
6506 static void
6507 set_source_row (GdkDragContext *context,
6508                 GtkTreeModel   *model,
6509                 GtkTreePath    *source_row)
6510 {
6511   g_object_set_data_full (G_OBJECT (context),
6512                           I_("gtk-tree-view-source-row"),
6513                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6514                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6515 }
6516
6517 static GtkTreePath*
6518 get_source_row (GdkDragContext *context)
6519 {
6520   GtkTreeRowReference *ref =
6521     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6522
6523   if (ref)
6524     return gtk_tree_row_reference_get_path (ref);
6525   else
6526     return NULL;
6527 }
6528
6529 typedef struct
6530 {
6531   GtkTreeRowReference *dest_row;
6532   guint                path_down_mode   : 1;
6533   guint                empty_view_drop  : 1;
6534   guint                drop_append_mode : 1;
6535 }
6536 DestRow;
6537
6538 static void
6539 dest_row_free (gpointer data)
6540 {
6541   DestRow *dr = (DestRow *)data;
6542
6543   gtk_tree_row_reference_free (dr->dest_row);
6544   g_slice_free (DestRow, dr);
6545 }
6546
6547 static void
6548 set_dest_row (GdkDragContext *context,
6549               GtkTreeModel   *model,
6550               GtkTreePath    *dest_row,
6551               gboolean        path_down_mode,
6552               gboolean        empty_view_drop,
6553               gboolean        drop_append_mode)
6554 {
6555   DestRow *dr;
6556
6557   if (!dest_row)
6558     {
6559       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6560                               NULL, NULL);
6561       return;
6562     }
6563
6564   dr = g_slice_new (DestRow);
6565
6566   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6567   dr->path_down_mode = path_down_mode != FALSE;
6568   dr->empty_view_drop = empty_view_drop != FALSE;
6569   dr->drop_append_mode = drop_append_mode != FALSE;
6570
6571   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6572                           dr, (GDestroyNotify) dest_row_free);
6573 }
6574
6575 static GtkTreePath*
6576 get_dest_row (GdkDragContext *context,
6577               gboolean       *path_down_mode)
6578 {
6579   DestRow *dr =
6580     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6581
6582   if (dr)
6583     {
6584       GtkTreePath *path = NULL;
6585
6586       if (path_down_mode)
6587         *path_down_mode = dr->path_down_mode;
6588
6589       if (dr->dest_row)
6590         path = gtk_tree_row_reference_get_path (dr->dest_row);
6591       else if (dr->empty_view_drop)
6592         path = gtk_tree_path_new_from_indices (0, -1);
6593       else
6594         path = NULL;
6595
6596       if (path && dr->drop_append_mode)
6597         gtk_tree_path_next (path);
6598
6599       return path;
6600     }
6601   else
6602     return NULL;
6603 }
6604
6605 /* Get/set whether drag_motion requested the drag data and
6606  * drag_data_received should thus not actually insert the data,
6607  * since the data doesn't result from a drop.
6608  */
6609 static void
6610 set_status_pending (GdkDragContext *context,
6611                     GdkDragAction   suggested_action)
6612 {
6613   g_object_set_data (G_OBJECT (context),
6614                      I_("gtk-tree-view-status-pending"),
6615                      GINT_TO_POINTER (suggested_action));
6616 }
6617
6618 static GdkDragAction
6619 get_status_pending (GdkDragContext *context)
6620 {
6621   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6622                                              "gtk-tree-view-status-pending"));
6623 }
6624
6625 static TreeViewDragInfo*
6626 get_info (GtkTreeView *tree_view)
6627 {
6628   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6629 }
6630
6631 static void
6632 destroy_info (TreeViewDragInfo *di)
6633 {
6634   g_slice_free (TreeViewDragInfo, di);
6635 }
6636
6637 static TreeViewDragInfo*
6638 ensure_info (GtkTreeView *tree_view)
6639 {
6640   TreeViewDragInfo *di;
6641
6642   di = get_info (tree_view);
6643
6644   if (di == NULL)
6645     {
6646       di = g_slice_new0 (TreeViewDragInfo);
6647
6648       g_object_set_data_full (G_OBJECT (tree_view),
6649                               I_("gtk-tree-view-drag-info"),
6650                               di,
6651                               (GDestroyNotify) destroy_info);
6652     }
6653
6654   return di;
6655 }
6656
6657 static void
6658 remove_info (GtkTreeView *tree_view)
6659 {
6660   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6661 }
6662
6663 #if 0
6664 static gint
6665 drag_scan_timeout (gpointer data)
6666 {
6667   GtkTreeView *tree_view;
6668   gint x, y;
6669   GdkModifierType state;
6670   GtkTreePath *path = NULL;
6671   GtkTreeViewColumn *column = NULL;
6672   GdkRectangle visible_rect;
6673
6674   GDK_THREADS_ENTER ();
6675
6676   tree_view = GTK_TREE_VIEW (data);
6677
6678   gdk_window_get_pointer (tree_view->priv->bin_window,
6679                           &x, &y, &state);
6680
6681   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6682
6683   /* See if we are near the edge. */
6684   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6685       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6686       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6687       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6688     {
6689       gtk_tree_view_get_path_at_pos (tree_view,
6690                                      tree_view->priv->bin_window,
6691                                      x, y,
6692                                      &path,
6693                                      &column,
6694                                      NULL,
6695                                      NULL);
6696
6697       if (path != NULL)
6698         {
6699           gtk_tree_view_scroll_to_cell (tree_view,
6700                                         path,
6701                                         column,
6702                                         TRUE,
6703                                         0.5, 0.5);
6704
6705           gtk_tree_path_free (path);
6706         }
6707     }
6708
6709   GDK_THREADS_LEAVE ();
6710
6711   return TRUE;
6712 }
6713 #endif /* 0 */
6714
6715 static void
6716 add_scroll_timeout (GtkTreeView *tree_view)
6717 {
6718   if (tree_view->priv->scroll_timeout == 0)
6719     {
6720       tree_view->priv->scroll_timeout =
6721         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6722     }
6723 }
6724
6725 static void
6726 remove_scroll_timeout (GtkTreeView *tree_view)
6727 {
6728   if (tree_view->priv->scroll_timeout != 0)
6729     {
6730       g_source_remove (tree_view->priv->scroll_timeout);
6731       tree_view->priv->scroll_timeout = 0;
6732     }
6733 }
6734
6735 static gboolean
6736 check_model_dnd (GtkTreeModel *model,
6737                  GType         required_iface,
6738                  const gchar  *signal)
6739 {
6740   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6741     {
6742       g_warning ("You must override the default '%s' handler "
6743                  "on GtkTreeView when using models that don't support "
6744                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6745                  "is to connect to '%s' and call "
6746                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6747                  "the default handler from running. Look at the source code "
6748                  "for the default handler in gtktreeview.c to get an idea what "
6749                  "your handler should do. (gtktreeview.c is in the GTK source "
6750                  "code.) If you're using GTK from a language other than C, "
6751                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6752                  signal, g_type_name (required_iface), signal);
6753       return FALSE;
6754     }
6755   else
6756     return TRUE;
6757 }
6758
6759 static void
6760 remove_open_timeout (GtkTreeView *tree_view)
6761 {
6762   if (tree_view->priv->open_dest_timeout != 0)
6763     {
6764       g_source_remove (tree_view->priv->open_dest_timeout);
6765       tree_view->priv->open_dest_timeout = 0;
6766     }
6767 }
6768
6769
6770 static gint
6771 open_row_timeout (gpointer data)
6772 {
6773   GtkTreeView *tree_view = data;
6774   GtkTreePath *dest_path = NULL;
6775   GtkTreeViewDropPosition pos;
6776   gboolean result = FALSE;
6777
6778   gtk_tree_view_get_drag_dest_row (tree_view,
6779                                    &dest_path,
6780                                    &pos);
6781
6782   if (dest_path &&
6783       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6784        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6785     {
6786       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6787       tree_view->priv->open_dest_timeout = 0;
6788
6789       gtk_tree_path_free (dest_path);
6790     }
6791   else
6792     {
6793       if (dest_path)
6794         gtk_tree_path_free (dest_path);
6795
6796       result = TRUE;
6797     }
6798
6799   return result;
6800 }
6801
6802 static gboolean
6803 scroll_row_timeout (gpointer data)
6804 {
6805   GtkTreeView *tree_view = data;
6806
6807   gtk_tree_view_vertical_autoscroll (tree_view);
6808
6809   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6810     gtk_tree_view_update_rubber_band (tree_view);
6811
6812   return TRUE;
6813 }
6814
6815 /* Returns TRUE if event should not be propagated to parent widgets */
6816 static gboolean
6817 set_destination_row (GtkTreeView    *tree_view,
6818                      GdkDragContext *context,
6819                      /* coordinates relative to the widget */
6820                      gint            x,
6821                      gint            y,
6822                      GdkDragAction  *suggested_action,
6823                      GdkAtom        *target)
6824 {
6825   GtkTreePath *path = NULL;
6826   GtkTreeViewDropPosition pos;
6827   GtkTreeViewDropPosition old_pos;
6828   TreeViewDragInfo *di;
6829   GtkWidget *widget;
6830   GtkTreePath *old_dest_path = NULL;
6831   gboolean can_drop = FALSE;
6832
6833   *suggested_action = 0;
6834   *target = GDK_NONE;
6835
6836   widget = GTK_WIDGET (tree_view);
6837
6838   di = get_info (tree_view);
6839
6840   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6841     {
6842       /* someone unset us as a drag dest, note that if
6843        * we return FALSE drag_leave isn't called
6844        */
6845
6846       gtk_tree_view_set_drag_dest_row (tree_view,
6847                                        NULL,
6848                                        GTK_TREE_VIEW_DROP_BEFORE);
6849
6850       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6851       remove_open_timeout (GTK_TREE_VIEW (widget));
6852
6853       return FALSE; /* no longer a drop site */
6854     }
6855
6856   *target = gtk_drag_dest_find_target (widget, context,
6857                                        gtk_drag_dest_get_target_list (widget));
6858   if (*target == GDK_NONE)
6859     {
6860       return FALSE;
6861     }
6862
6863   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6864                                           x, y,
6865                                           &path,
6866                                           &pos))
6867     {
6868       gint n_children;
6869       GtkTreeModel *model;
6870
6871       remove_open_timeout (tree_view);
6872
6873       /* the row got dropped on empty space, let's setup a special case
6874        */
6875
6876       if (path)
6877         gtk_tree_path_free (path);
6878
6879       model = gtk_tree_view_get_model (tree_view);
6880
6881       n_children = gtk_tree_model_iter_n_children (model, NULL);
6882       if (n_children)
6883         {
6884           pos = GTK_TREE_VIEW_DROP_AFTER;
6885           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6886         }
6887       else
6888         {
6889           pos = GTK_TREE_VIEW_DROP_BEFORE;
6890           path = gtk_tree_path_new_from_indices (0, -1);
6891         }
6892
6893       can_drop = TRUE;
6894
6895       goto out;
6896     }
6897
6898   g_assert (path);
6899
6900   /* If we left the current row's "open" zone, unset the timeout for
6901    * opening the row
6902    */
6903   gtk_tree_view_get_drag_dest_row (tree_view,
6904                                    &old_dest_path,
6905                                    &old_pos);
6906
6907   if (old_dest_path &&
6908       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
6909        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6910          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
6911     remove_open_timeout (tree_view);
6912
6913   if (old_dest_path)
6914     gtk_tree_path_free (old_dest_path);
6915
6916   if (TRUE /* FIXME if the location droppable predicate */)
6917     {
6918       can_drop = TRUE;
6919     }
6920
6921 out:
6922   if (can_drop)
6923     {
6924       GtkWidget *source_widget;
6925
6926       *suggested_action = context->suggested_action;
6927       source_widget = gtk_drag_get_source_widget (context);
6928
6929       if (source_widget == widget)
6930         {
6931           /* Default to MOVE, unless the user has
6932            * pressed ctrl or shift to affect available actions
6933            */
6934           if ((context->actions & GDK_ACTION_MOVE) != 0)
6935             *suggested_action = GDK_ACTION_MOVE;
6936         }
6937
6938       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6939                                        path, pos);
6940     }
6941   else
6942     {
6943       /* can't drop here */
6944       remove_open_timeout (tree_view);
6945
6946       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6947                                        NULL,
6948                                        GTK_TREE_VIEW_DROP_BEFORE);
6949     }
6950
6951   if (path)
6952     gtk_tree_path_free (path);
6953
6954   return TRUE;
6955 }
6956
6957 static GtkTreePath*
6958 get_logical_dest_row (GtkTreeView *tree_view,
6959                       gboolean    *path_down_mode,
6960                       gboolean    *drop_append_mode)
6961 {
6962   /* adjust path to point to the row the drop goes in front of */
6963   GtkTreePath *path = NULL;
6964   GtkTreeViewDropPosition pos;
6965
6966   g_return_val_if_fail (path_down_mode != NULL, NULL);
6967   g_return_val_if_fail (drop_append_mode != NULL, NULL);
6968
6969   *path_down_mode = FALSE;
6970   *drop_append_mode = 0;
6971
6972   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6973
6974   if (path == NULL)
6975     return NULL;
6976
6977   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
6978     ; /* do nothing */
6979   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
6980            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
6981     *path_down_mode = TRUE;
6982   else
6983     {
6984       GtkTreeIter iter;
6985       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
6986
6987       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
6988
6989       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6990           !gtk_tree_model_iter_next (model, &iter))
6991         *drop_append_mode = 1;
6992       else
6993         {
6994           *drop_append_mode = 0;
6995           gtk_tree_path_next (path);
6996         }
6997     }
6998
6999   return path;
7000 }
7001
7002 static gboolean
7003 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7004                                         GdkEventMotion   *event)
7005 {
7006   GtkWidget *widget = GTK_WIDGET (tree_view);
7007   GdkDragContext *context;
7008   TreeViewDragInfo *di;
7009   GtkTreePath *path = NULL;
7010   gint button;
7011   gint cell_x, cell_y;
7012   GtkTreeModel *model;
7013   gboolean retval = FALSE;
7014
7015   di = get_info (tree_view);
7016
7017   if (di == NULL || !di->source_set)
7018     goto out;
7019
7020   if (tree_view->priv->pressed_button < 0)
7021     goto out;
7022
7023   if (!gtk_drag_check_threshold (widget,
7024                                  tree_view->priv->press_start_x,
7025                                  tree_view->priv->press_start_y,
7026                                  event->x, event->y))
7027     goto out;
7028
7029   model = gtk_tree_view_get_model (tree_view);
7030
7031   if (model == NULL)
7032     goto out;
7033
7034   button = tree_view->priv->pressed_button;
7035   tree_view->priv->pressed_button = -1;
7036
7037   gtk_tree_view_get_path_at_pos (tree_view,
7038                                  tree_view->priv->press_start_x,
7039                                  tree_view->priv->press_start_y,
7040                                  &path,
7041                                  NULL,
7042                                  &cell_x,
7043                                  &cell_y);
7044
7045   if (path == NULL)
7046     goto out;
7047
7048   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7049       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7050                                            path))
7051     goto out;
7052
7053   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7054     goto out;
7055
7056   /* Now we can begin the drag */
7057
7058   retval = TRUE;
7059
7060   context = gtk_drag_begin (widget,
7061                             gtk_drag_source_get_target_list (widget),
7062                             di->source_actions,
7063                             button,
7064                             (GdkEvent*)event);
7065
7066   set_source_row (context, model, path);
7067
7068  out:
7069   if (path)
7070     gtk_tree_path_free (path);
7071
7072   return retval;
7073 }
7074
7075
7076 static void
7077 gtk_tree_view_drag_begin (GtkWidget      *widget,
7078                           GdkDragContext *context)
7079 {
7080   GtkTreeView *tree_view;
7081   GtkTreePath *path = NULL;
7082   gint cell_x, cell_y;
7083   GdkPixmap *row_pix;
7084   TreeViewDragInfo *di;
7085
7086   tree_view = GTK_TREE_VIEW (widget);
7087
7088   /* if the user uses a custom DND source impl, we don't set the icon here */
7089   di = get_info (tree_view);
7090
7091   if (di == NULL || !di->source_set)
7092     return;
7093
7094   gtk_tree_view_get_path_at_pos (tree_view,
7095                                  tree_view->priv->press_start_x,
7096                                  tree_view->priv->press_start_y,
7097                                  &path,
7098                                  NULL,
7099                                  &cell_x,
7100                                  &cell_y);
7101
7102   g_return_if_fail (path != NULL);
7103
7104   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7105                                                 path);
7106
7107   gtk_drag_set_icon_pixmap (context,
7108                             gdk_drawable_get_colormap (row_pix),
7109                             row_pix,
7110                             NULL,
7111                             /* the + 1 is for the black border in the icon */
7112                             tree_view->priv->press_start_x + 1,
7113                             cell_y + 1);
7114
7115   g_object_unref (row_pix);
7116   gtk_tree_path_free (path);
7117 }
7118
7119 static void
7120 gtk_tree_view_drag_end (GtkWidget      *widget,
7121                         GdkDragContext *context)
7122 {
7123   /* do nothing */
7124 }
7125
7126 /* Default signal implementations for the drag signals */
7127 static void
7128 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7129                              GdkDragContext   *context,
7130                              GtkSelectionData *selection_data,
7131                              guint             info,
7132                              guint             time)
7133 {
7134   GtkTreeView *tree_view;
7135   GtkTreeModel *model;
7136   TreeViewDragInfo *di;
7137   GtkTreePath *source_row;
7138
7139   tree_view = GTK_TREE_VIEW (widget);
7140
7141   model = gtk_tree_view_get_model (tree_view);
7142
7143   if (model == NULL)
7144     return;
7145
7146   di = get_info (GTK_TREE_VIEW (widget));
7147
7148   if (di == NULL)
7149     return;
7150
7151   source_row = get_source_row (context);
7152
7153   if (source_row == NULL)
7154     return;
7155
7156   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7157    * any model; for DragSource models there are some other targets
7158    * we also support.
7159    */
7160
7161   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7162       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7163                                           source_row,
7164                                           selection_data))
7165     goto done;
7166
7167   /* If drag_data_get does nothing, try providing row data. */
7168   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7169     {
7170       gtk_tree_set_row_drag_data (selection_data,
7171                                   model,
7172                                   source_row);
7173     }
7174
7175  done:
7176   gtk_tree_path_free (source_row);
7177 }
7178
7179
7180 static void
7181 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7182                                 GdkDragContext *context)
7183 {
7184   TreeViewDragInfo *di;
7185   GtkTreeModel *model;
7186   GtkTreeView *tree_view;
7187   GtkTreePath *source_row;
7188
7189   tree_view = GTK_TREE_VIEW (widget);
7190   model = gtk_tree_view_get_model (tree_view);
7191
7192   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7193     return;
7194
7195   di = get_info (tree_view);
7196
7197   if (di == NULL)
7198     return;
7199
7200   source_row = get_source_row (context);
7201
7202   if (source_row == NULL)
7203     return;
7204
7205   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7206                                          source_row);
7207
7208   gtk_tree_path_free (source_row);
7209
7210   set_source_row (context, NULL, NULL);
7211 }
7212
7213 static void
7214 gtk_tree_view_drag_leave (GtkWidget      *widget,
7215                           GdkDragContext *context,
7216                           guint             time)
7217 {
7218   /* unset any highlight row */
7219   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7220                                    NULL,
7221                                    GTK_TREE_VIEW_DROP_BEFORE);
7222
7223   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7224   remove_open_timeout (GTK_TREE_VIEW (widget));
7225 }
7226
7227
7228 static gboolean
7229 gtk_tree_view_drag_motion (GtkWidget        *widget,
7230                            GdkDragContext   *context,
7231                            /* coordinates relative to the widget */
7232                            gint              x,
7233                            gint              y,
7234                            guint             time)
7235 {
7236   gboolean empty;
7237   GtkTreePath *path = NULL;
7238   GtkTreeViewDropPosition pos;
7239   GtkTreeView *tree_view;
7240   GdkDragAction suggested_action = 0;
7241   GdkAtom target;
7242
7243   tree_view = GTK_TREE_VIEW (widget);
7244
7245   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7246     return FALSE;
7247
7248   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7249
7250   /* we only know this *after* set_desination_row */
7251   empty = tree_view->priv->empty_view_drop;
7252
7253   if (path == NULL && !empty)
7254     {
7255       /* Can't drop here. */
7256       gdk_drag_status (context, 0, time);
7257     }
7258   else
7259     {
7260       if (tree_view->priv->open_dest_timeout == 0 &&
7261           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7262            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7263         {
7264           tree_view->priv->open_dest_timeout =
7265             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7266         }
7267       else
7268         {
7269           add_scroll_timeout (tree_view);
7270         }
7271
7272       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7273         {
7274           /* Request data so we can use the source row when
7275            * determining whether to accept the drop
7276            */
7277           set_status_pending (context, suggested_action);
7278           gtk_drag_get_data (widget, context, target, time);
7279         }
7280       else
7281         {
7282           set_status_pending (context, 0);
7283           gdk_drag_status (context, suggested_action, time);
7284         }
7285     }
7286
7287   if (path)
7288     gtk_tree_path_free (path);
7289
7290   return TRUE;
7291 }
7292
7293
7294 static gboolean
7295 gtk_tree_view_drag_drop (GtkWidget        *widget,
7296                          GdkDragContext   *context,
7297                          /* coordinates relative to the widget */
7298                          gint              x,
7299                          gint              y,
7300                          guint             time)
7301 {
7302   GtkTreeView *tree_view;
7303   GtkTreePath *path;
7304   GdkDragAction suggested_action = 0;
7305   GdkAtom target = GDK_NONE;
7306   TreeViewDragInfo *di;
7307   GtkTreeModel *model;
7308   gboolean path_down_mode;
7309   gboolean drop_append_mode;
7310
7311   tree_view = GTK_TREE_VIEW (widget);
7312
7313   model = gtk_tree_view_get_model (tree_view);
7314
7315   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7316   remove_open_timeout (GTK_TREE_VIEW (widget));
7317
7318   di = get_info (tree_view);
7319
7320   if (di == NULL)
7321     return FALSE;
7322
7323   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7324     return FALSE;
7325
7326   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7327     return FALSE;
7328
7329   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7330
7331   if (target != GDK_NONE && path != NULL)
7332     {
7333       /* in case a motion had requested drag data, change things so we
7334        * treat drag data receives as a drop.
7335        */
7336       set_status_pending (context, 0);
7337       set_dest_row (context, model, path,
7338                     path_down_mode, tree_view->priv->empty_view_drop,
7339                     drop_append_mode);
7340     }
7341
7342   if (path)
7343     gtk_tree_path_free (path);
7344
7345   /* Unset this thing */
7346   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7347                                    NULL,
7348                                    GTK_TREE_VIEW_DROP_BEFORE);
7349
7350   if (target != GDK_NONE)
7351     {
7352       gtk_drag_get_data (widget, context, target, time);
7353       return TRUE;
7354     }
7355   else
7356     return FALSE;
7357 }
7358
7359 static void
7360 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7361                                   GdkDragContext   *context,
7362                                   /* coordinates relative to the widget */
7363                                   gint              x,
7364                                   gint              y,
7365                                   GtkSelectionData *selection_data,
7366                                   guint             info,
7367                                   guint             time)
7368 {
7369   GtkTreePath *path;
7370   TreeViewDragInfo *di;
7371   gboolean accepted = FALSE;
7372   GtkTreeModel *model;
7373   GtkTreeView *tree_view;
7374   GtkTreePath *dest_row;
7375   GdkDragAction suggested_action;
7376   gboolean path_down_mode;
7377   gboolean drop_append_mode;
7378
7379   tree_view = GTK_TREE_VIEW (widget);
7380
7381   model = gtk_tree_view_get_model (tree_view);
7382
7383   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7384     return;
7385
7386   di = get_info (tree_view);
7387
7388   if (di == NULL)
7389     return;
7390
7391   suggested_action = get_status_pending (context);
7392
7393   if (suggested_action)
7394     {
7395       /* We are getting this data due to a request in drag_motion,
7396        * rather than due to a request in drag_drop, so we are just
7397        * supposed to call drag_status, not actually paste in the
7398        * data.
7399        */
7400       path = get_logical_dest_row (tree_view, &path_down_mode,
7401                                    &drop_append_mode);
7402
7403       if (path == NULL)
7404         suggested_action = 0;
7405       else if (path_down_mode)
7406         gtk_tree_path_down (path);
7407
7408       if (suggested_action)
7409         {
7410           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7411                                                      path,
7412                                                      selection_data))
7413             {
7414               if (path_down_mode)
7415                 {
7416                   path_down_mode = FALSE;
7417                   gtk_tree_path_up (path);
7418
7419                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7420                                                              path,
7421                                                              selection_data))
7422                     suggested_action = 0;
7423                 }
7424               else
7425                 suggested_action = 0;
7426             }
7427         }
7428
7429       gdk_drag_status (context, suggested_action, time);
7430
7431       if (path)
7432         gtk_tree_path_free (path);
7433
7434       /* If you can't drop, remove user drop indicator until the next motion */
7435       if (suggested_action == 0)
7436         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7437                                          NULL,
7438                                          GTK_TREE_VIEW_DROP_BEFORE);
7439
7440       return;
7441     }
7442
7443   dest_row = get_dest_row (context, &path_down_mode);
7444
7445   if (dest_row == NULL)
7446     return;
7447
7448   if (selection_data->length >= 0)
7449     {
7450       if (path_down_mode)
7451         {
7452           gtk_tree_path_down (dest_row);
7453           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7454                                                      dest_row, selection_data))
7455             gtk_tree_path_up (dest_row);
7456         }
7457     }
7458
7459   if (selection_data->length >= 0)
7460     {
7461       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7462                                                  dest_row,
7463                                                  selection_data))
7464         accepted = TRUE;
7465     }
7466
7467   gtk_drag_finish (context,
7468                    accepted,
7469                    (context->action == GDK_ACTION_MOVE),
7470                    time);
7471
7472   if (gtk_tree_path_get_depth (dest_row) == 1
7473       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7474     {
7475       /* special special case drag to "0", scroll to first item */
7476       if (!tree_view->priv->scroll_to_path)
7477         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7478     }
7479
7480   gtk_tree_path_free (dest_row);
7481
7482   /* drop dest_row */
7483   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7484 }
7485
7486
7487
7488 /* GtkContainer Methods
7489  */
7490
7491
7492 static void
7493 gtk_tree_view_remove (GtkContainer *container,
7494                       GtkWidget    *widget)
7495 {
7496   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7497   GtkTreeViewChild *child = NULL;
7498   GList *tmp_list;
7499
7500   tmp_list = tree_view->priv->children;
7501   while (tmp_list)
7502     {
7503       child = tmp_list->data;
7504       if (child->widget == widget)
7505         {
7506           gtk_widget_unparent (widget);
7507
7508           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7509           g_list_free_1 (tmp_list);
7510           g_slice_free (GtkTreeViewChild, child);
7511           return;
7512         }
7513
7514       tmp_list = tmp_list->next;
7515     }
7516
7517   tmp_list = tree_view->priv->columns;
7518
7519   while (tmp_list)
7520     {
7521       GtkTreeViewColumn *column;
7522       column = tmp_list->data;
7523       if (column->button == widget)
7524         {
7525           gtk_widget_unparent (widget);
7526           return;
7527         }
7528       tmp_list = tmp_list->next;
7529     }
7530 }
7531
7532 static void
7533 gtk_tree_view_forall (GtkContainer *container,
7534                       gboolean      include_internals,
7535                       GtkCallback   callback,
7536                       gpointer      callback_data)
7537 {
7538   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7539   GtkTreeViewChild *child = NULL;
7540   GtkTreeViewColumn *column;
7541   GList *tmp_list;
7542
7543   tmp_list = tree_view->priv->children;
7544   while (tmp_list)
7545     {
7546       child = tmp_list->data;
7547       tmp_list = tmp_list->next;
7548
7549       (* callback) (child->widget, callback_data);
7550     }
7551   if (include_internals == FALSE)
7552     return;
7553
7554   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7555     {
7556       column = tmp_list->data;
7557
7558       if (column->button)
7559         (* callback) (column->button, callback_data);
7560     }
7561 }
7562
7563 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7564  * cells. If so we draw one big row-spanning focus rectangle.
7565  */
7566 static gboolean
7567 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7568 {
7569   GList *list;
7570
7571   for (list = tree_view->priv->columns; list; list = list->next)
7572     {
7573       if (!((GtkTreeViewColumn *)list->data)->visible)
7574         continue;
7575       if (_gtk_tree_view_column_count_special_cells (list->data))
7576         return TRUE;
7577     }
7578
7579   return FALSE;
7580 }
7581
7582 static void
7583 column_sizing_notify (GObject    *object,
7584                       GParamSpec *pspec,
7585                       gpointer    data)
7586 {
7587   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7588
7589   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7590     /* disable fixed height mode */
7591     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7592 }
7593
7594 /**
7595  * gtk_tree_view_set_fixed_height_mode:
7596  * @tree_view: a #GtkTreeView 
7597  * @enable: %TRUE to enable fixed height mode
7598  * 
7599  * Enables or disables the fixed height mode of @tree_view. 
7600  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7601  * rows have the same height. 
7602  * Only enable this option if all rows are the same height and all
7603  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7604  *
7605  * Since: 2.6 
7606  **/
7607 void
7608 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7609                                      gboolean     enable)
7610 {
7611   GList *l;
7612   
7613   enable = enable != FALSE;
7614
7615   if (enable == tree_view->priv->fixed_height_mode)
7616     return;
7617
7618   if (!enable)
7619     {
7620       tree_view->priv->fixed_height_mode = 0;
7621       tree_view->priv->fixed_height = -1;
7622
7623       /* force a revalidation */
7624       install_presize_handler (tree_view);
7625     }
7626   else 
7627     {
7628       /* make sure all columns are of type FIXED */
7629       for (l = tree_view->priv->columns; l; l = l->next)
7630         {
7631           GtkTreeViewColumn *c = l->data;
7632           
7633           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7634         }
7635       
7636       /* yes, we really have to do this is in a separate loop */
7637       for (l = tree_view->priv->columns; l; l = l->next)
7638         g_signal_connect (l->data, "notify::sizing",
7639                           G_CALLBACK (column_sizing_notify), tree_view);
7640       
7641       tree_view->priv->fixed_height_mode = 1;
7642       tree_view->priv->fixed_height = -1;
7643       
7644       if (tree_view->priv->tree)
7645         initialize_fixed_height_mode (tree_view);
7646     }
7647
7648   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7649 }
7650
7651 /**
7652  * gtk_tree_view_get_fixed_height_mode:
7653  * @tree_view: a #GtkTreeView
7654  * 
7655  * Returns whether fixed height mode is turned on for @tree_view.
7656  * 
7657  * Return value: %TRUE if @tree_view is in fixed height mode
7658  * 
7659  * Since: 2.6
7660  **/
7661 gboolean
7662 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7663 {
7664   return tree_view->priv->fixed_height_mode;
7665 }
7666
7667 /* Returns TRUE if the focus is within the headers, after the focus operation is
7668  * done
7669  */
7670 static gboolean
7671 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7672                             GtkDirectionType  dir,
7673                             gboolean          clamp_column_visible)
7674 {
7675   GtkWidget *focus_child;
7676
7677   GList *last_column, *first_column;
7678   GList *tmp_list;
7679   gboolean rtl;
7680
7681   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7682     return FALSE;
7683
7684   focus_child = GTK_CONTAINER (tree_view)->focus_child;
7685
7686   first_column = tree_view->priv->columns;
7687   while (first_column)
7688     {
7689       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7690           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7691           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7692            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7693         break;
7694       first_column = first_column->next;
7695     }
7696
7697   /* No headers are visible, or are focusable.  We can't focus in or out.
7698    */
7699   if (first_column == NULL)
7700     return FALSE;
7701
7702   last_column = g_list_last (tree_view->priv->columns);
7703   while (last_column)
7704     {
7705       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7706           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7707           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7708            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7709         break;
7710       last_column = last_column->prev;
7711     }
7712
7713
7714   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7715
7716   switch (dir)
7717     {
7718     case GTK_DIR_TAB_BACKWARD:
7719     case GTK_DIR_TAB_FORWARD:
7720     case GTK_DIR_UP:
7721     case GTK_DIR_DOWN:
7722       if (focus_child == NULL)
7723         {
7724           if (tree_view->priv->focus_column != NULL && GTK_WIDGET_CAN_FOCUS (tree_view->priv->focus_column->button))
7725             focus_child = tree_view->priv->focus_column->button;
7726           else
7727             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7728           gtk_widget_grab_focus (focus_child);
7729           break;
7730         }
7731       return FALSE;
7732
7733     case GTK_DIR_LEFT:
7734     case GTK_DIR_RIGHT:
7735       if (focus_child == NULL)
7736         {
7737           if (tree_view->priv->focus_column != NULL)
7738             focus_child = tree_view->priv->focus_column->button;
7739           else if (dir == GTK_DIR_LEFT)
7740             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7741           else
7742             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7743           gtk_widget_grab_focus (focus_child);
7744           break;
7745         }
7746
7747       if (gtk_widget_child_focus (focus_child, dir))
7748         {
7749           /* The focus moves inside the button. */
7750           /* This is probably a great example of bad UI */
7751           break;
7752         }
7753
7754       /* We need to move the focus among the row of buttons. */
7755       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7756         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7757           break;
7758
7759       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7760           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7761         {
7762           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7763           break;
7764         }
7765
7766       while (tmp_list)
7767         {
7768           GtkTreeViewColumn *column;
7769
7770           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7771             tmp_list = tmp_list->next;
7772           else
7773             tmp_list = tmp_list->prev;
7774
7775           if (tmp_list == NULL)
7776             {
7777               g_warning ("Internal button not found");
7778               break;
7779             }
7780           column = tmp_list->data;
7781           if (column->button &&
7782               column->visible &&
7783               GTK_WIDGET_CAN_FOCUS (column->button))
7784             {
7785               focus_child = column->button;
7786               gtk_widget_grab_focus (column->button);
7787               break;
7788             }
7789         }
7790       break;
7791     default:
7792       g_assert_not_reached ();
7793       break;
7794     }
7795
7796   /* if focus child is non-null, we assume it's been set to the current focus child
7797    */
7798   if (focus_child)
7799     {
7800       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7801         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7802           {
7803             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7804             break;
7805           }
7806
7807       if (clamp_column_visible)
7808         {
7809           gtk_tree_view_clamp_column_visible (tree_view,
7810                                               tree_view->priv->focus_column,
7811                                               FALSE);
7812         }
7813     }
7814
7815   return (focus_child != NULL);
7816 }
7817
7818 /* This function returns in 'path' the first focusable path, if the given path
7819  * is already focusable, it's the returned one.
7820  */
7821 static gboolean
7822 search_first_focusable_path (GtkTreeView  *tree_view,
7823                              GtkTreePath **path,
7824                              gboolean      search_forward,
7825                              GtkRBTree   **new_tree,
7826                              GtkRBNode   **new_node)
7827 {
7828   GtkRBTree *tree = NULL;
7829   GtkRBNode *node = NULL;
7830
7831   if (!path || !*path)
7832     return FALSE;
7833
7834   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7835
7836   if (!tree || !node)
7837     return FALSE;
7838
7839   while (node && row_is_separator (tree_view, NULL, *path))
7840     {
7841       if (search_forward)
7842         _gtk_rbtree_next_full (tree, node, &tree, &node);
7843       else
7844         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7845
7846       if (*path)
7847         gtk_tree_path_free (*path);
7848
7849       if (node)
7850         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7851       else
7852         *path = NULL;
7853     }
7854
7855   if (new_tree)
7856     *new_tree = tree;
7857
7858   if (new_node)
7859     *new_node = node;
7860
7861   return (*path != NULL);
7862 }
7863
7864 static gint
7865 gtk_tree_view_focus (GtkWidget        *widget,
7866                      GtkDirectionType  direction)
7867 {
7868   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7869   GtkContainer *container = GTK_CONTAINER (widget);
7870   GtkWidget *focus_child;
7871
7872   if (!GTK_WIDGET_IS_SENSITIVE (container) || !GTK_WIDGET_CAN_FOCUS (widget))
7873     return FALSE;
7874
7875   focus_child = container->focus_child;
7876
7877   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
7878   /* Case 1.  Headers currently have focus. */
7879   if (focus_child)
7880     {
7881       switch (direction)
7882         {
7883         case GTK_DIR_LEFT:
7884         case GTK_DIR_RIGHT:
7885           gtk_tree_view_header_focus (tree_view, direction, TRUE);
7886           return TRUE;
7887         case GTK_DIR_TAB_BACKWARD:
7888         case GTK_DIR_UP:
7889           return FALSE;
7890         case GTK_DIR_TAB_FORWARD:
7891         case GTK_DIR_DOWN:
7892           gtk_widget_grab_focus (widget);
7893           return TRUE;
7894         default:
7895           g_assert_not_reached ();
7896           return FALSE;
7897         }
7898     }
7899
7900   /* Case 2. We don't have focus at all. */
7901   if (!GTK_WIDGET_HAS_FOCUS (container))
7902     {
7903       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
7904         gtk_widget_grab_focus (widget);
7905       return TRUE;
7906     }
7907
7908   /* Case 3. We have focus already. */
7909   if (direction == GTK_DIR_TAB_BACKWARD)
7910     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
7911   else if (direction == GTK_DIR_TAB_FORWARD)
7912     return FALSE;
7913
7914   /* Other directions caught by the keybindings */
7915   gtk_widget_grab_focus (widget);
7916   return TRUE;
7917 }
7918
7919 static void
7920 gtk_tree_view_grab_focus (GtkWidget *widget)
7921 {
7922   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
7923
7924   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
7925 }
7926
7927 static void
7928 gtk_tree_view_style_set (GtkWidget *widget,
7929                          GtkStyle *previous_style)
7930 {
7931   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7932   GList *list;
7933   GtkTreeViewColumn *column;
7934
7935   if (GTK_WIDGET_REALIZED (widget))
7936     {
7937       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
7938       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
7939       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
7940
7941       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
7942       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
7943     }
7944
7945   gtk_widget_style_get (widget,
7946                         "expander-size", &tree_view->priv->expander_size,
7947                         NULL);
7948   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
7949
7950   for (list = tree_view->priv->columns; list; list = list->next)
7951     {
7952       column = list->data;
7953       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
7954     }
7955
7956   tree_view->priv->fixed_height = -1;
7957   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
7958
7959   gtk_widget_queue_resize (widget);
7960 }
7961
7962
7963 static void
7964 gtk_tree_view_set_focus_child (GtkContainer *container,
7965                                GtkWidget    *child)
7966 {
7967   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7968   GList *list;
7969
7970   for (list = tree_view->priv->columns; list; list = list->next)
7971     {
7972       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
7973         {
7974           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
7975           break;
7976         }
7977     }
7978
7979   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
7980 }
7981
7982 static void
7983 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
7984                                GtkAdjustment *hadj,
7985                                GtkAdjustment *vadj)
7986 {
7987   gboolean need_adjust = FALSE;
7988
7989   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7990
7991   if (hadj)
7992     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
7993   else
7994     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7995   if (vadj)
7996     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
7997   else
7998     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7999
8000   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
8001     {
8002       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
8003                                             gtk_tree_view_adjustment_changed,
8004                                             tree_view);
8005       g_object_unref (tree_view->priv->hadjustment);
8006     }
8007
8008   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
8009     {
8010       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8011                                             gtk_tree_view_adjustment_changed,
8012                                             tree_view);
8013       g_object_unref (tree_view->priv->vadjustment);
8014     }
8015
8016   if (tree_view->priv->hadjustment != hadj)
8017     {
8018       tree_view->priv->hadjustment = hadj;
8019       g_object_ref_sink (tree_view->priv->hadjustment);
8020
8021       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8022                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8023                         tree_view);
8024       need_adjust = TRUE;
8025     }
8026
8027   if (tree_view->priv->vadjustment != vadj)
8028     {
8029       tree_view->priv->vadjustment = vadj;
8030       g_object_ref_sink (tree_view->priv->vadjustment);
8031
8032       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8033                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8034                         tree_view);
8035       need_adjust = TRUE;
8036     }
8037
8038   if (need_adjust)
8039     gtk_tree_view_adjustment_changed (NULL, tree_view);
8040 }
8041
8042
8043 static gboolean
8044 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8045                                 GtkMovementStep    step,
8046                                 gint               count)
8047 {
8048   GdkModifierType state;
8049
8050   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8051   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8052                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8053                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8054                         step == GTK_MOVEMENT_PAGES ||
8055                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8056
8057   if (tree_view->priv->tree == NULL)
8058     return FALSE;
8059   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
8060     return FALSE;
8061
8062   gtk_tree_view_stop_editing (tree_view, FALSE);
8063   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8064   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8065
8066   if (gtk_get_current_event_state (&state))
8067     {
8068       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8069         tree_view->priv->ctrl_pressed = TRUE;
8070       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8071         tree_view->priv->shift_pressed = TRUE;
8072     }
8073   /* else we assume not pressed */
8074
8075   switch (step)
8076     {
8077       /* currently we make no distinction.  When we go bi-di, we need to */
8078     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8079     case GTK_MOVEMENT_VISUAL_POSITIONS:
8080       gtk_tree_view_move_cursor_left_right (tree_view, count);
8081       break;
8082     case GTK_MOVEMENT_DISPLAY_LINES:
8083       gtk_tree_view_move_cursor_up_down (tree_view, count);
8084       break;
8085     case GTK_MOVEMENT_PAGES:
8086       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8087       break;
8088     case GTK_MOVEMENT_BUFFER_ENDS:
8089       gtk_tree_view_move_cursor_start_end (tree_view, count);
8090       break;
8091     default:
8092       g_assert_not_reached ();
8093     }
8094
8095   tree_view->priv->ctrl_pressed = FALSE;
8096   tree_view->priv->shift_pressed = FALSE;
8097
8098   return TRUE;
8099 }
8100
8101 static void
8102 gtk_tree_view_put (GtkTreeView *tree_view,
8103                    GtkWidget   *child_widget,
8104                    /* in bin_window coordinates */
8105                    gint         x,
8106                    gint         y,
8107                    gint         width,
8108                    gint         height)
8109 {
8110   GtkTreeViewChild *child;
8111   
8112   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8113   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8114
8115   child = g_slice_new (GtkTreeViewChild);
8116
8117   child->widget = child_widget;
8118   child->x = x;
8119   child->y = y;
8120   child->width = width;
8121   child->height = height;
8122
8123   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8124
8125   if (GTK_WIDGET_REALIZED (tree_view))
8126     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8127   
8128   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8129 }
8130
8131 void
8132 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8133                                   GtkWidget   *widget,
8134                                   /* in tree coordinates */
8135                                   gint         x,
8136                                   gint         y,
8137                                   gint         width,
8138                                   gint         height)
8139 {
8140   GtkTreeViewChild *child = NULL;
8141   GList *list;
8142   GdkRectangle allocation;
8143
8144   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8145   g_return_if_fail (GTK_IS_WIDGET (widget));
8146
8147   for (list = tree_view->priv->children; list; list = list->next)
8148     {
8149       if (((GtkTreeViewChild *)list->data)->widget == widget)
8150         {
8151           child = list->data;
8152           break;
8153         }
8154     }
8155   if (child == NULL)
8156     return;
8157
8158   allocation.x = child->x = x;
8159   allocation.y = child->y = y;
8160   allocation.width = child->width = width;
8161   allocation.height = child->height = height;
8162
8163   if (GTK_WIDGET_REALIZED (widget))
8164     gtk_widget_size_allocate (widget, &allocation);
8165 }
8166
8167
8168 /* TreeModel Callbacks
8169  */
8170
8171 static void
8172 gtk_tree_view_row_changed (GtkTreeModel *model,
8173                            GtkTreePath  *path,
8174                            GtkTreeIter  *iter,
8175                            gpointer      data)
8176 {
8177   GtkTreeView *tree_view = (GtkTreeView *)data;
8178   GtkRBTree *tree;
8179   GtkRBNode *node;
8180   gboolean free_path = FALSE;
8181   GList *list;
8182   GtkTreePath *cursor_path;
8183
8184   g_return_if_fail (path != NULL || iter != NULL);
8185
8186   if (tree_view->priv->cursor != NULL)
8187     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8188   else
8189     cursor_path = NULL;
8190
8191   if (tree_view->priv->edited_column &&
8192       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8193     gtk_tree_view_stop_editing (tree_view, TRUE);
8194
8195   if (cursor_path != NULL)
8196     gtk_tree_path_free (cursor_path);
8197
8198   if (path == NULL)
8199     {
8200       path = gtk_tree_model_get_path (model, iter);
8201       free_path = TRUE;
8202     }
8203   else if (iter == NULL)
8204     gtk_tree_model_get_iter (model, iter, path);
8205
8206   if (_gtk_tree_view_find_node (tree_view,
8207                                 path,
8208                                 &tree,
8209                                 &node))
8210     /* We aren't actually showing the node */
8211     goto done;
8212
8213   if (tree == NULL)
8214     goto done;
8215
8216   if (tree_view->priv->fixed_height_mode
8217       && tree_view->priv->fixed_height >= 0)
8218     {
8219       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8220       if (GTK_WIDGET_REALIZED (tree_view))
8221         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8222     }
8223   else
8224     {
8225       _gtk_rbtree_node_mark_invalid (tree, node);
8226       for (list = tree_view->priv->columns; list; list = list->next)
8227         {
8228           GtkTreeViewColumn *column;
8229
8230           column = list->data;
8231           if (! column->visible)
8232             continue;
8233
8234           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8235             {
8236               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8237             }
8238         }
8239     }
8240
8241  done:
8242   if (GTK_WIDGET_REALIZED (tree_view) && !tree_view->priv->fixed_height_mode)
8243     install_presize_handler (tree_view);
8244   if (free_path)
8245     gtk_tree_path_free (path);
8246 }
8247
8248 static void
8249 gtk_tree_view_row_inserted (GtkTreeModel *model,
8250                             GtkTreePath  *path,
8251                             GtkTreeIter  *iter,
8252                             gpointer      data)
8253 {
8254   GtkTreeView *tree_view = (GtkTreeView *) data;
8255   gint *indices;
8256   GtkRBTree *tmptree, *tree;
8257   GtkRBNode *tmpnode = NULL;
8258   gint depth;
8259   gint i = 0;
8260   gint height;
8261   gboolean free_path = FALSE;
8262   gboolean node_visible = TRUE;
8263
8264   g_return_if_fail (path != NULL || iter != NULL);
8265
8266   if (tree_view->priv->fixed_height_mode
8267       && tree_view->priv->fixed_height >= 0)
8268     height = tree_view->priv->fixed_height;
8269   else
8270     height = 0;
8271
8272   if (path == NULL)
8273     {
8274       path = gtk_tree_model_get_path (model, iter);
8275       free_path = TRUE;
8276     }
8277   else if (iter == NULL)
8278     gtk_tree_model_get_iter (model, iter, path);
8279
8280   if (tree_view->priv->tree == NULL)
8281     tree_view->priv->tree = _gtk_rbtree_new ();
8282
8283   tmptree = tree = tree_view->priv->tree;
8284
8285   /* Update all row-references */
8286   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8287   depth = gtk_tree_path_get_depth (path);
8288   indices = gtk_tree_path_get_indices (path);
8289
8290   /* First, find the parent tree */
8291   while (i < depth - 1)
8292     {
8293       if (tmptree == NULL)
8294         {
8295           /* We aren't showing the node */
8296           node_visible = FALSE;
8297           goto done;
8298         }
8299
8300       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8301       if (tmpnode == NULL)
8302         {
8303           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8304                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8305                      "before the parent was inserted.");
8306           goto done;
8307         }
8308       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8309         {
8310           /* FIXME enforce correct behavior on model, probably */
8311           /* In theory, the model should have emitted has_child_toggled here.  We
8312            * try to catch it anyway, just to be safe, in case the model hasn't.
8313            */
8314           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8315                                                            tree,
8316                                                            tmpnode);
8317           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8318           gtk_tree_path_free (tmppath);
8319           goto done;
8320         }
8321
8322       tmptree = tmpnode->children;
8323       tree = tmptree;
8324       i++;
8325     }
8326
8327   if (tree == NULL)
8328     {
8329       node_visible = FALSE;
8330       goto done;
8331     }
8332
8333   /* ref the node */
8334   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8335   if (indices[depth - 1] == 0)
8336     {
8337       tmpnode = _gtk_rbtree_find_count (tree, 1);
8338       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8339     }
8340   else
8341     {
8342       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8343       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8344     }
8345
8346  done:
8347   if (height > 0)
8348     {
8349       if (tree)
8350         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8351
8352       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8353         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8354       else
8355         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8356     }
8357   else
8358     install_presize_handler (tree_view);
8359   if (free_path)
8360     gtk_tree_path_free (path);
8361 }
8362
8363 static void
8364 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8365                                      GtkTreePath  *path,
8366                                      GtkTreeIter  *iter,
8367                                      gpointer      data)
8368 {
8369   GtkTreeView *tree_view = (GtkTreeView *)data;
8370   GtkTreeIter real_iter;
8371   gboolean has_child;
8372   GtkRBTree *tree;
8373   GtkRBNode *node;
8374   gboolean free_path = FALSE;
8375
8376   g_return_if_fail (path != NULL || iter != NULL);
8377
8378   if (iter)
8379     real_iter = *iter;
8380
8381   if (path == NULL)
8382     {
8383       path = gtk_tree_model_get_path (model, iter);
8384       free_path = TRUE;
8385     }
8386   else if (iter == NULL)
8387     gtk_tree_model_get_iter (model, &real_iter, path);
8388
8389   if (_gtk_tree_view_find_node (tree_view,
8390                                 path,
8391                                 &tree,
8392                                 &node))
8393     /* We aren't actually showing the node */
8394     goto done;
8395
8396   if (tree == NULL)
8397     goto done;
8398
8399   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8400   /* Sanity check.
8401    */
8402   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8403     goto done;
8404
8405   if (has_child)
8406     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8407   else
8408     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8409
8410   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8411     {
8412       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8413       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8414         {
8415           GList *list;
8416
8417           for (list = tree_view->priv->columns; list; list = list->next)
8418             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8419               {
8420                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8421                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8422                 break;
8423               }
8424         }
8425       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8426     }
8427   else
8428     {
8429       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8430     }
8431
8432  done:
8433   if (free_path)
8434     gtk_tree_path_free (path);
8435 }
8436
8437 static void
8438 count_children_helper (GtkRBTree *tree,
8439                        GtkRBNode *node,
8440                        gpointer   data)
8441 {
8442   if (node->children)
8443     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8444   (*((gint *)data))++;
8445 }
8446
8447 static void
8448 check_selection_helper (GtkRBTree *tree,
8449                         GtkRBNode *node,
8450                         gpointer   data)
8451 {
8452   gint *value = (gint *)data;
8453
8454   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8455
8456   if (node->children && !*value)
8457     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8458 }
8459
8460 static void
8461 gtk_tree_view_row_deleted (GtkTreeModel *model,
8462                            GtkTreePath  *path,
8463                            gpointer      data)
8464 {
8465   GtkTreeView *tree_view = (GtkTreeView *)data;
8466   GtkRBTree *tree;
8467   GtkRBNode *node;
8468   GList *list;
8469   gint selection_changed = FALSE;
8470
8471   g_return_if_fail (path != NULL);
8472
8473   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8474
8475   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8476     return;
8477
8478   if (tree == NULL)
8479     return;
8480
8481   /* check if the selection has been changed */
8482   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8483                         check_selection_helper, &selection_changed);
8484
8485   for (list = tree_view->priv->columns; list; list = list->next)
8486     if (((GtkTreeViewColumn *)list->data)->visible &&
8487         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8488       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8489
8490   /* Ensure we don't have a dangling pointer to a dead node */
8491   ensure_unprelighted (tree_view);
8492
8493   /* Cancel editting if we've started */
8494   gtk_tree_view_stop_editing (tree_view, TRUE);
8495
8496   /* If we have a node expanded/collapsed timeout, remove it */
8497   remove_expand_collapse_timeout (tree_view);
8498
8499   if (tree_view->priv->destroy_count_func)
8500     {
8501       gint child_count = 0;
8502       if (node->children)
8503         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8504       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8505     }
8506
8507   if (tree->root->count == 1)
8508     {
8509       if (tree_view->priv->tree == tree)
8510         tree_view->priv->tree = NULL;
8511
8512       _gtk_rbtree_remove (tree);
8513     }
8514   else
8515     {
8516       _gtk_rbtree_remove_node (tree, node);
8517     }
8518
8519   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8520     {
8521       gtk_tree_row_reference_free (tree_view->priv->top_row);
8522       tree_view->priv->top_row = NULL;
8523     }
8524
8525   install_scroll_sync_handler (tree_view);
8526
8527   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8528
8529   if (selection_changed)
8530     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8531 }
8532
8533 static void
8534 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8535                               GtkTreePath  *parent,
8536                               GtkTreeIter  *iter,
8537                               gint         *new_order,
8538                               gpointer      data)
8539 {
8540   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8541   GtkRBTree *tree;
8542   GtkRBNode *node;
8543   gint len;
8544
8545   len = gtk_tree_model_iter_n_children (model, iter);
8546
8547   if (len < 2)
8548     return;
8549
8550   gtk_tree_row_reference_reordered (G_OBJECT (data),
8551                                     parent,
8552                                     iter,
8553                                     new_order);
8554
8555   if (_gtk_tree_view_find_node (tree_view,
8556                                 parent,
8557                                 &tree,
8558                                 &node))
8559     return;
8560
8561   /* We need to special case the parent path */
8562   if (tree == NULL)
8563     tree = tree_view->priv->tree;
8564   else
8565     tree = node->children;
8566
8567   if (tree == NULL)
8568     return;
8569
8570   if (tree_view->priv->edited_column)
8571     gtk_tree_view_stop_editing (tree_view, TRUE);
8572
8573   /* we need to be unprelighted */
8574   ensure_unprelighted (tree_view);
8575
8576   /* clear the timeout */
8577   cancel_arrow_animation (tree_view);
8578   
8579   _gtk_rbtree_reorder (tree, new_order, len);
8580
8581   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8582
8583   gtk_tree_view_dy_to_top_row (tree_view);
8584 }
8585
8586
8587 /* Internal tree functions
8588  */
8589
8590
8591 static void
8592 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8593                                      GtkRBTree         *tree,
8594                                      GtkTreeViewColumn *column,
8595                                      gint              *x1,
8596                                      gint              *x2)
8597 {
8598   GtkTreeViewColumn *tmp_column = NULL;
8599   gint total_width;
8600   GList *list;
8601   gboolean rtl;
8602
8603   if (x1)
8604     *x1 = 0;
8605
8606   if (x2)
8607     *x2 = 0;
8608
8609   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8610
8611   total_width = 0;
8612   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8613        list;
8614        list = (rtl ? list->prev : list->next))
8615     {
8616       tmp_column = list->data;
8617
8618       if (tmp_column == column)
8619         break;
8620
8621       if (tmp_column->visible)
8622         total_width += tmp_column->width;
8623     }
8624
8625   if (tmp_column != column)
8626     {
8627       g_warning (G_STRLOC": passed-in column isn't in the tree");
8628       return;
8629     }
8630
8631   if (x1)
8632     *x1 = total_width;
8633
8634   if (x2)
8635     {
8636       if (column->visible)
8637         *x2 = total_width + column->width;
8638       else
8639         *x2 = total_width; /* width of 0 */
8640     }
8641 }
8642 static void
8643 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8644                                 GtkRBTree   *tree,
8645                                 gint        *x1,
8646                                 gint        *x2)
8647 {
8648   gint x_offset = 0;
8649   GList *list;
8650   GtkTreeViewColumn *tmp_column = NULL;
8651   gint total_width;
8652   gboolean indent_expanders;
8653   gboolean rtl;
8654
8655   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8656
8657   total_width = 0;
8658   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8659        list;
8660        list = (rtl ? list->prev : list->next))
8661     {
8662       tmp_column = list->data;
8663
8664       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8665         {
8666           if (rtl)
8667             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8668           else
8669             x_offset = total_width;
8670           break;
8671         }
8672
8673       if (tmp_column->visible)
8674         total_width += tmp_column->width;
8675     }
8676
8677   gtk_widget_style_get (GTK_WIDGET (tree_view),
8678                         "indent-expanders", &indent_expanders,
8679                         NULL);
8680
8681   if (indent_expanders)
8682     {
8683       if (rtl)
8684         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8685       else
8686         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8687     }
8688
8689   *x1 = x_offset;
8690   
8691   if (tmp_column && tmp_column->visible)
8692     /* +1 because x2 isn't included in the range. */
8693     *x2 = *x1 + tree_view->priv->expander_size + 1;
8694   else
8695     *x2 = *x1;
8696 }
8697
8698 static void
8699 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8700                           GtkRBTree   *tree,
8701                           GtkTreeIter *iter,
8702                           gint         depth,
8703                           gboolean     recurse)
8704 {
8705   GtkRBNode *temp = NULL;
8706   GtkTreePath *path = NULL;
8707   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8708
8709   do
8710     {
8711       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8712       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8713
8714       if (tree_view->priv->fixed_height > 0)
8715         {
8716           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8717             {
8718               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8719               _gtk_rbtree_node_mark_valid (tree, temp);
8720             }
8721         }
8722
8723       if (is_list)
8724         continue;
8725
8726       if (recurse)
8727         {
8728           GtkTreeIter child;
8729
8730           if (!path)
8731             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8732           else
8733             gtk_tree_path_next (path);
8734
8735           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8736             {
8737               gboolean expand;
8738
8739               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8740
8741               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8742                   && !expand)
8743                 {
8744                   temp->children = _gtk_rbtree_new ();
8745                   temp->children->parent_tree = tree;
8746                   temp->children->parent_node = temp;
8747                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8748                 }
8749             }
8750         }
8751
8752       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8753         {
8754           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8755             temp->flags ^= GTK_RBNODE_IS_PARENT;
8756         }
8757     }
8758   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8759
8760   if (path)
8761     gtk_tree_path_free (path);
8762 }
8763
8764 /* If height is non-NULL, then we set it to be the new height.  if it's all
8765  * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
8766  */
8767 static gboolean
8768 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
8769                                    GtkTreeIter *iter,
8770                                    gint         depth,
8771                                    gint        *height,
8772                                    GtkRBNode   *node)
8773 {
8774   GtkTreeViewColumn *column;
8775   GList *list;
8776   gboolean retval = FALSE;
8777   gint tmpheight;
8778   gint horizontal_separator;
8779
8780   gtk_widget_style_get (GTK_WIDGET (tree_view),
8781                         "horizontal-separator", &horizontal_separator,
8782                         NULL);
8783
8784   if (height)
8785     *height = -1;
8786
8787   for (list = tree_view->priv->columns; list; list = list->next)
8788     {
8789       gint width;
8790       column = list->data;
8791       if (column->dirty == TRUE)
8792         continue;
8793       if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
8794         continue;
8795       if (!column->visible)
8796         continue;
8797
8798       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
8799                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
8800                                                node->children?TRUE:FALSE);
8801
8802       if (height)
8803         {
8804           gtk_tree_view_column_cell_get_size (column,
8805                                               NULL, NULL, NULL,
8806                                               &width, &tmpheight);
8807           *height = MAX (*height, tmpheight);
8808         }
8809       else
8810         {
8811           gtk_tree_view_column_cell_get_size (column,
8812                                               NULL, NULL, NULL,
8813                                               &width, NULL);
8814         }
8815
8816       if (gtk_tree_view_is_expander_column (tree_view, column))
8817         {
8818           int tmp = 0;
8819
8820           tmp = horizontal_separator + width + (depth - 1) * tree_view->priv->level_indentation;
8821           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
8822             tmp += depth * tree_view->priv->expander_size;
8823
8824           if (tmp > column->requested_width)
8825             {
8826               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8827               retval = TRUE;
8828             }
8829         }
8830       else
8831         {
8832           if (horizontal_separator + width > column->requested_width)
8833             {
8834               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8835               retval = TRUE;
8836             }
8837         }
8838     }
8839
8840   return retval;
8841 }
8842
8843 static void
8844 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
8845                               GtkRBTree   *tree,
8846                               GtkTreeIter *iter,
8847                               gint         depth)
8848 {
8849   GtkRBNode *temp = tree->root;
8850   GtkTreeViewColumn *column;
8851   GList *list;
8852   GtkTreeIter child;
8853   gboolean is_all_dirty;
8854
8855   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
8856
8857   while (temp->left != tree->nil)
8858     temp = temp->left;
8859
8860   do
8861     {
8862       TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
8863       is_all_dirty = TRUE;
8864       for (list = tree_view->priv->columns; list; list = list->next)
8865         {
8866           column = list->data;
8867           if (column->dirty == FALSE)
8868             {
8869               is_all_dirty = FALSE;
8870               break;
8871             }
8872         }
8873
8874       if (is_all_dirty)
8875         return;
8876
8877       gtk_tree_view_discover_dirty_iter (tree_view,
8878                                          iter,
8879                                          depth,
8880                                          NULL,
8881                                          temp);
8882       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
8883           temp->children != NULL)
8884         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
8885       temp = _gtk_rbtree_next (tree, temp);
8886     }
8887   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8888 }
8889
8890
8891 /* Make sure the node is visible vertically */
8892 static void
8893 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8894                                   GtkRBTree   *tree,
8895                                   GtkRBNode   *node)
8896 {
8897   gint node_dy, height;
8898   GtkTreePath *path = NULL;
8899
8900   if (!GTK_WIDGET_REALIZED (tree_view))
8901     return;
8902
8903   /* just return if the node is visible, avoiding a costly expose */
8904   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8905   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8906   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8907       && node_dy >= tree_view->priv->vadjustment->value
8908       && node_dy + height <= (tree_view->priv->vadjustment->value
8909                               + tree_view->priv->vadjustment->page_size))
8910     return;
8911
8912   path = _gtk_tree_view_find_path (tree_view, tree, node);
8913   if (path)
8914     {
8915       /* We process updates because we want to clear old selected items when we scroll.
8916        * if this is removed, we get a "selection streak" at the bottom. */
8917       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8918       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8919       gtk_tree_path_free (path);
8920     }
8921 }
8922
8923 static void
8924 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8925                                     GtkTreeViewColumn *column,
8926                                     gboolean           focus_to_cell)
8927 {
8928   gint x, width;
8929
8930   if (column == NULL)
8931     return;
8932
8933   x = column->button->allocation.x;
8934   width = column->button->allocation.width;
8935
8936   if (width > tree_view->priv->hadjustment->page_size)
8937     {
8938       /* The column is larger than the horizontal page size.  If the
8939        * column has cells which can be focussed individually, then we make
8940        * sure the cell which gets focus is fully visible (if even the
8941        * focus cell is bigger than the page size, we make sure the
8942        * left-hand side of the cell is visible).
8943        *
8944        * If the column does not have those so-called special cells, we
8945        * make sure the left-hand side of the column is visible.
8946        */
8947
8948       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8949         {
8950           GtkTreePath *cursor_path;
8951           GdkRectangle background_area, cell_area, focus_area;
8952
8953           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8954
8955           gtk_tree_view_get_cell_area (tree_view,
8956                                        cursor_path, column, &cell_area);
8957           gtk_tree_view_get_background_area (tree_view,
8958                                              cursor_path, column,
8959                                              &background_area);
8960
8961           gtk_tree_path_free (cursor_path);
8962
8963           _gtk_tree_view_column_get_focus_area (column,
8964                                                 &background_area,
8965                                                 &cell_area,
8966                                                 &focus_area);
8967
8968           x = focus_area.x;
8969           width = focus_area.width;
8970
8971           if (width < tree_view->priv->hadjustment->page_size)
8972             {
8973               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8974                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8975                                           x + width - tree_view->priv->hadjustment->page_size);
8976               else if (tree_view->priv->hadjustment->value > x)
8977                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8978             }
8979         }
8980
8981       gtk_adjustment_set_value (tree_view->priv->hadjustment,
8982                                 CLAMP (x,
8983                                        tree_view->priv->hadjustment->lower,
8984                                        tree_view->priv->hadjustment->upper
8985                                        - tree_view->priv->hadjustment->page_size));
8986     }
8987   else
8988     {
8989       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8990           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8991                                     x + width - tree_view->priv->hadjustment->page_size);
8992       else if (tree_view->priv->hadjustment->value > x)
8993         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8994   }
8995 }
8996
8997 /* This function could be more efficient.  I'll optimize it if profiling seems
8998  * to imply that it is important */
8999 GtkTreePath *
9000 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9001                           GtkRBTree   *tree,
9002                           GtkRBNode   *node)
9003 {
9004   GtkTreePath *path;
9005   GtkRBTree *tmp_tree;
9006   GtkRBNode *tmp_node, *last;
9007   gint count;
9008
9009   path = gtk_tree_path_new ();
9010
9011   g_return_val_if_fail (node != NULL, path);
9012   g_return_val_if_fail (node != tree->nil, path);
9013
9014   count = 1 + node->left->count;
9015
9016   last = node;
9017   tmp_node = node->parent;
9018   tmp_tree = tree;
9019   while (tmp_tree)
9020     {
9021       while (tmp_node != tmp_tree->nil)
9022         {
9023           if (tmp_node->right == last)
9024             count += 1 + tmp_node->left->count;
9025           last = tmp_node;
9026           tmp_node = tmp_node->parent;
9027         }
9028       gtk_tree_path_prepend_index (path, count - 1);
9029       last = tmp_tree->parent_node;
9030       tmp_tree = tmp_tree->parent_tree;
9031       if (last)
9032         {
9033           count = 1 + last->left->count;
9034           tmp_node = last->parent;
9035         }
9036     }
9037   return path;
9038 }
9039
9040 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9041  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9042  * both set to NULL.
9043  */
9044 gboolean
9045 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9046                           GtkTreePath  *path,
9047                           GtkRBTree   **tree,
9048                           GtkRBNode   **node)
9049 {
9050   GtkRBNode *tmpnode = NULL;
9051   GtkRBTree *tmptree = tree_view->priv->tree;
9052   gint *indices = gtk_tree_path_get_indices (path);
9053   gint depth = gtk_tree_path_get_depth (path);
9054   gint i = 0;
9055
9056   *node = NULL;
9057   *tree = NULL;
9058
9059   if (depth == 0 || tmptree == NULL)
9060     return FALSE;
9061   do
9062     {
9063       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9064       ++i;
9065       if (tmpnode == NULL)
9066         {
9067           *tree = NULL;
9068           *node = NULL;
9069           return FALSE;
9070         }
9071       if (i >= depth)
9072         {
9073           *tree = tmptree;
9074           *node = tmpnode;
9075           return FALSE;
9076         }
9077       *tree = tmptree;
9078       *node = tmpnode;
9079       tmptree = tmpnode->children;
9080       if (tmptree == NULL)
9081         return TRUE;
9082     }
9083   while (1);
9084 }
9085
9086 static gboolean
9087 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9088                                   GtkTreeViewColumn *column)
9089 {
9090   GList *list;
9091
9092   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9093     return FALSE;
9094
9095   if (tree_view->priv->expander_column != NULL)
9096     {
9097       if (tree_view->priv->expander_column == column)
9098         return TRUE;
9099       return FALSE;
9100     }
9101   else
9102     {
9103       for (list = tree_view->priv->columns;
9104            list;
9105            list = list->next)
9106         if (((GtkTreeViewColumn *)list->data)->visible)
9107           break;
9108       if (list && list->data == column)
9109         return TRUE;
9110     }
9111   return FALSE;
9112 }
9113
9114 static void
9115 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9116                                 guint           keyval,
9117                                 guint           modmask,
9118                                 gboolean        add_shifted_binding,
9119                                 GtkMovementStep step,
9120                                 gint            count)
9121 {
9122   
9123   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9124                                 "move-cursor", 2,
9125                                 G_TYPE_ENUM, step,
9126                                 G_TYPE_INT, count);
9127
9128   if (add_shifted_binding)
9129     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9130                                   "move-cursor", 2,
9131                                   G_TYPE_ENUM, step,
9132                                   G_TYPE_INT, count);
9133
9134   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9135    return;
9136
9137   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9138                                 "move-cursor", 2,
9139                                 G_TYPE_ENUM, step,
9140                                 G_TYPE_INT, count);
9141
9142   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9143                                 "move-cursor", 2,
9144                                 G_TYPE_ENUM, step,
9145                                 G_TYPE_INT, count);
9146 }
9147
9148 static gint
9149 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9150                                  GtkTreeIter  *iter,
9151                                  GtkRBTree    *tree,
9152                                  GtkRBNode    *node)
9153 {
9154   gint retval = FALSE;
9155   do
9156     {
9157       g_return_val_if_fail (node != NULL, FALSE);
9158
9159       if (node->children)
9160         {
9161           GtkTreeIter child;
9162           GtkRBTree *new_tree;
9163           GtkRBNode *new_node;
9164
9165           new_tree = node->children;
9166           new_node = new_tree->root;
9167
9168           while (new_node && new_node->left != new_tree->nil)
9169             new_node = new_node->left;
9170
9171           if (!gtk_tree_model_iter_children (model, &child, iter))
9172             return FALSE;
9173
9174           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9175         }
9176
9177       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9178         retval = TRUE;
9179       gtk_tree_model_unref_node (model, iter);
9180       node = _gtk_rbtree_next (tree, node);
9181     }
9182   while (gtk_tree_model_iter_next (model, iter));
9183
9184   return retval;
9185 }
9186
9187 static gint
9188 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9189                                               GtkRBTree   *tree)
9190 {
9191   GtkTreeIter iter;
9192   GtkTreePath *path;
9193   GtkRBNode *node;
9194   gint retval;
9195
9196   if (!tree)
9197     return FALSE;
9198
9199   node = tree->root;
9200   while (node && node->left != tree->nil)
9201     node = node->left;
9202
9203   g_return_val_if_fail (node != NULL, FALSE);
9204   path = _gtk_tree_view_find_path (tree_view, tree, node);
9205   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9206                            &iter, path);
9207   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9208   gtk_tree_path_free (path);
9209
9210   return retval;
9211 }
9212
9213 static void
9214 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9215                                     GtkTreeViewColumn *column)
9216 {
9217   GtkTreeViewColumn *left_column;
9218   GtkTreeViewColumn *cur_column = NULL;
9219   GtkTreeViewColumnReorder *reorder;
9220   gboolean rtl;
9221   GList *tmp_list;
9222   gint left;
9223
9224   /* We want to precalculate the motion list such that we know what column slots
9225    * are available.
9226    */
9227   left_column = NULL;
9228   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9229
9230   /* First, identify all possible drop spots */
9231   if (rtl)
9232     tmp_list = g_list_last (tree_view->priv->columns);
9233   else
9234     tmp_list = g_list_first (tree_view->priv->columns);
9235
9236   while (tmp_list)
9237     {
9238       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9239       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9240
9241       if (cur_column->visible == FALSE)
9242         continue;
9243
9244       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9245       if (left_column != column && cur_column != column &&
9246           tree_view->priv->column_drop_func &&
9247           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9248         {
9249           left_column = cur_column;
9250           continue;
9251         }
9252       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9253       reorder->left_column = left_column;
9254       left_column = reorder->right_column = cur_column;
9255
9256       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9257     }
9258
9259   /* Add the last one */
9260   if (tree_view->priv->column_drop_func == NULL ||
9261       ((left_column != column) &&
9262        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9263     {
9264       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9265       reorder->left_column = left_column;
9266       reorder->right_column = NULL;
9267       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9268     }
9269
9270   /* We quickly check to see if it even makes sense to reorder columns. */
9271   /* If there is nothing that can be moved, then we return */
9272
9273   if (tree_view->priv->column_drag_info == NULL)
9274     return;
9275
9276   /* We know there are always 2 slots possbile, as you can always return column. */
9277   /* If that's all there is, return */
9278   if (tree_view->priv->column_drag_info->next == NULL || 
9279       (tree_view->priv->column_drag_info->next->next == NULL &&
9280        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9281        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9282     {
9283       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9284         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9285       g_list_free (tree_view->priv->column_drag_info);
9286       tree_view->priv->column_drag_info = NULL;
9287       return;
9288     }
9289   /* We fill in the ranges for the columns, now that we've isolated them */
9290   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9291
9292   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9293     {
9294       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9295
9296       reorder->left_align = left;
9297       if (tmp_list->next != NULL)
9298         {
9299           g_assert (tmp_list->next->data);
9300           left = reorder->right_align = (reorder->right_column->button->allocation.x +
9301                                          reorder->right_column->button->allocation.width +
9302                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
9303         }
9304       else
9305         {
9306           gint width;
9307
9308           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9309           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9310         }
9311     }
9312 }
9313
9314 void
9315 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9316                                   GtkTreeViewColumn *column)
9317 {
9318   GdkEvent *send_event;
9319   GtkAllocation allocation;
9320   gint x, y, width, height;
9321   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9322   GdkDisplay *display = gdk_screen_get_display (screen);
9323
9324   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9325   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9326
9327   gtk_tree_view_set_column_drag_info (tree_view, column);
9328
9329   if (tree_view->priv->column_drag_info == NULL)
9330     return;
9331
9332   if (tree_view->priv->drag_window == NULL)
9333     {
9334       GdkWindowAttr attributes;
9335       guint attributes_mask;
9336
9337       attributes.window_type = GDK_WINDOW_CHILD;
9338       attributes.wclass = GDK_INPUT_OUTPUT;
9339       attributes.x = column->button->allocation.x;
9340       attributes.y = 0;
9341       attributes.width = column->button->allocation.width;
9342       attributes.height = column->button->allocation.height;
9343       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9344       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
9345       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9346       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
9347
9348       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9349                                                      &attributes,
9350                                                      attributes_mask);
9351       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9352     }
9353
9354   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9355   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9356
9357   gtk_grab_remove (column->button);
9358
9359   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9360   send_event->crossing.send_event = TRUE;
9361   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9362   send_event->crossing.subwindow = NULL;
9363   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9364   send_event->crossing.time = GDK_CURRENT_TIME;
9365
9366   gtk_propagate_event (column->button, send_event);
9367   gdk_event_free (send_event);
9368
9369   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9370   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9371   send_event->button.send_event = TRUE;
9372   send_event->button.time = GDK_CURRENT_TIME;
9373   send_event->button.x = -1;
9374   send_event->button.y = -1;
9375   send_event->button.axes = NULL;
9376   send_event->button.state = 0;
9377   send_event->button.button = 1;
9378   send_event->button.device = gdk_display_get_core_pointer (display);
9379   send_event->button.x_root = 0;
9380   send_event->button.y_root = 0;
9381
9382   gtk_propagate_event (column->button, send_event);
9383   gdk_event_free (send_event);
9384
9385   /* Kids, don't try this at home */
9386   g_object_ref (column->button);
9387   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9388   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9389   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9390   g_object_unref (column->button);
9391
9392   tree_view->priv->drag_column_x = column->button->allocation.x;
9393   allocation = column->button->allocation;
9394   allocation.x = 0;
9395   gtk_widget_size_allocate (column->button, &allocation);
9396   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9397
9398   tree_view->priv->drag_column = column;
9399   gdk_window_show (tree_view->priv->drag_window);
9400
9401   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9402   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9403
9404   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9405   while (gtk_events_pending ())
9406     gtk_main_iteration ();
9407
9408   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9409   gdk_pointer_grab (tree_view->priv->drag_window,
9410                     FALSE,
9411                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9412                     NULL, NULL, GDK_CURRENT_TIME);
9413   gdk_keyboard_grab (tree_view->priv->drag_window,
9414                      FALSE,
9415                      GDK_CURRENT_TIME);
9416 }
9417
9418 static void
9419 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9420                                 GtkRBTree          *tree,
9421                                 GtkRBNode          *node,
9422                                 const GdkRectangle *clip_rect)
9423 {
9424   GdkRectangle rect;
9425
9426   if (!GTK_WIDGET_REALIZED (tree_view))
9427     return;
9428
9429   rect.x = 0;
9430   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
9431
9432   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9433   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9434
9435   if (clip_rect)
9436     {
9437       GdkRectangle new_rect;
9438
9439       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9440
9441       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9442     }
9443   else
9444     {
9445       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9446     }
9447 }
9448
9449 void
9450 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9451                                 GtkRBTree          *tree,
9452                                 GtkRBNode          *node,
9453                                 const GdkRectangle *clip_rect)
9454 {
9455   GdkRectangle rect;
9456
9457   if (!GTK_WIDGET_REALIZED (tree_view))
9458     return;
9459
9460   rect.x = 0;
9461   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
9462
9463   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9464   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9465
9466   if (clip_rect)
9467     {
9468       GdkRectangle new_rect;
9469
9470       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9471
9472       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9473     }
9474   else
9475     {
9476       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9477     }
9478 }
9479
9480 static void
9481 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9482                                GtkTreePath        *path,
9483                                const GdkRectangle *clip_rect)
9484 {
9485   GtkRBTree *tree = NULL;
9486   GtkRBNode *node = NULL;
9487
9488   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9489
9490   if (tree)
9491     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9492 }
9493
9494 /* x and y are the mouse position
9495  */
9496 static void
9497 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9498                           GtkRBTree   *tree,
9499                           GtkRBNode   *node,
9500                           /* in bin_window coordinates */
9501                           gint         x,
9502                           gint         y)
9503 {
9504   GdkRectangle area;
9505   GtkStateType state;
9506   GtkWidget *widget;
9507   gint x_offset = 0;
9508   gint x2;
9509   gint vertical_separator;
9510   gint expander_size;
9511   GtkExpanderStyle expander_style;
9512
9513   gtk_widget_style_get (GTK_WIDGET (tree_view),
9514                         "vertical-separator", &vertical_separator,
9515                         NULL);
9516   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9517
9518   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9519     return;
9520
9521   widget = GTK_WIDGET (tree_view);
9522
9523   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9524
9525   area.x = x_offset;
9526   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9527   area.width = expander_size + 2;
9528   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9529
9530   if (GTK_WIDGET_STATE (tree_view) == GTK_STATE_INSENSITIVE)
9531     {
9532       state = GTK_STATE_INSENSITIVE;
9533     }
9534   else if (node == tree_view->priv->button_pressed_node)
9535     {
9536       if (x >= area.x && x <= (area.x + area.width) &&
9537           y >= area.y && y <= (area.y + area.height))
9538         state = GTK_STATE_ACTIVE;
9539       else
9540         state = GTK_STATE_NORMAL;
9541     }
9542   else
9543     {
9544       if (node == tree_view->priv->prelight_node &&
9545           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9546         state = GTK_STATE_PRELIGHT;
9547       else
9548         state = GTK_STATE_NORMAL;
9549     }
9550
9551   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9552     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9553   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9554     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9555   else if (node->children != NULL)
9556     expander_style = GTK_EXPANDER_EXPANDED;
9557   else
9558     expander_style = GTK_EXPANDER_COLLAPSED;
9559
9560   gtk_paint_expander (widget->style,
9561                       tree_view->priv->bin_window,
9562                       state,
9563                       &area,
9564                       widget,
9565                       "treeview",
9566                       area.x + area.width / 2,
9567                       area.y + area.height / 2,
9568                       expander_style);
9569 }
9570
9571 static void
9572 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9573
9574 {
9575   GtkTreePath *cursor_path;
9576
9577   if ((tree_view->priv->tree == NULL) ||
9578       (! GTK_WIDGET_REALIZED (tree_view)))
9579     return;
9580
9581   cursor_path = NULL;
9582   if (tree_view->priv->cursor)
9583     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9584
9585   if (cursor_path == NULL)
9586     {
9587       /* Consult the selection before defaulting to the
9588        * first focusable element
9589        */
9590       GList *selected_rows;
9591       GtkTreeModel *model;
9592       GtkTreeSelection *selection;
9593
9594       selection = gtk_tree_view_get_selection (tree_view);
9595       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9596
9597       if (selected_rows)
9598         {
9599           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9600           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9601           g_list_free (selected_rows);
9602         }
9603       else
9604         {
9605           cursor_path = gtk_tree_path_new_first ();
9606           search_first_focusable_path (tree_view, &cursor_path,
9607                                        TRUE, NULL, NULL);
9608         }
9609
9610       gtk_tree_row_reference_free (tree_view->priv->cursor);
9611       tree_view->priv->cursor = NULL;
9612
9613       if (cursor_path)
9614         {
9615           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9616             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9617           else
9618             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9619         }
9620     }
9621
9622   if (cursor_path)
9623     {
9624       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9625
9626       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9627       gtk_tree_path_free (cursor_path);
9628
9629       if (tree_view->priv->focus_column == NULL)
9630         {
9631           GList *list;
9632           for (list = tree_view->priv->columns; list; list = list->next)
9633             {
9634               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9635                 {
9636                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9637                   break;
9638                 }
9639             }
9640         }
9641     }
9642 }
9643
9644 static void
9645 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9646                                    gint         count)
9647 {
9648   gint selection_count;
9649   GtkRBTree *cursor_tree = NULL;
9650   GtkRBNode *cursor_node = NULL;
9651   GtkRBTree *new_cursor_tree = NULL;
9652   GtkRBNode *new_cursor_node = NULL;
9653   GtkTreePath *cursor_path = NULL;
9654   gboolean grab_focus = TRUE;
9655   gboolean selectable;
9656
9657   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9658     return;
9659
9660   cursor_path = NULL;
9661   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9662     /* FIXME: we lost the cursor; should we get the first? */
9663     return;
9664
9665   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9666   _gtk_tree_view_find_node (tree_view, cursor_path,
9667                             &cursor_tree, &cursor_node);
9668
9669   if (cursor_tree == NULL)
9670     /* FIXME: we lost the cursor; should we get the first? */
9671     return;
9672
9673   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9674   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9675                                                       cursor_node,
9676                                                       cursor_path);
9677
9678   if (selection_count == 0
9679       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9680       && !tree_view->priv->ctrl_pressed
9681       && selectable)
9682     {
9683       /* Don't move the cursor, but just select the current node */
9684       new_cursor_tree = cursor_tree;
9685       new_cursor_node = cursor_node;
9686     }
9687   else
9688     {
9689       if (count == -1)
9690         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9691                                &new_cursor_tree, &new_cursor_node);
9692       else
9693         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9694                                &new_cursor_tree, &new_cursor_node);
9695     }
9696
9697   gtk_tree_path_free (cursor_path);
9698
9699   if (new_cursor_node)
9700     {
9701       cursor_path = _gtk_tree_view_find_path (tree_view,
9702                                               new_cursor_tree, new_cursor_node);
9703
9704       search_first_focusable_path (tree_view, &cursor_path,
9705                                    (count != -1),
9706                                    &new_cursor_tree,
9707                                    &new_cursor_node);
9708
9709       if (cursor_path)
9710         gtk_tree_path_free (cursor_path);
9711     }
9712
9713   /*
9714    * If the list has only one item and multi-selection is set then select
9715    * the row (if not yet selected).
9716    */
9717   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9718       new_cursor_node == NULL)
9719     {
9720       if (count == -1)
9721         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9722                                &new_cursor_tree, &new_cursor_node);
9723       else
9724         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9725                                &new_cursor_tree, &new_cursor_node);
9726
9727       if (new_cursor_node == NULL
9728           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9729         {
9730           new_cursor_node = cursor_node;
9731           new_cursor_tree = cursor_tree;
9732         }
9733       else
9734         {
9735           new_cursor_node = NULL;
9736         }
9737     }
9738
9739   if (new_cursor_node)
9740     {
9741       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9742       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9743       gtk_tree_path_free (cursor_path);
9744     }
9745   else
9746     {
9747       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9748
9749       if (!tree_view->priv->shift_pressed)
9750         {
9751           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9752                                           count < 0 ?
9753                                           GTK_DIR_UP : GTK_DIR_DOWN))
9754             {
9755               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9756
9757               if (toplevel)
9758                 gtk_widget_child_focus (toplevel,
9759                                         count < 0 ?
9760                                         GTK_DIR_TAB_BACKWARD :
9761                                         GTK_DIR_TAB_FORWARD);
9762
9763               grab_focus = FALSE;
9764             }
9765         }
9766       else
9767         {
9768           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9769         }
9770     }
9771
9772   if (grab_focus)
9773     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9774 }
9775
9776 static void
9777 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9778                                         gint         count)
9779 {
9780   GtkRBTree *cursor_tree = NULL;
9781   GtkRBNode *cursor_node = NULL;
9782   GtkTreePath *old_cursor_path = NULL;
9783   GtkTreePath *cursor_path = NULL;
9784   GtkRBTree *start_cursor_tree = NULL;
9785   GtkRBNode *start_cursor_node = NULL;
9786   gint y;
9787   gint window_y;
9788   gint vertical_separator;
9789
9790   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9791     return;
9792
9793   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9794     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9795   else
9796     /* This is sorta weird.  Focus in should give us a cursor */
9797     return;
9798
9799   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9800   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9801                             &cursor_tree, &cursor_node);
9802
9803   if (cursor_tree == NULL)
9804     {
9805       /* FIXME: we lost the cursor.  Should we try to get one? */
9806       gtk_tree_path_free (old_cursor_path);
9807       return;
9808     }
9809   g_return_if_fail (cursor_node != NULL);
9810
9811   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9812   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9813   y += tree_view->priv->cursor_offset;
9814   y += count * (int)tree_view->priv->vadjustment->page_increment;
9815   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9816
9817   if (y >= tree_view->priv->height)
9818     y = tree_view->priv->height - 1;
9819
9820   tree_view->priv->cursor_offset =
9821     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9822                              &cursor_tree, &cursor_node);
9823
9824   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9825     {
9826       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9827                              &cursor_tree, &cursor_node);
9828       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9829     }
9830
9831   y -= tree_view->priv->cursor_offset;
9832   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9833
9834   start_cursor_tree = cursor_tree;
9835   start_cursor_node = cursor_node;
9836
9837   if (! search_first_focusable_path (tree_view, &cursor_path,
9838                                      (count != -1),
9839                                      &cursor_tree, &cursor_node))
9840     {
9841       /* It looks like we reached the end of the view without finding
9842        * a focusable row.  We will step backwards to find the last
9843        * focusable row.
9844        */
9845       cursor_tree = start_cursor_tree;
9846       cursor_node = start_cursor_node;
9847       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9848
9849       search_first_focusable_path (tree_view, &cursor_path,
9850                                    (count == -1),
9851                                    &cursor_tree, &cursor_node);
9852     }
9853
9854   if (!cursor_path)
9855     goto cleanup;
9856
9857   /* update y */
9858   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9859
9860   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9861
9862   y -= window_y;
9863   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9864   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9865   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9866
9867   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9868     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9869
9870 cleanup:
9871   gtk_tree_path_free (old_cursor_path);
9872   gtk_tree_path_free (cursor_path);
9873 }
9874
9875 static void
9876 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9877                                       gint         count)
9878 {
9879   GtkRBTree *cursor_tree = NULL;
9880   GtkRBNode *cursor_node = NULL;
9881   GtkTreePath *cursor_path = NULL;
9882   GtkTreeViewColumn *column;
9883   GtkTreeIter iter;
9884   GList *list;
9885   gboolean found_column = FALSE;
9886   gboolean rtl;
9887
9888   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9889
9890   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9891     return;
9892
9893   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9894     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9895   else
9896     return;
9897
9898   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9899   if (cursor_tree == NULL)
9900     return;
9901   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9902     {
9903       gtk_tree_path_free (cursor_path);
9904       return;
9905     }
9906   gtk_tree_path_free (cursor_path);
9907
9908   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9909   if (tree_view->priv->focus_column)
9910     {
9911       for (; list; list = (rtl ? list->prev : list->next))
9912         {
9913           if (list->data == tree_view->priv->focus_column)
9914             break;
9915         }
9916     }
9917
9918   while (list)
9919     {
9920       gboolean left, right;
9921
9922       column = list->data;
9923       if (column->visible == FALSE)
9924         goto loop_end;
9925
9926       gtk_tree_view_column_cell_set_cell_data (column,
9927                                                tree_view->priv->model,
9928                                                &iter,
9929                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9930                                                cursor_node->children?TRUE:FALSE);
9931
9932       if (rtl)
9933         {
9934           right = list->prev ? TRUE : FALSE;
9935           left = list->next ? TRUE : FALSE;
9936         }
9937       else
9938         {
9939           left = list->prev ? TRUE : FALSE;
9940           right = list->next ? TRUE : FALSE;
9941         }
9942
9943       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9944         {
9945           tree_view->priv->focus_column = column;
9946           found_column = TRUE;
9947           break;
9948         }
9949     loop_end:
9950       if (count == 1)
9951         list = rtl ? list->prev : list->next;
9952       else
9953         list = rtl ? list->next : list->prev;
9954     }
9955
9956   if (found_column)
9957     {
9958       if (!gtk_tree_view_has_special_cell (tree_view))
9959         _gtk_tree_view_queue_draw_node (tree_view,
9960                                         cursor_tree,
9961                                         cursor_node,
9962                                         NULL);
9963       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9964     }
9965   else
9966     {
9967       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9968     }
9969
9970   gtk_tree_view_clamp_column_visible (tree_view,
9971                                       tree_view->priv->focus_column, TRUE);
9972 }
9973
9974 static void
9975 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9976                                      gint         count)
9977 {
9978   GtkRBTree *cursor_tree;
9979   GtkRBNode *cursor_node;
9980   GtkTreePath *path;
9981   GtkTreePath *old_path;
9982
9983   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9984     return;
9985
9986   g_return_if_fail (tree_view->priv->tree != NULL);
9987
9988   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9989
9990   cursor_tree = tree_view->priv->tree;
9991   cursor_node = cursor_tree->root;
9992
9993   if (count == -1)
9994     {
9995       while (cursor_node && cursor_node->left != cursor_tree->nil)
9996         cursor_node = cursor_node->left;
9997
9998       /* Now go forward to find the first focusable row. */
9999       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10000       search_first_focusable_path (tree_view, &path,
10001                                    TRUE, &cursor_tree, &cursor_node);
10002     }
10003   else
10004     {
10005       do
10006         {
10007           while (cursor_node && cursor_node->right != cursor_tree->nil)
10008             cursor_node = cursor_node->right;
10009           if (cursor_node->children == NULL)
10010             break;
10011
10012           cursor_tree = cursor_node->children;
10013           cursor_node = cursor_tree->root;
10014         }
10015       while (1);
10016
10017       /* Now go backwards to find last focusable row. */
10018       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10019       search_first_focusable_path (tree_view, &path,
10020                                    FALSE, &cursor_tree, &cursor_node);
10021     }
10022
10023   if (!path)
10024     goto cleanup;
10025
10026   if (gtk_tree_path_compare (old_path, path))
10027     {
10028       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10029     }
10030   else
10031     {
10032       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10033     }
10034
10035 cleanup:
10036   gtk_tree_path_free (old_path);
10037   gtk_tree_path_free (path);
10038 }
10039
10040 static gboolean
10041 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10042 {
10043   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10044     return FALSE;
10045
10046   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10047     return FALSE;
10048
10049   gtk_tree_selection_select_all (tree_view->priv->selection);
10050
10051   return TRUE;
10052 }
10053
10054 static gboolean
10055 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10056 {
10057   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10058     return FALSE;
10059
10060   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10061     return FALSE;
10062
10063   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10064
10065   return TRUE;
10066 }
10067
10068 static gboolean
10069 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10070                                       gboolean     start_editing)
10071 {
10072   GtkRBTree *new_tree = NULL;
10073   GtkRBNode *new_node = NULL;
10074   GtkRBTree *cursor_tree = NULL;
10075   GtkRBNode *cursor_node = NULL;
10076   GtkTreePath *cursor_path = NULL;
10077   GtkTreeSelectMode mode = 0;
10078
10079   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10080     return FALSE;
10081
10082   if (tree_view->priv->cursor)
10083     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10084
10085   if (cursor_path == NULL)
10086     return FALSE;
10087
10088   _gtk_tree_view_find_node (tree_view, cursor_path,
10089                             &cursor_tree, &cursor_node);
10090
10091   if (cursor_tree == NULL)
10092     {
10093       gtk_tree_path_free (cursor_path);
10094       return FALSE;
10095     }
10096
10097   if (!tree_view->priv->shift_pressed && start_editing &&
10098       tree_view->priv->focus_column)
10099     {
10100       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10101         {
10102           gtk_tree_path_free (cursor_path);
10103           return TRUE;
10104         }
10105     }
10106
10107   if (tree_view->priv->ctrl_pressed)
10108     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10109   if (tree_view->priv->shift_pressed)
10110     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10111
10112   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10113                                             cursor_node,
10114                                             cursor_tree,
10115                                             cursor_path,
10116                                             mode,
10117                                             FALSE);
10118
10119   /* We bail out if the original (tree, node) don't exist anymore after
10120    * handling the selection-changed callback.  We do return TRUE because
10121    * the key press has been handled at this point.
10122    */
10123   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10124
10125   if (cursor_tree != new_tree || cursor_node != new_node)
10126     return FALSE;
10127
10128   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10129
10130   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10131   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10132
10133   if (!tree_view->priv->shift_pressed)
10134     gtk_tree_view_row_activated (tree_view, cursor_path,
10135                                  tree_view->priv->focus_column);
10136     
10137   gtk_tree_path_free (cursor_path);
10138
10139   return TRUE;
10140 }
10141
10142 static gboolean
10143 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10144 {
10145   GtkRBTree *new_tree = NULL;
10146   GtkRBNode *new_node = NULL;
10147   GtkRBTree *cursor_tree = NULL;
10148   GtkRBNode *cursor_node = NULL;
10149   GtkTreePath *cursor_path = NULL;
10150
10151   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10152     return FALSE;
10153
10154   cursor_path = NULL;
10155   if (tree_view->priv->cursor)
10156     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10157
10158   if (cursor_path == NULL)
10159     return FALSE;
10160
10161   _gtk_tree_view_find_node (tree_view, cursor_path,
10162                             &cursor_tree, &cursor_node);
10163   if (cursor_tree == NULL)
10164     {
10165       gtk_tree_path_free (cursor_path);
10166       return FALSE;
10167     }
10168
10169   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10170                                             cursor_node,
10171                                             cursor_tree,
10172                                             cursor_path,
10173                                             GTK_TREE_SELECT_MODE_TOGGLE,
10174                                             FALSE);
10175
10176   /* We bail out if the original (tree, node) don't exist anymore after
10177    * handling the selection-changed callback.  We do return TRUE because
10178    * the key press has been handled at this point.
10179    */
10180   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10181
10182   if (cursor_tree != new_tree || cursor_node != new_node)
10183     return FALSE;
10184
10185   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10186
10187   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10188   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10189   gtk_tree_path_free (cursor_path);
10190
10191   return TRUE;
10192 }
10193
10194 static gboolean
10195 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10196                                                gboolean     logical,
10197                                                gboolean     expand,
10198                                                gboolean     open_all)
10199 {
10200   GtkTreePath *cursor_path = NULL;
10201   GtkRBTree *tree;
10202   GtkRBNode *node;
10203
10204   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10205     return FALSE;
10206
10207   cursor_path = NULL;
10208   if (tree_view->priv->cursor)
10209     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10210
10211   if (cursor_path == NULL)
10212     return FALSE;
10213
10214   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10215     return FALSE;
10216
10217   /* Don't handle the event if we aren't an expander */
10218   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10219     return FALSE;
10220
10221   if (!logical
10222       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10223     expand = !expand;
10224
10225   if (expand)
10226     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10227   else
10228     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10229
10230   gtk_tree_path_free (cursor_path);
10231
10232   return TRUE;
10233 }
10234
10235 static gboolean
10236 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10237 {
10238   GtkRBTree *cursor_tree = NULL;
10239   GtkRBNode *cursor_node = NULL;
10240   GtkTreePath *cursor_path = NULL;
10241   GdkModifierType state;
10242
10243   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10244     goto out;
10245
10246   cursor_path = NULL;
10247   if (tree_view->priv->cursor)
10248     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10249
10250   if (cursor_path == NULL)
10251     goto out;
10252
10253   _gtk_tree_view_find_node (tree_view, cursor_path,
10254                             &cursor_tree, &cursor_node);
10255   if (cursor_tree == NULL)
10256     {
10257       gtk_tree_path_free (cursor_path);
10258       goto out;
10259     }
10260
10261   if (cursor_tree->parent_node)
10262     {
10263       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10264       cursor_node = cursor_tree->parent_node;
10265       cursor_tree = cursor_tree->parent_tree;
10266
10267       gtk_tree_path_up (cursor_path);
10268
10269       if (gtk_get_current_event_state (&state))
10270         {
10271           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10272             tree_view->priv->ctrl_pressed = TRUE;
10273         }
10274
10275       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10276       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10277
10278       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10279       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10280       gtk_tree_path_free (cursor_path);
10281
10282       tree_view->priv->ctrl_pressed = FALSE;
10283
10284       return TRUE;
10285     }
10286
10287  out:
10288
10289   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10290   return FALSE;
10291 }
10292
10293 static gboolean
10294 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10295 {
10296   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
10297   tree_view->priv->typeselect_flush_timeout = 0;
10298
10299   return FALSE;
10300 }
10301
10302 /* Cut and paste from gtkwindow.c */
10303 static void
10304 send_focus_change (GtkWidget *widget,
10305                    gboolean   in)
10306 {
10307   GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10308
10309   g_object_ref (widget);
10310    
10311  if (in)
10312     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
10313   else
10314     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
10315
10316   fevent->focus_change.type = GDK_FOCUS_CHANGE;
10317   fevent->focus_change.window = g_object_ref (widget->window);
10318   fevent->focus_change.in = in;
10319   
10320   gtk_widget_event (widget, fevent);
10321   
10322   g_object_notify (G_OBJECT (widget), "has-focus");
10323
10324   g_object_unref (widget);
10325   gdk_event_free (fevent);
10326 }
10327
10328 static void
10329 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10330 {
10331   GtkWidget *frame, *vbox, *toplevel;
10332   GdkScreen *screen;
10333
10334   if (tree_view->priv->search_custom_entry_set)
10335     return;
10336
10337   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10338   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10339
10340    if (tree_view->priv->search_window != NULL)
10341      {
10342        if (GTK_WINDOW (toplevel)->group)
10343          gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10344                                       GTK_WINDOW (tree_view->priv->search_window));
10345        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
10346          gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
10347                                          GTK_WINDOW (tree_view->priv->search_window));
10348        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10349        return;
10350      }
10351    
10352   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10353   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10354
10355   if (GTK_WINDOW (toplevel)->group)
10356     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10357                                  GTK_WINDOW (tree_view->priv->search_window));
10358
10359   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10360                             GDK_WINDOW_TYPE_HINT_UTILITY);
10361   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10362   g_signal_connect (tree_view->priv->search_window, "delete-event",
10363                     G_CALLBACK (gtk_tree_view_search_delete_event),
10364                     tree_view);
10365   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10366                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10367                     tree_view);
10368   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10369                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10370                     tree_view);
10371   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10372                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10373                     tree_view);
10374
10375   frame = gtk_frame_new (NULL);
10376   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10377   gtk_widget_show (frame);
10378   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10379
10380   vbox = gtk_vbox_new (FALSE, 0);
10381   gtk_widget_show (vbox);
10382   gtk_container_add (GTK_CONTAINER (frame), vbox);
10383   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10384
10385   /* add entry */
10386   tree_view->priv->search_entry = gtk_entry_new ();
10387   gtk_widget_show (tree_view->priv->search_entry);
10388   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10389                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10390                     tree_view);
10391   g_signal_connect (tree_view->priv->search_entry,
10392                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10393                     tree_view);
10394   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10395                     "preedit-changed",
10396                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10397                     tree_view);
10398   gtk_container_add (GTK_CONTAINER (vbox),
10399                      tree_view->priv->search_entry);
10400
10401   gtk_widget_realize (tree_view->priv->search_entry);
10402 }
10403
10404 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10405  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10406  */
10407 static gboolean
10408 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10409                                              gboolean     keybinding)
10410 {
10411   /* We only start interactive search if we have focus or the columns
10412    * have focus.  If one of our children have focus, we don't want to
10413    * start the search.
10414    */
10415   GList *list;
10416   gboolean found_focus = FALSE;
10417   GtkWidgetClass *entry_parent_class;
10418   
10419   if (!tree_view->priv->enable_search && !keybinding)
10420     return FALSE;
10421
10422   if (tree_view->priv->search_custom_entry_set)
10423     return FALSE;
10424
10425   if (tree_view->priv->search_window != NULL &&
10426       GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
10427     return TRUE;
10428
10429   for (list = tree_view->priv->columns; list; list = list->next)
10430     {
10431       GtkTreeViewColumn *column;
10432
10433       column = list->data;
10434       if (! column->visible)
10435         continue;
10436
10437       if (GTK_WIDGET_HAS_FOCUS (column->button))
10438         {
10439           found_focus = TRUE;
10440           break;
10441         }
10442     }
10443   
10444   if (GTK_WIDGET_HAS_FOCUS (tree_view))
10445     found_focus = TRUE;
10446
10447   if (!found_focus)
10448     return FALSE;
10449
10450   if (tree_view->priv->search_column < 0)
10451     return FALSE;
10452
10453   gtk_tree_view_ensure_interactive_directory (tree_view);
10454
10455   if (keybinding)
10456     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10457
10458   /* done, show it */
10459   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10460   gtk_widget_show (tree_view->priv->search_window);
10461   if (tree_view->priv->search_entry_changed_id == 0)
10462     {
10463       tree_view->priv->search_entry_changed_id =
10464         g_signal_connect (tree_view->priv->search_entry, "changed",
10465                           G_CALLBACK (gtk_tree_view_search_init),
10466                           tree_view);
10467     }
10468
10469   tree_view->priv->typeselect_flush_timeout =
10470     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10471                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10472                    tree_view);
10473
10474   /* Grab focus will select all the text.  We don't want that to happen, so we
10475    * call the parent instance and bypass the selection change.  This is probably
10476    * really non-kosher. */
10477   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10478   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10479
10480   /* send focus-in event */
10481   send_focus_change (tree_view->priv->search_entry, TRUE);
10482
10483   /* search first matching iter */
10484   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10485
10486   return TRUE;
10487 }
10488
10489 static gboolean
10490 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10491 {
10492   return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
10493 }
10494
10495 /* this function returns the new width of the column being resized given
10496  * the column and x position of the cursor; the x cursor position is passed
10497  * in as a pointer and automagicly corrected if it's beyond min/max limits
10498  */
10499 static gint
10500 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10501                                 gint       i,
10502                                 gint      *x)
10503 {
10504   GtkTreeViewColumn *column;
10505   gint width;
10506   gboolean rtl;
10507
10508   /* first translate the x position from widget->window
10509    * to clist->clist_window
10510    */
10511   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10512   column = g_list_nth (tree_view->priv->columns, i)->data;
10513   width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
10514  
10515   /* Clamp down the value */
10516   if (column->min_width == -1)
10517     width = MAX (column->button->requisition.width,
10518                  width);
10519   else
10520     width = MAX (column->min_width,
10521                  width);
10522   if (column->max_width != -1)
10523     width = MIN (width, column->max_width);
10524
10525   *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
10526  
10527   return width;
10528 }
10529
10530
10531 /* FIXME this adjust_allocation is a big cut-and-paste from
10532  * GtkCList, needs to be some "official" way to do this
10533  * factored out.
10534  */
10535 typedef struct
10536 {
10537   GdkWindow *window;
10538   int dx;
10539   int dy;
10540 } ScrollData;
10541
10542 /* The window to which widget->window is relative */
10543 #define ALLOCATION_WINDOW(widget)               \
10544    (GTK_WIDGET_NO_WINDOW (widget) ?             \
10545     (widget)->window :                          \
10546      gdk_window_get_parent ((widget)->window))
10547
10548 static void
10549 adjust_allocation_recurse (GtkWidget *widget,
10550                            gpointer   data)
10551 {
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   if (!GTK_WIDGET_REALIZED (widget))
10559     {
10560       if (GTK_WIDGET_VISIBLE (widget))
10561         {
10562           GdkRectangle tmp_rectangle = widget->allocation;
10563           tmp_rectangle.x += scroll_data->dx;
10564           tmp_rectangle.y += scroll_data->dy;
10565           
10566           gtk_widget_size_allocate (widget, &tmp_rectangle);
10567         }
10568     }
10569   else
10570     {
10571       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10572         {
10573           widget->allocation.x += scroll_data->dx;
10574           widget->allocation.y += scroll_data->dy;
10575           
10576           if (GTK_IS_CONTAINER (widget))
10577             gtk_container_forall (GTK_CONTAINER (widget),
10578                                   adjust_allocation_recurse,
10579                                   data);
10580         }
10581     }
10582 }
10583
10584 static void
10585 adjust_allocation (GtkWidget *widget,
10586                    int        dx,
10587                    int        dy)
10588 {
10589   ScrollData scroll_data;
10590
10591   if (GTK_WIDGET_REALIZED (widget))
10592     scroll_data.window = ALLOCATION_WINDOW (widget);
10593   else
10594     scroll_data.window = NULL;
10595     
10596   scroll_data.dx = dx;
10597   scroll_data.dy = dy;
10598   
10599   adjust_allocation_recurse (widget, &scroll_data);
10600 }
10601
10602 /* Callbacks */
10603 static void
10604 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10605                                   GtkTreeView   *tree_view)
10606 {
10607   if (GTK_WIDGET_REALIZED (tree_view))
10608     {
10609       gint dy;
10610         
10611       gdk_window_move (tree_view->priv->bin_window,
10612                        - tree_view->priv->hadjustment->value,
10613                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10614       gdk_window_move (tree_view->priv->header_window,
10615                        - tree_view->priv->hadjustment->value,
10616                        0);
10617       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10618       if (dy && tree_view->priv->edited_column)
10619         {
10620           if (GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10621             {
10622               GList *list;
10623               GtkWidget *widget;
10624               GtkTreeViewChild *child = NULL;
10625
10626               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10627               adjust_allocation (widget, 0, dy); 
10628               
10629               for (list = tree_view->priv->children; list; list = list->next)
10630                 {
10631                   child = (GtkTreeViewChild *)list->data;
10632                   if (child->widget == widget)
10633                     {
10634                       child->y += dy;
10635                       break;
10636                     }
10637                 }
10638             }
10639         }
10640       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10641
10642       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10643         {
10644           /* update our dy and top_row */
10645           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10646
10647           if (!tree_view->priv->in_top_row_to_dy)
10648             gtk_tree_view_dy_to_top_row (tree_view);
10649         }
10650     }
10651 }
10652
10653 \f
10654
10655 /* Public methods
10656  */
10657
10658 /**
10659  * gtk_tree_view_new:
10660  *
10661  * Creates a new #GtkTreeView widget.
10662  *
10663  * Return value: A newly created #GtkTreeView widget.
10664  **/
10665 GtkWidget *
10666 gtk_tree_view_new (void)
10667 {
10668   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10669 }
10670
10671 /**
10672  * gtk_tree_view_new_with_model:
10673  * @model: the model.
10674  *
10675  * Creates a new #GtkTreeView widget with the model initialized to @model.
10676  *
10677  * Return value: A newly created #GtkTreeView widget.
10678  **/
10679 GtkWidget *
10680 gtk_tree_view_new_with_model (GtkTreeModel *model)
10681 {
10682   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10683 }
10684
10685 /* Public Accessors
10686  */
10687
10688 /**
10689  * gtk_tree_view_get_model:
10690  * @tree_view: a #GtkTreeView
10691  *
10692  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10693  * model is unset.
10694  *
10695  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
10696  **/
10697 GtkTreeModel *
10698 gtk_tree_view_get_model (GtkTreeView *tree_view)
10699 {
10700   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10701
10702   return tree_view->priv->model;
10703 }
10704
10705 /**
10706  * gtk_tree_view_set_model:
10707  * @tree_view: A #GtkTreeNode.
10708  * @model: The model.
10709  *
10710  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10711  * set, it will remove it before setting the new model.  If @model is %NULL, 
10712  * then it will unset the old model.
10713  **/
10714 void
10715 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10716                          GtkTreeModel *model)
10717 {
10718   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10719   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10720
10721   if (model == tree_view->priv->model)
10722     return;
10723
10724   if (tree_view->priv->scroll_to_path)
10725     {
10726       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10727       tree_view->priv->scroll_to_path = NULL;
10728     }
10729
10730   if (tree_view->priv->model)
10731     {
10732       GList *tmplist = tree_view->priv->columns;
10733
10734       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10735       gtk_tree_view_stop_editing (tree_view, TRUE);
10736
10737       remove_expand_collapse_timeout (tree_view);
10738
10739       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10740                                             gtk_tree_view_row_changed,
10741                                             tree_view);
10742       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10743                                             gtk_tree_view_row_inserted,
10744                                             tree_view);
10745       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10746                                             gtk_tree_view_row_has_child_toggled,
10747                                             tree_view);
10748       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10749                                             gtk_tree_view_row_deleted,
10750                                             tree_view);
10751       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10752                                             gtk_tree_view_rows_reordered,
10753                                             tree_view);
10754
10755       for (; tmplist; tmplist = tmplist->next)
10756         _gtk_tree_view_column_unset_model (tmplist->data,
10757                                            tree_view->priv->model);
10758
10759       if (tree_view->priv->tree)
10760         gtk_tree_view_free_rbtree (tree_view);
10761
10762       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10763       tree_view->priv->drag_dest_row = NULL;
10764       gtk_tree_row_reference_free (tree_view->priv->cursor);
10765       tree_view->priv->cursor = NULL;
10766       gtk_tree_row_reference_free (tree_view->priv->anchor);
10767       tree_view->priv->anchor = NULL;
10768       gtk_tree_row_reference_free (tree_view->priv->top_row);
10769       tree_view->priv->top_row = NULL;
10770       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
10771       tree_view->priv->last_button_press = NULL;
10772       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
10773       tree_view->priv->last_button_press_2 = NULL;
10774       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10775       tree_view->priv->scroll_to_path = NULL;
10776
10777       tree_view->priv->scroll_to_column = NULL;
10778
10779       g_object_unref (tree_view->priv->model);
10780
10781       tree_view->priv->search_column = -1;
10782       tree_view->priv->fixed_height_check = 0;
10783       tree_view->priv->fixed_height = -1;
10784       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10785     }
10786
10787   tree_view->priv->model = model;
10788
10789   if (tree_view->priv->model)
10790     {
10791       gint i;
10792       GtkTreePath *path;
10793       GtkTreeIter iter;
10794       GtkTreeModelFlags flags;
10795
10796       if (tree_view->priv->search_column == -1)
10797         {
10798           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10799             {
10800               GType type = gtk_tree_model_get_column_type (model, i);
10801
10802               if (g_value_type_transformable (type, G_TYPE_STRING))
10803                 {
10804                   tree_view->priv->search_column = i;
10805                   break;
10806                 }
10807             }
10808         }
10809
10810       g_object_ref (tree_view->priv->model);
10811       g_signal_connect (tree_view->priv->model,
10812                         "row-changed",
10813                         G_CALLBACK (gtk_tree_view_row_changed),
10814                         tree_view);
10815       g_signal_connect (tree_view->priv->model,
10816                         "row-inserted",
10817                         G_CALLBACK (gtk_tree_view_row_inserted),
10818                         tree_view);
10819       g_signal_connect (tree_view->priv->model,
10820                         "row-has-child-toggled",
10821                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10822                         tree_view);
10823       g_signal_connect (tree_view->priv->model,
10824                         "row-deleted",
10825                         G_CALLBACK (gtk_tree_view_row_deleted),
10826                         tree_view);
10827       g_signal_connect (tree_view->priv->model,
10828                         "rows-reordered",
10829                         G_CALLBACK (gtk_tree_view_rows_reordered),
10830                         tree_view);
10831
10832       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10833       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10834         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10835       else
10836         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10837
10838       path = gtk_tree_path_new_first ();
10839       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10840         {
10841           tree_view->priv->tree = _gtk_rbtree_new ();
10842           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10843         }
10844       gtk_tree_path_free (path);
10845
10846       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10847       install_presize_handler (tree_view);
10848     }
10849
10850   g_object_notify (G_OBJECT (tree_view), "model");
10851
10852   if (tree_view->priv->selection)
10853   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10854
10855   if (GTK_WIDGET_REALIZED (tree_view))
10856     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10857 }
10858
10859 /**
10860  * gtk_tree_view_get_selection:
10861  * @tree_view: A #GtkTreeView.
10862  *
10863  * Gets the #GtkTreeSelection associated with @tree_view.
10864  *
10865  * Return value: A #GtkTreeSelection object.
10866  **/
10867 GtkTreeSelection *
10868 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10869 {
10870   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10871
10872   return tree_view->priv->selection;
10873 }
10874
10875 /**
10876  * gtk_tree_view_get_hadjustment:
10877  * @tree_view: A #GtkTreeView
10878  *
10879  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10880  *
10881  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10882  * used.
10883  **/
10884 GtkAdjustment *
10885 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10886 {
10887   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10888
10889   if (tree_view->priv->hadjustment == NULL)
10890     gtk_tree_view_set_hadjustment (tree_view, NULL);
10891
10892   return tree_view->priv->hadjustment;
10893 }
10894
10895 /**
10896  * gtk_tree_view_set_hadjustment:
10897  * @tree_view: A #GtkTreeView
10898  * @adjustment: The #GtkAdjustment to set, or %NULL
10899  *
10900  * Sets the #GtkAdjustment for the current horizontal aspect.
10901  **/
10902 void
10903 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10904                                GtkAdjustment *adjustment)
10905 {
10906   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10907
10908   gtk_tree_view_set_adjustments (tree_view,
10909                                  adjustment,
10910                                  tree_view->priv->vadjustment);
10911
10912   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10913 }
10914
10915 /**
10916  * gtk_tree_view_get_vadjustment:
10917  * @tree_view: A #GtkTreeView
10918  *
10919  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10920  *
10921  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10922  * used.
10923  **/
10924 GtkAdjustment *
10925 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10926 {
10927   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10928
10929   if (tree_view->priv->vadjustment == NULL)
10930     gtk_tree_view_set_vadjustment (tree_view, NULL);
10931
10932   return tree_view->priv->vadjustment;
10933 }
10934
10935 /**
10936  * gtk_tree_view_set_vadjustment:
10937  * @tree_view: A #GtkTreeView
10938  * @adjustment: The #GtkAdjustment to set, or %NULL
10939  *
10940  * Sets the #GtkAdjustment for the current vertical aspect.
10941  **/
10942 void
10943 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10944                                GtkAdjustment *adjustment)
10945 {
10946   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10947
10948   gtk_tree_view_set_adjustments (tree_view,
10949                                  tree_view->priv->hadjustment,
10950                                  adjustment);
10951
10952   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10953 }
10954
10955 /* Column and header operations */
10956
10957 /**
10958  * gtk_tree_view_get_headers_visible:
10959  * @tree_view: A #GtkTreeView.
10960  *
10961  * Returns %TRUE if the headers on the @tree_view are visible.
10962  *
10963  * Return value: Whether the headers are visible or not.
10964  **/
10965 gboolean
10966 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10967 {
10968   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10969
10970   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10971 }
10972
10973 /**
10974  * gtk_tree_view_set_headers_visible:
10975  * @tree_view: A #GtkTreeView.
10976  * @headers_visible: %TRUE if the headers are visible
10977  *
10978  * Sets the visibility state of the headers.
10979  **/
10980 void
10981 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
10982                                    gboolean     headers_visible)
10983 {
10984   gint x, y;
10985   GList *list;
10986   GtkTreeViewColumn *column;
10987
10988   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10989
10990   headers_visible = !! headers_visible;
10991
10992   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
10993     return;
10994
10995   if (headers_visible)
10996     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10997   else
10998     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10999
11000   if (GTK_WIDGET_REALIZED (tree_view))
11001     {
11002       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11003       if (headers_visible)
11004         {
11005           gdk_window_move_resize (tree_view->priv->bin_window, x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view), tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
11006
11007           if (GTK_WIDGET_MAPPED (tree_view))
11008             gtk_tree_view_map_buttons (tree_view);
11009         }
11010       else
11011         {
11012           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11013
11014           for (list = tree_view->priv->columns; list; list = list->next)
11015             {
11016               column = list->data;
11017               gtk_widget_unmap (column->button);
11018             }
11019           gdk_window_hide (tree_view->priv->header_window);
11020         }
11021     }
11022
11023   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11024   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11025   tree_view->priv->vadjustment->lower = 0;
11026   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11027   gtk_adjustment_changed (tree_view->priv->vadjustment);
11028
11029   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11030
11031   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11032 }
11033
11034 /**
11035  * gtk_tree_view_columns_autosize:
11036  * @tree_view: A #GtkTreeView.
11037  *
11038  * Resizes all columns to their optimal width. Only works after the
11039  * treeview has been realized.
11040  **/
11041 void
11042 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11043 {
11044   gboolean dirty = FALSE;
11045   GList *list;
11046   GtkTreeViewColumn *column;
11047
11048   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11049
11050   for (list = tree_view->priv->columns; list; list = list->next)
11051     {
11052       column = list->data;
11053       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11054         continue;
11055       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11056       dirty = TRUE;
11057     }
11058
11059   if (dirty)
11060     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11061 }
11062
11063 /**
11064  * gtk_tree_view_set_headers_clickable:
11065  * @tree_view: A #GtkTreeView.
11066  * @setting: %TRUE if the columns are clickable.
11067  *
11068  * Allow the column title buttons to be clicked.
11069  **/
11070 void
11071 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11072                                      gboolean   setting)
11073 {
11074   GList *list;
11075
11076   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11077
11078   for (list = tree_view->priv->columns; list; list = list->next)
11079     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11080
11081   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11082 }
11083
11084
11085 /**
11086  * gtk_tree_view_get_headers_clickable:
11087  * @tree_view: A #GtkTreeView.
11088  *
11089  * Returns whether all header columns are clickable.
11090  *
11091  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11092  *
11093  * Since: 2.10
11094  **/
11095 gboolean 
11096 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11097 {
11098   GList *list;
11099   
11100   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11101
11102   for (list = tree_view->priv->columns; list; list = list->next)
11103     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11104       return FALSE;
11105
11106   return TRUE;
11107 }
11108
11109 /**
11110  * gtk_tree_view_set_rules_hint
11111  * @tree_view: a #GtkTreeView
11112  * @setting: %TRUE if the tree requires reading across rows
11113  *
11114  * This function tells GTK+ that the user interface for your
11115  * application requires users to read across tree rows and associate
11116  * cells with one another. By default, GTK+ will then render the tree
11117  * with alternating row colors. Do <emphasis>not</emphasis> use it
11118  * just because you prefer the appearance of the ruled tree; that's a
11119  * question for the theme. Some themes will draw tree rows in
11120  * alternating colors even when rules are turned off, and users who
11121  * prefer that appearance all the time can choose those themes. You
11122  * should call this function only as a <emphasis>semantic</emphasis>
11123  * hint to the theme engine that your tree makes alternating colors
11124  * useful from a functional standpoint (since it has lots of columns,
11125  * generally).
11126  *
11127  **/
11128 void
11129 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11130                               gboolean      setting)
11131 {
11132   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11133
11134   setting = setting != FALSE;
11135
11136   if (tree_view->priv->has_rules != setting)
11137     {
11138       tree_view->priv->has_rules = setting;
11139       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11140     }
11141
11142   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11143 }
11144
11145 /**
11146  * gtk_tree_view_get_rules_hint
11147  * @tree_view: a #GtkTreeView
11148  *
11149  * Gets the setting set by gtk_tree_view_set_rules_hint().
11150  *
11151  * Return value: %TRUE if rules are useful for the user of this tree
11152  **/
11153 gboolean
11154 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11155 {
11156   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11157
11158   return tree_view->priv->has_rules;
11159 }
11160
11161 /* Public Column functions
11162  */
11163
11164 /**
11165  * gtk_tree_view_append_column:
11166  * @tree_view: A #GtkTreeView.
11167  * @column: The #GtkTreeViewColumn to add.
11168  *
11169  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11170  * mode enabled, then @column must have its "sizing" property set to be
11171  * GTK_TREE_VIEW_COLUMN_FIXED.
11172  *
11173  * Return value: The number of columns in @tree_view after appending.
11174  **/
11175 gint
11176 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11177                              GtkTreeViewColumn *column)
11178 {
11179   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11180   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11181   g_return_val_if_fail (column->tree_view == NULL, -1);
11182
11183   return gtk_tree_view_insert_column (tree_view, column, -1);
11184 }
11185
11186
11187 /**
11188  * gtk_tree_view_remove_column:
11189  * @tree_view: A #GtkTreeView.
11190  * @column: The #GtkTreeViewColumn to remove.
11191  *
11192  * Removes @column from @tree_view.
11193  *
11194  * Return value: The number of columns in @tree_view after removing.
11195  **/
11196 gint
11197 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11198                              GtkTreeViewColumn *column)
11199 {
11200   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11201   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11202   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11203
11204   if (tree_view->priv->focus_column == column)
11205     tree_view->priv->focus_column = NULL;
11206
11207   if (tree_view->priv->edited_column == column)
11208     {
11209       gtk_tree_view_stop_editing (tree_view, TRUE);
11210
11211       /* no need to, but just to be sure ... */
11212       tree_view->priv->edited_column = NULL;
11213     }
11214
11215   g_signal_handlers_disconnect_by_func (column,
11216                                         G_CALLBACK (column_sizing_notify),
11217                                         tree_view);
11218
11219   _gtk_tree_view_column_unset_tree_view (column);
11220
11221   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11222   tree_view->priv->n_columns--;
11223
11224   if (GTK_WIDGET_REALIZED (tree_view))
11225     {
11226       GList *list;
11227
11228       _gtk_tree_view_column_unrealize_button (column);
11229       for (list = tree_view->priv->columns; list; list = list->next)
11230         {
11231           GtkTreeViewColumn *tmp_column;
11232
11233           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11234           if (tmp_column->visible)
11235             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11236         }
11237
11238       if (tree_view->priv->n_columns == 0 &&
11239           gtk_tree_view_get_headers_visible (tree_view))
11240         gdk_window_hide (tree_view->priv->header_window);
11241
11242       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11243     }
11244
11245   g_object_unref (column);
11246   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11247
11248   return tree_view->priv->n_columns;
11249 }
11250
11251 /**
11252  * gtk_tree_view_insert_column:
11253  * @tree_view: A #GtkTreeView.
11254  * @column: The #GtkTreeViewColumn to be inserted.
11255  * @position: The position to insert @column in.
11256  *
11257  * This inserts the @column into the @tree_view at @position.  If @position is
11258  * -1, then the column is inserted at the end. If @tree_view has
11259  * "fixed_height" mode enabled, then @column must have its "sizing" property
11260  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11261  *
11262  * Return value: The number of columns in @tree_view after insertion.
11263  **/
11264 gint
11265 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11266                              GtkTreeViewColumn *column,
11267                              gint               position)
11268 {
11269   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11270   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11271   g_return_val_if_fail (column->tree_view == NULL, -1);
11272
11273   if (tree_view->priv->fixed_height_mode)
11274     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11275                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11276
11277   g_object_ref_sink (column);
11278
11279   if (tree_view->priv->n_columns == 0 &&
11280       GTK_WIDGET_REALIZED (tree_view) &&
11281       gtk_tree_view_get_headers_visible (tree_view))
11282     {
11283       gdk_window_show (tree_view->priv->header_window);
11284     }
11285
11286   g_signal_connect (column, "notify::sizing",
11287                     G_CALLBACK (column_sizing_notify), tree_view);
11288
11289   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11290                                             column, position);
11291   tree_view->priv->n_columns++;
11292
11293   _gtk_tree_view_column_set_tree_view (column, tree_view);
11294
11295   if (GTK_WIDGET_REALIZED (tree_view))
11296     {
11297       GList *list;
11298
11299       _gtk_tree_view_column_realize_button (column);
11300
11301       for (list = tree_view->priv->columns; list; list = list->next)
11302         {
11303           column = GTK_TREE_VIEW_COLUMN (list->data);
11304           if (column->visible)
11305             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11306         }
11307       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11308     }
11309
11310   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11311
11312   return tree_view->priv->n_columns;
11313 }
11314
11315 /**
11316  * gtk_tree_view_insert_column_with_attributes:
11317  * @tree_view: A #GtkTreeView
11318  * @position: The position to insert the new column in.
11319  * @title: The title to set the header to.
11320  * @cell: The #GtkCellRenderer.
11321  * @Varargs: A %NULL-terminated list of attributes.
11322  *
11323  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11324  * @position.  If @position is -1, then the newly created column is inserted at
11325  * the end.  The column is initialized with the attributes given. If @tree_view
11326  * has "fixed_height" mode enabled, then the new column will have its sizing
11327  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11328  *
11329  * Return value: The number of columns in @tree_view after insertion.
11330  **/
11331 gint
11332 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11333                                              gint             position,
11334                                              const gchar     *title,
11335                                              GtkCellRenderer *cell,
11336                                              ...)
11337 {
11338   GtkTreeViewColumn *column;
11339   gchar *attribute;
11340   va_list args;
11341   gint column_id;
11342
11343   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11344
11345   column = gtk_tree_view_column_new ();
11346   if (tree_view->priv->fixed_height_mode)
11347     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11348
11349   gtk_tree_view_column_set_title (column, title);
11350   gtk_tree_view_column_pack_start (column, cell, TRUE);
11351
11352   va_start (args, cell);
11353
11354   attribute = va_arg (args, gchar *);
11355
11356   while (attribute != NULL)
11357     {
11358       column_id = va_arg (args, gint);
11359       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11360       attribute = va_arg (args, gchar *);
11361     }
11362
11363   va_end (args);
11364
11365   gtk_tree_view_insert_column (tree_view, column, position);
11366
11367   return tree_view->priv->n_columns;
11368 }
11369
11370 /**
11371  * gtk_tree_view_insert_column_with_data_func:
11372  * @tree_view: a #GtkTreeView
11373  * @position: Position to insert, -1 for append
11374  * @title: column title
11375  * @cell: cell renderer for column
11376  * @func: function to set attributes of cell renderer
11377  * @data: data for @func
11378  * @dnotify: destroy notifier for @data
11379  *
11380  * Convenience function that inserts a new column into the #GtkTreeView
11381  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11382  * attributes (normally using data from the model). See also
11383  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11384  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11385  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11386  *
11387  * Return value: number of columns in the tree view post-insert
11388  **/
11389 gint
11390 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11391                                              gint                       position,
11392                                              const gchar               *title,
11393                                              GtkCellRenderer           *cell,
11394                                              GtkTreeCellDataFunc        func,
11395                                              gpointer                   data,
11396                                              GDestroyNotify             dnotify)
11397 {
11398   GtkTreeViewColumn *column;
11399
11400   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11401
11402   column = gtk_tree_view_column_new ();
11403   if (tree_view->priv->fixed_height_mode)
11404     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11405
11406   gtk_tree_view_column_set_title (column, title);
11407   gtk_tree_view_column_pack_start (column, cell, TRUE);
11408   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11409
11410   gtk_tree_view_insert_column (tree_view, column, position);
11411
11412   return tree_view->priv->n_columns;
11413 }
11414
11415 /**
11416  * gtk_tree_view_get_column:
11417  * @tree_view: A #GtkTreeView.
11418  * @n: The position of the column, counting from 0.
11419  *
11420  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11421  *
11422  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11423  * range of columns.
11424  **/
11425 GtkTreeViewColumn *
11426 gtk_tree_view_get_column (GtkTreeView *tree_view,
11427                           gint         n)
11428 {
11429   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11430
11431   if (n < 0 || n >= tree_view->priv->n_columns)
11432     return NULL;
11433
11434   if (tree_view->priv->columns == NULL)
11435     return NULL;
11436
11437   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11438 }
11439
11440 /**
11441  * gtk_tree_view_get_columns:
11442  * @tree_view: A #GtkTreeView
11443  *
11444  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11445  * The returned list must be freed with g_list_free ().
11446  *
11447  * Return value: A list of #GtkTreeViewColumn s
11448  **/
11449 GList *
11450 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11451 {
11452   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11453
11454   return g_list_copy (tree_view->priv->columns);
11455 }
11456
11457 /**
11458  * gtk_tree_view_move_column_after:
11459  * @tree_view: A #GtkTreeView
11460  * @column: The #GtkTreeViewColumn to be moved.
11461  * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
11462  *
11463  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11464  * @column is placed in the first position.
11465  **/
11466 void
11467 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11468                                  GtkTreeViewColumn *column,
11469                                  GtkTreeViewColumn *base_column)
11470 {
11471   GList *column_list_el, *base_el = NULL;
11472
11473   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11474
11475   column_list_el = g_list_find (tree_view->priv->columns, column);
11476   g_return_if_fail (column_list_el != NULL);
11477
11478   if (base_column)
11479     {
11480       base_el = g_list_find (tree_view->priv->columns, base_column);
11481       g_return_if_fail (base_el != NULL);
11482     }
11483
11484   if (column_list_el->prev == base_el)
11485     return;
11486
11487   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11488   if (base_el == NULL)
11489     {
11490       column_list_el->prev = NULL;
11491       column_list_el->next = tree_view->priv->columns;
11492       if (column_list_el->next)
11493         column_list_el->next->prev = column_list_el;
11494       tree_view->priv->columns = column_list_el;
11495     }
11496   else
11497     {
11498       column_list_el->prev = base_el;
11499       column_list_el->next = base_el->next;
11500       if (column_list_el->next)
11501         column_list_el->next->prev = column_list_el;
11502       base_el->next = column_list_el;
11503     }
11504
11505   if (GTK_WIDGET_REALIZED (tree_view))
11506     {
11507       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11508       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11509     }
11510
11511   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11512 }
11513
11514 /**
11515  * gtk_tree_view_set_expander_column:
11516  * @tree_view: A #GtkTreeView
11517  * @column: %NULL, or the column to draw the expander arrow at.
11518  *
11519  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11520  * If @column is %NULL, then the expander arrow is always at the first 
11521  * visible column.
11522  *
11523  * If you do not want expander arrow to appear in your tree, set the 
11524  * expander column to a hidden column.
11525  **/
11526 void
11527 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11528                                    GtkTreeViewColumn *column)
11529 {
11530   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11531   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11532
11533   if (tree_view->priv->expander_column != column)
11534     {
11535       GList *list;
11536
11537       if (column)
11538         {
11539           /* Confirm that column is in tree_view */
11540           for (list = tree_view->priv->columns; list; list = list->next)
11541             if (list->data == column)
11542               break;
11543           g_return_if_fail (list != NULL);
11544         }
11545
11546       tree_view->priv->expander_column = column;
11547       g_object_notify (G_OBJECT (tree_view), "expander-column");
11548     }
11549 }
11550
11551 /**
11552  * gtk_tree_view_get_expander_column:
11553  * @tree_view: A #GtkTreeView
11554  *
11555  * Returns the column that is the current expander column.  This
11556  * column has the expander arrow drawn next to it.
11557  *
11558  * Return value: The expander column.
11559  **/
11560 GtkTreeViewColumn *
11561 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11562 {
11563   GList *list;
11564
11565   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11566
11567   for (list = tree_view->priv->columns; list; list = list->next)
11568     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11569       return (GtkTreeViewColumn *) list->data;
11570   return NULL;
11571 }
11572
11573
11574 /**
11575  * gtk_tree_view_set_column_drag_function:
11576  * @tree_view: A #GtkTreeView.
11577  * @func: A function to determine which columns are reorderable, or %NULL.
11578  * @user_data: User data to be passed to @func, or %NULL
11579  * @destroy: Destroy notifier for @user_data, or %NULL
11580  *
11581  * Sets a user function for determining where a column may be dropped when
11582  * dragged.  This function is called on every column pair in turn at the
11583  * beginning of a column drag to determine where a drop can take place.  The
11584  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11585  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11586  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11587  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11588  * @tree_view reverts to the default behavior of allowing all columns to be
11589  * dropped everywhere.
11590  **/
11591 void
11592 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11593                                         GtkTreeViewColumnDropFunc  func,
11594                                         gpointer                   user_data,
11595                                         GDestroyNotify             destroy)
11596 {
11597   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11598
11599   if (tree_view->priv->column_drop_func_data_destroy)
11600     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11601
11602   tree_view->priv->column_drop_func = func;
11603   tree_view->priv->column_drop_func_data = user_data;
11604   tree_view->priv->column_drop_func_data_destroy = destroy;
11605 }
11606
11607 /**
11608  * gtk_tree_view_scroll_to_point:
11609  * @tree_view: a #GtkTreeView
11610  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11611  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11612  *
11613  * Scrolls the tree view such that the top-left corner of the visible
11614  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11615  * in tree coordinates.  The @tree_view must be realized before
11616  * this function is called.  If it isn't, you probably want to be
11617  * using gtk_tree_view_scroll_to_cell().
11618  *
11619  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11620  **/
11621 void
11622 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11623                                gint         tree_x,
11624                                gint         tree_y)
11625 {
11626   GtkAdjustment *hadj;
11627   GtkAdjustment *vadj;
11628
11629   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11630   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
11631
11632   hadj = tree_view->priv->hadjustment;
11633   vadj = tree_view->priv->vadjustment;
11634
11635   if (tree_x != -1)
11636     gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
11637   if (tree_y != -1)
11638     gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
11639 }
11640
11641 /**
11642  * gtk_tree_view_scroll_to_cell:
11643  * @tree_view: A #GtkTreeView.
11644  * @path: The path of the row to move to, or %NULL.
11645  * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
11646  * @use_align: whether to use alignment arguments, or %FALSE.
11647  * @row_align: The vertical alignment of the row specified by @path.
11648  * @col_align: The horizontal alignment of the column specified by @column.
11649  *
11650  * Moves the alignments of @tree_view to the position specified by @column and
11651  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11652  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11653  * or @path need to be non-%NULL.  @row_align determines where the row is
11654  * placed, and @col_align determines where @column is placed.  Both are expected
11655  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11656  * right/bottom alignment, 0.5 means center.
11657  *
11658  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11659  * tree does the minimum amount of work to scroll the cell onto the screen.
11660  * This means that the cell will be scrolled to the edge closest to its current
11661  * position.  If the cell is currently visible on the screen, nothing is done.
11662  *
11663  * This function only works if the model is set, and @path is a valid row on the
11664  * model.  If the model changes before the @tree_view is realized, the centered
11665  * path will be modified to reflect this change.
11666  **/
11667 void
11668 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11669                               GtkTreePath       *path,
11670                               GtkTreeViewColumn *column,
11671                               gboolean           use_align,
11672                               gfloat             row_align,
11673                               gfloat             col_align)
11674 {
11675   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11676   g_return_if_fail (tree_view->priv->model != NULL);
11677   g_return_if_fail (tree_view->priv->tree != NULL);
11678   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11679   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11680   g_return_if_fail (path != NULL || column != NULL);
11681
11682 #if 0
11683   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11684            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11685 #endif
11686   row_align = CLAMP (row_align, 0.0, 1.0);
11687   col_align = CLAMP (col_align, 0.0, 1.0);
11688
11689
11690   /* Note: Despite the benefits that come from having one code path for the
11691    * scrolling code, we short-circuit validate_visible_area's immplementation as
11692    * it is much slower than just going to the point.
11693    */
11694   if (! GTK_WIDGET_VISIBLE (tree_view) ||
11695       ! GTK_WIDGET_REALIZED (tree_view) ||
11696       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11697       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11698     {
11699       if (tree_view->priv->scroll_to_path)
11700         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11701
11702       tree_view->priv->scroll_to_path = NULL;
11703       tree_view->priv->scroll_to_column = NULL;
11704
11705       if (path)
11706         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11707       if (column)
11708         tree_view->priv->scroll_to_column = column;
11709       tree_view->priv->scroll_to_use_align = use_align;
11710       tree_view->priv->scroll_to_row_align = row_align;
11711       tree_view->priv->scroll_to_col_align = col_align;
11712
11713       install_presize_handler (tree_view);
11714     }
11715   else
11716     {
11717       GdkRectangle cell_rect;
11718       GdkRectangle vis_rect;
11719       gint dest_x, dest_y;
11720
11721       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11722       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11723
11724       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11725
11726       dest_x = vis_rect.x;
11727       dest_y = vis_rect.y;
11728
11729       if (column)
11730         {
11731           if (use_align)
11732             {
11733               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11734             }
11735           else
11736             {
11737               if (cell_rect.x < vis_rect.x)
11738                 dest_x = cell_rect.x;
11739               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11740                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11741             }
11742         }
11743
11744       if (path)
11745         {
11746           if (use_align)
11747             {
11748               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11749               dest_y = MAX (dest_y, 0);
11750             }
11751           else
11752             {
11753               if (cell_rect.y < vis_rect.y)
11754                 dest_y = cell_rect.y;
11755               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11756                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11757             }
11758         }
11759
11760       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11761     }
11762 }
11763
11764 /**
11765  * gtk_tree_view_row_activated:
11766  * @tree_view: A #GtkTreeView
11767  * @path: The #GtkTreePath to be activated.
11768  * @column: The #GtkTreeViewColumn to be activated.
11769  *
11770  * Activates the cell determined by @path and @column.
11771  **/
11772 void
11773 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11774                              GtkTreePath       *path,
11775                              GtkTreeViewColumn *column)
11776 {
11777   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11778
11779   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11780 }
11781
11782
11783 static void
11784 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11785                                           GtkRBNode *node,
11786                                           gpointer   data)
11787 {
11788   GtkTreeView *tree_view = data;
11789
11790   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11791       node->children)
11792     {
11793       GtkTreePath *path;
11794       GtkTreeIter iter;
11795
11796       path = _gtk_tree_view_find_path (tree_view, tree, node);
11797       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11798
11799       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11800
11801       gtk_tree_path_free (path);
11802     }
11803
11804   if (node->children)
11805     _gtk_rbtree_traverse (node->children,
11806                           node->children->root,
11807                           G_PRE_ORDER,
11808                           gtk_tree_view_expand_all_emission_helper,
11809                           tree_view);
11810 }
11811
11812 /**
11813  * gtk_tree_view_expand_all:
11814  * @tree_view: A #GtkTreeView.
11815  *
11816  * Recursively expands all nodes in the @tree_view.
11817  **/
11818 void
11819 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11820 {
11821   GtkTreePath *path;
11822   GtkRBTree *tree;
11823   GtkRBNode *node;
11824
11825   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11826
11827   if (tree_view->priv->tree == NULL)
11828     return;
11829
11830   path = gtk_tree_path_new_first ();
11831   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11832
11833   while (node)
11834     {
11835       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11836       node = _gtk_rbtree_next (tree, node);
11837       gtk_tree_path_next (path);
11838   }
11839
11840   gtk_tree_path_free (path);
11841 }
11842
11843 /* Timeout to animate the expander during expands and collapses */
11844 static gboolean
11845 expand_collapse_timeout (gpointer data)
11846 {
11847   return do_expand_collapse (data);
11848 }
11849
11850 static void
11851 add_expand_collapse_timeout (GtkTreeView *tree_view,
11852                              GtkRBTree   *tree,
11853                              GtkRBNode   *node,
11854                              gboolean     expand)
11855 {
11856   if (tree_view->priv->expand_collapse_timeout != 0)
11857     return;
11858
11859   tree_view->priv->expand_collapse_timeout =
11860       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11861   tree_view->priv->expanded_collapsed_tree = tree;
11862   tree_view->priv->expanded_collapsed_node = node;
11863
11864   if (expand)
11865     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11866   else
11867     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11868 }
11869
11870 static void
11871 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11872 {
11873   if (tree_view->priv->expand_collapse_timeout)
11874     {
11875       g_source_remove (tree_view->priv->expand_collapse_timeout);
11876       tree_view->priv->expand_collapse_timeout = 0;
11877     }
11878
11879   if (tree_view->priv->expanded_collapsed_node != NULL)
11880     {
11881       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11882       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11883
11884       tree_view->priv->expanded_collapsed_node = NULL;
11885     }
11886 }
11887
11888 static void
11889 cancel_arrow_animation (GtkTreeView *tree_view)
11890 {
11891   if (tree_view->priv->expand_collapse_timeout)
11892     {
11893       while (do_expand_collapse (tree_view));
11894
11895       remove_expand_collapse_timeout (tree_view);
11896     }
11897 }
11898
11899 static gboolean
11900 do_expand_collapse (GtkTreeView *tree_view)
11901 {
11902   GtkRBNode *node;
11903   GtkRBTree *tree;
11904   gboolean expanding;
11905   gboolean redraw;
11906
11907   redraw = FALSE;
11908   expanding = TRUE;
11909
11910   node = tree_view->priv->expanded_collapsed_node;
11911   tree = tree_view->priv->expanded_collapsed_tree;
11912
11913   if (node->children == NULL)
11914     expanding = FALSE;
11915
11916   if (expanding)
11917     {
11918       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11919         {
11920           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11921           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11922
11923           redraw = TRUE;
11924
11925         }
11926       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11927         {
11928           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11929
11930           redraw = TRUE;
11931         }
11932     }
11933   else
11934     {
11935       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11936         {
11937           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11938           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11939
11940           redraw = TRUE;
11941         }
11942       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11943         {
11944           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11945
11946           redraw = TRUE;
11947
11948         }
11949     }
11950
11951   if (redraw)
11952     {
11953       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
11954
11955       return TRUE;
11956     }
11957
11958   return FALSE;
11959 }
11960
11961 /**
11962  * gtk_tree_view_collapse_all:
11963  * @tree_view: A #GtkTreeView.
11964  *
11965  * Recursively collapses all visible, expanded nodes in @tree_view.
11966  **/
11967 void
11968 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11969 {
11970   GtkRBTree *tree;
11971   GtkRBNode *node;
11972   GtkTreePath *path;
11973   gint *indices;
11974
11975   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11976
11977   if (tree_view->priv->tree == NULL)
11978     return;
11979
11980   path = gtk_tree_path_new ();
11981   gtk_tree_path_down (path);
11982   indices = gtk_tree_path_get_indices (path);
11983
11984   tree = tree_view->priv->tree;
11985   node = tree->root;
11986   while (node && node->left != tree->nil)
11987     node = node->left;
11988
11989   while (node)
11990     {
11991       if (node->children)
11992         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
11993       indices[0]++;
11994       node = _gtk_rbtree_next (tree, node);
11995     }
11996
11997   gtk_tree_path_free (path);
11998 }
11999
12000 /**
12001  * gtk_tree_view_expand_to_path:
12002  * @tree_view: A #GtkTreeView.
12003  * @path: path to a row.
12004  *
12005  * Expands the row at @path. This will also expand all parent rows of
12006  * @path as necessary.
12007  *
12008  * Since: 2.2
12009  **/
12010 void
12011 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12012                               GtkTreePath *path)
12013 {
12014   gint i, depth;
12015   gint *indices;
12016   GtkTreePath *tmp;
12017
12018   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12019   g_return_if_fail (path != NULL);
12020
12021   depth = gtk_tree_path_get_depth (path);
12022   indices = gtk_tree_path_get_indices (path);
12023
12024   tmp = gtk_tree_path_new ();
12025   g_return_if_fail (tmp != NULL);
12026
12027   for (i = 0; i < depth; i++)
12028     {
12029       gtk_tree_path_append_index (tmp, indices[i]);
12030       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12031     }
12032
12033   gtk_tree_path_free (tmp);
12034 }
12035
12036 /* FIXME the bool return values for expand_row and collapse_row are
12037  * not analagous; they should be TRUE if the row had children and
12038  * was not already in the requested state.
12039  */
12040
12041
12042 static gboolean
12043 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12044                                GtkTreePath *path,
12045                                GtkRBTree   *tree,
12046                                GtkRBNode   *node,
12047                                gboolean     open_all,
12048                                gboolean     animate)
12049 {
12050   GtkTreeIter iter;
12051   GtkTreeIter temp;
12052   gboolean expand;
12053
12054   if (animate)
12055     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12056                   "gtk-enable-animations", &animate,
12057                   NULL);
12058
12059   remove_auto_expand_timeout (tree_view);
12060
12061   if (node->children && !open_all)
12062     return FALSE;
12063
12064   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12065     return FALSE;
12066
12067   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12068   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12069     return FALSE;
12070
12071
12072    if (node->children && open_all)
12073     {
12074       gboolean retval = FALSE;
12075       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12076
12077       gtk_tree_path_append_index (tmp_path, 0);
12078       tree = node->children;
12079       node = tree->root;
12080       while (node->left != tree->nil)
12081         node = node->left;
12082       /* try to expand the children */
12083       do
12084         {
12085          gboolean t;
12086          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12087                                             TRUE, animate);
12088          if (t)
12089            retval = TRUE;
12090
12091          gtk_tree_path_next (tmp_path);
12092          node = _gtk_rbtree_next (tree, node);
12093        }
12094       while (node != NULL);
12095
12096       gtk_tree_path_free (tmp_path);
12097
12098       return retval;
12099     }
12100
12101   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12102
12103   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12104     return FALSE;
12105
12106   if (expand)
12107     return FALSE;
12108
12109   node->children = _gtk_rbtree_new ();
12110   node->children->parent_tree = tree;
12111   node->children->parent_node = node;
12112
12113   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12114
12115   gtk_tree_view_build_tree (tree_view,
12116                             node->children,
12117                             &temp,
12118                             gtk_tree_path_get_depth (path) + 1,
12119                             open_all);
12120
12121   remove_expand_collapse_timeout (tree_view);
12122
12123   if (animate)
12124     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12125
12126   install_presize_handler (tree_view);
12127
12128   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12129   if (open_all && node->children)
12130     {
12131       _gtk_rbtree_traverse (node->children,
12132                             node->children->root,
12133                             G_PRE_ORDER,
12134                             gtk_tree_view_expand_all_emission_helper,
12135                             tree_view);
12136     }
12137   return TRUE;
12138 }
12139
12140
12141 /**
12142  * gtk_tree_view_expand_row:
12143  * @tree_view: a #GtkTreeView
12144  * @path: path to a row
12145  * @open_all: whether to recursively expand, or just expand immediate children
12146  *
12147  * Opens the row so its children are visible.
12148  *
12149  * Return value: %TRUE if the row existed and had children
12150  **/
12151 gboolean
12152 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12153                           GtkTreePath *path,
12154                           gboolean     open_all)
12155 {
12156   GtkRBTree *tree;
12157   GtkRBNode *node;
12158
12159   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12160   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12161   g_return_val_if_fail (path != NULL, FALSE);
12162
12163   if (_gtk_tree_view_find_node (tree_view,
12164                                 path,
12165                                 &tree,
12166                                 &node))
12167     return FALSE;
12168
12169   if (tree != NULL)
12170     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12171   else
12172     return FALSE;
12173 }
12174
12175 static gboolean
12176 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12177                                  GtkTreePath *path,
12178                                  GtkRBTree   *tree,
12179                                  GtkRBNode   *node,
12180                                  gboolean     animate)
12181 {
12182   GtkTreeIter iter;
12183   GtkTreeIter children;
12184   gboolean collapse;
12185   gint x, y;
12186   GList *list;
12187   GdkWindow *child, *parent;
12188
12189   if (animate)
12190     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12191                   "gtk-enable-animations", &animate,
12192                   NULL);
12193
12194   remove_auto_expand_timeout (tree_view);
12195
12196   if (node->children == NULL)
12197     return FALSE;
12198
12199   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12200
12201   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12202
12203   if (collapse)
12204     return FALSE;
12205
12206   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12207    * a chance to prelight the correct node below */
12208
12209   if (tree_view->priv->prelight_tree)
12210     {
12211       GtkRBTree *parent_tree;
12212       GtkRBNode *parent_node;
12213
12214       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12215       parent_node = tree_view->priv->prelight_tree->parent_node;
12216       while (parent_tree)
12217         {
12218           if (parent_tree == tree && parent_node == node)
12219             {
12220               ensure_unprelighted (tree_view);
12221               break;
12222             }
12223           parent_node = parent_tree->parent_node;
12224           parent_tree = parent_tree->parent_tree;
12225         }
12226     }
12227
12228   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12229
12230   for (list = tree_view->priv->columns; list; list = list->next)
12231     {
12232       GtkTreeViewColumn *column = list->data;
12233
12234       if (column->visible == FALSE)
12235         continue;
12236       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12237         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12238     }
12239
12240   if (tree_view->priv->destroy_count_func)
12241     {
12242       GtkTreePath *child_path;
12243       gint child_count = 0;
12244       child_path = gtk_tree_path_copy (path);
12245       gtk_tree_path_down (child_path);
12246       if (node->children)
12247         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12248       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12249       gtk_tree_path_free (child_path);
12250     }
12251
12252   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12253     {
12254       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12255
12256       if (gtk_tree_path_is_ancestor (path, cursor_path))
12257         {
12258           gtk_tree_row_reference_free (tree_view->priv->cursor);
12259           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12260                                                                       tree_view->priv->model,
12261                                                                       path);
12262         }
12263       gtk_tree_path_free (cursor_path);
12264     }
12265
12266   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12267     {
12268       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12269       if (gtk_tree_path_is_ancestor (path, anchor_path))
12270         {
12271           gtk_tree_row_reference_free (tree_view->priv->anchor);
12272           tree_view->priv->anchor = NULL;
12273         }
12274       gtk_tree_path_free (anchor_path);
12275     }
12276
12277   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press))
12278     {
12279       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
12280       if (gtk_tree_path_is_ancestor (path, lsc))
12281         {
12282           gtk_tree_row_reference_free (tree_view->priv->last_button_press);
12283           tree_view->priv->last_button_press = NULL;
12284         }
12285       gtk_tree_path_free (lsc);
12286     }
12287
12288   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press_2))
12289     {
12290       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press_2);
12291       if (gtk_tree_path_is_ancestor (path, lsc))
12292         {
12293           gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
12294           tree_view->priv->last_button_press_2 = NULL;
12295         }
12296       gtk_tree_path_free (lsc);
12297     }
12298
12299   remove_expand_collapse_timeout (tree_view);
12300
12301   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12302     {
12303       _gtk_rbtree_remove (node->children);
12304       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12305     }
12306   else
12307     _gtk_rbtree_remove (node->children);
12308   
12309   if (animate)
12310     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12311   
12312   if (GTK_WIDGET_MAPPED (tree_view))
12313     {
12314       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12315     }
12316
12317   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12318
12319   if (GTK_WIDGET_MAPPED (tree_view))
12320     {
12321       /* now that we've collapsed all rows, we want to try to set the prelight
12322        * again. To do this, we fake a motion event and send it to ourselves. */
12323
12324       child = tree_view->priv->bin_window;
12325       parent = gdk_window_get_parent (child);
12326
12327       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12328         {
12329           GdkEventMotion event;
12330           gint child_x, child_y;
12331
12332           gdk_window_get_position (child, &child_x, &child_y);
12333
12334           event.window = tree_view->priv->bin_window;
12335           event.x = x - child_x;
12336           event.y = y - child_y;
12337
12338           /* despite the fact this isn't a real event, I'm almost positive it will
12339            * never trigger a drag event.  maybe_drag is the only function that uses
12340            * more than just event.x and event.y. */
12341           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12342         }
12343     }
12344
12345   return TRUE;
12346 }
12347
12348 /**
12349  * gtk_tree_view_collapse_row:
12350  * @tree_view: a #GtkTreeView
12351  * @path: path to a row in the @tree_view
12352  *
12353  * Collapses a row (hides its child rows, if they exist).
12354  *
12355  * Return value: %TRUE if the row was collapsed.
12356  **/
12357 gboolean
12358 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12359                             GtkTreePath *path)
12360 {
12361   GtkRBTree *tree;
12362   GtkRBNode *node;
12363
12364   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12365   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12366   g_return_val_if_fail (path != NULL, FALSE);
12367
12368   if (_gtk_tree_view_find_node (tree_view,
12369                                 path,
12370                                 &tree,
12371                                 &node))
12372     return FALSE;
12373
12374   if (tree == NULL || node->children == NULL)
12375     return FALSE;
12376
12377   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12378 }
12379
12380 static void
12381 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12382                                         GtkRBTree              *tree,
12383                                         GtkTreePath            *path,
12384                                         GtkTreeViewMappingFunc  func,
12385                                         gpointer                user_data)
12386 {
12387   GtkRBNode *node;
12388
12389   if (tree == NULL || tree->root == NULL)
12390     return;
12391
12392   node = tree->root;
12393
12394   while (node && node->left != tree->nil)
12395     node = node->left;
12396
12397   while (node)
12398     {
12399       if (node->children)
12400         {
12401           (* func) (tree_view, path, user_data);
12402           gtk_tree_path_down (path);
12403           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12404           gtk_tree_path_up (path);
12405         }
12406       gtk_tree_path_next (path);
12407       node = _gtk_rbtree_next (tree, node);
12408     }
12409 }
12410
12411 /**
12412  * gtk_tree_view_map_expanded_rows:
12413  * @tree_view: A #GtkTreeView
12414  * @func: A function to be called
12415  * @data: User data to be passed to the function.
12416  *
12417  * Calls @func on all expanded rows.
12418  **/
12419 void
12420 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12421                                  GtkTreeViewMappingFunc  func,
12422                                  gpointer                user_data)
12423 {
12424   GtkTreePath *path;
12425
12426   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12427   g_return_if_fail (func != NULL);
12428
12429   path = gtk_tree_path_new_first ();
12430
12431   gtk_tree_view_map_expanded_rows_helper (tree_view,
12432                                           tree_view->priv->tree,
12433                                           path, func, user_data);
12434
12435   gtk_tree_path_free (path);
12436 }
12437
12438 /**
12439  * gtk_tree_view_row_expanded:
12440  * @tree_view: A #GtkTreeView.
12441  * @path: A #GtkTreePath to test expansion state.
12442  *
12443  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12444  *
12445  * Return value: %TRUE if #path is expanded.
12446  **/
12447 gboolean
12448 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12449                             GtkTreePath *path)
12450 {
12451   GtkRBTree *tree;
12452   GtkRBNode *node;
12453
12454   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12455   g_return_val_if_fail (path != NULL, FALSE);
12456
12457   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12458
12459   if (node == NULL)
12460     return FALSE;
12461
12462   return (node->children != NULL);
12463 }
12464
12465 /**
12466  * gtk_tree_view_get_reorderable:
12467  * @tree_view: a #GtkTreeView
12468  *
12469  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12470  * gtk_tree_view_set_reorderable().
12471  *
12472  * Return value: %TRUE if the tree can be reordered.
12473  **/
12474 gboolean
12475 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12476 {
12477   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12478
12479   return tree_view->priv->reorderable;
12480 }
12481
12482 /**
12483  * gtk_tree_view_set_reorderable:
12484  * @tree_view: A #GtkTreeView.
12485  * @reorderable: %TRUE, if the tree can be reordered.
12486  *
12487  * This function is a convenience function to allow you to reorder
12488  * models that support the #GtkDragSourceIface and the
12489  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12490  * these.  If @reorderable is %TRUE, then the user can reorder the
12491  * model by dragging and dropping rows. The developer can listen to
12492  * these changes by connecting to the model's row_inserted and
12493  * row_deleted signals. The reordering is implemented by setting up
12494  * the tree view as a drag source and destination. Therefore, drag and
12495  * drop can not be used in a reorderable view for any other purpose.
12496  *
12497  * This function does not give you any degree of control over the order -- any
12498  * reordering is allowed.  If more control is needed, you should probably
12499  * handle drag and drop manually.
12500  **/
12501 void
12502 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12503                                gboolean     reorderable)
12504 {
12505   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12506
12507   reorderable = reorderable != FALSE;
12508
12509   if (tree_view->priv->reorderable == reorderable)
12510     return;
12511
12512   if (reorderable)
12513     {
12514       const GtkTargetEntry row_targets[] = {
12515         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12516       };
12517
12518       gtk_tree_view_enable_model_drag_source (tree_view,
12519                                               GDK_BUTTON1_MASK,
12520                                               row_targets,
12521                                               G_N_ELEMENTS (row_targets),
12522                                               GDK_ACTION_MOVE);
12523       gtk_tree_view_enable_model_drag_dest (tree_view,
12524                                             row_targets,
12525                                             G_N_ELEMENTS (row_targets),
12526                                             GDK_ACTION_MOVE);
12527     }
12528   else
12529     {
12530       gtk_tree_view_unset_rows_drag_source (tree_view);
12531       gtk_tree_view_unset_rows_drag_dest (tree_view);
12532     }
12533
12534   tree_view->priv->reorderable = reorderable;
12535
12536   g_object_notify (G_OBJECT (tree_view), "reorderable");
12537 }
12538
12539 static void
12540 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12541                                GtkTreePath     *path,
12542                                gboolean         clear_and_select,
12543                                gboolean         clamp_node)
12544 {
12545   GtkRBTree *tree = NULL;
12546   GtkRBNode *node = NULL;
12547
12548   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12549     {
12550       GtkTreePath *cursor_path;
12551       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12552       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12553       gtk_tree_path_free (cursor_path);
12554     }
12555
12556   gtk_tree_row_reference_free (tree_view->priv->cursor);
12557   tree_view->priv->cursor = NULL;
12558
12559   /* One cannot set the cursor on a separator. */
12560   if (!row_is_separator (tree_view, NULL, path))
12561     {
12562       tree_view->priv->cursor =
12563         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12564                                           tree_view->priv->model,
12565                                           path);
12566       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12567     }
12568
12569   if (tree != NULL)
12570     {
12571       GtkRBTree *new_tree = NULL;
12572       GtkRBNode *new_node = NULL;
12573
12574       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12575         {
12576           GtkTreeSelectMode mode = 0;
12577
12578           if (tree_view->priv->ctrl_pressed)
12579             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12580           if (tree_view->priv->shift_pressed)
12581             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12582
12583           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12584                                                     node, tree, path, mode,
12585                                                     FALSE);
12586         }
12587
12588       /* We have to re-find tree and node here again, somebody might have
12589        * cleared the node or the whole tree in the GtkTreeSelection::changed
12590        * callback. If the nodes differ we bail out here.
12591        */
12592       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12593
12594       if (tree != new_tree || node != new_node)
12595         return;
12596
12597       if (clamp_node)
12598         {
12599           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12600           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12601         }
12602     }
12603
12604   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12605 }
12606
12607 /**
12608  * gtk_tree_view_get_cursor:
12609  * @tree_view: A #GtkTreeView
12610  * @path: A pointer to be filled with the current cursor path, or %NULL
12611  * @focus_column: A pointer to be filled with the current focus column, or %NULL
12612  *
12613  * Fills in @path and @focus_column with the current path and focus column.  If
12614  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12615  * currently has focus, then *@focus_column will be %NULL.
12616  *
12617  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12618  * you are done with it.
12619  **/
12620 void
12621 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12622                           GtkTreePath       **path,
12623                           GtkTreeViewColumn **focus_column)
12624 {
12625   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12626
12627   if (path)
12628     {
12629       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12630         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12631       else
12632         *path = NULL;
12633     }
12634
12635   if (focus_column)
12636     {
12637       *focus_column = tree_view->priv->focus_column;
12638     }
12639 }
12640
12641 /**
12642  * gtk_tree_view_set_cursor:
12643  * @tree_view: A #GtkTreeView
12644  * @path: A #GtkTreePath
12645  * @focus_column: A #GtkTreeViewColumn, or %NULL
12646  * @start_editing: %TRUE if the specified cell should start being edited.
12647  *
12648  * Sets the current keyboard focus to be at @path, and selects it.  This is
12649  * useful when you want to focus the user's attention on a particular row.  If
12650  * @focus_column is not %NULL, then focus is given to the column specified by 
12651  * it. Additionally, if @focus_column is specified, and @start_editing is 
12652  * %TRUE, then editing should be started in the specified cell.  
12653  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12654  * in order to give keyboard focus to the widget.  Please note that editing 
12655  * can only happen when the widget is realized.
12656  **/
12657 void
12658 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12659                           GtkTreePath       *path,
12660                           GtkTreeViewColumn *focus_column,
12661                           gboolean           start_editing)
12662 {
12663   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12664                                     NULL, start_editing);
12665 }
12666
12667 /**
12668  * gtk_tree_view_set_cursor_on_cell:
12669  * @tree_view: A #GtkTreeView
12670  * @path: A #GtkTreePath
12671  * @focus_column: A #GtkTreeViewColumn, or %NULL
12672  * @focus_cell: A #GtkCellRenderer, or %NULL
12673  * @start_editing: %TRUE if the specified cell should start being edited.
12674  *
12675  * Sets the current keyboard focus to be at @path, and selects it.  This is
12676  * useful when you want to focus the user's attention on a particular row.  If
12677  * @focus_column is not %NULL, then focus is given to the column specified by
12678  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12679  * contains 2 or more editable or activatable cells, then focus is given to
12680  * the cell specified by @focus_cell. Additionally, if @focus_column is
12681  * specified, and @start_editing is %TRUE, then editing should be started in
12682  * the specified cell.  This function is often followed by
12683  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12684  * widget.  Please note that editing can only happen when the widget is
12685  * realized.
12686  *
12687  * Since: 2.2
12688  **/
12689 void
12690 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12691                                   GtkTreePath       *path,
12692                                   GtkTreeViewColumn *focus_column,
12693                                   GtkCellRenderer   *focus_cell,
12694                                   gboolean           start_editing)
12695 {
12696   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12697   g_return_if_fail (tree_view->priv->tree != NULL);
12698   g_return_if_fail (path != NULL);
12699   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12700   if (focus_cell)
12701     {
12702       g_return_if_fail (focus_column);
12703       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12704     }
12705
12706   /* cancel the current editing, if it exists */
12707   if (tree_view->priv->edited_column &&
12708       tree_view->priv->edited_column->editable_widget)
12709     gtk_tree_view_stop_editing (tree_view, TRUE);
12710
12711   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12712
12713   if (focus_column && focus_column->visible)
12714     {
12715       GList *list;
12716       gboolean column_in_tree = FALSE;
12717
12718       for (list = tree_view->priv->columns; list; list = list->next)
12719         if (list->data == focus_column)
12720           {
12721             column_in_tree = TRUE;
12722             break;
12723           }
12724       g_return_if_fail (column_in_tree);
12725       tree_view->priv->focus_column = focus_column;
12726       if (focus_cell)
12727         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12728       if (start_editing)
12729         gtk_tree_view_start_editing (tree_view, path);
12730     }
12731 }
12732
12733 /**
12734  * gtk_tree_view_get_bin_window:
12735  * @tree_view: A #GtkTreeView
12736  * 
12737  * Returns the window that @tree_view renders to.  This is used primarily to
12738  * compare to <literal>event->window</literal> to confirm that the event on
12739  * @tree_view is on the right window.
12740  * 
12741  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12742  **/
12743 GdkWindow *
12744 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12745 {
12746   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12747
12748   return tree_view->priv->bin_window;
12749 }
12750
12751 /**
12752  * gtk_tree_view_get_path_at_pos:
12753  * @tree_view: A #GtkTreeView.
12754  * @x: The x position to be identified (relative to bin_window).
12755  * @y: The y position to be identified (relative to bin_window).
12756  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12757  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12758  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
12759  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12760  *
12761  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12762  * (please see gtk_tree_view_get_bin_window()).
12763  * That is, @x and @y are relative to an events coordinates. @x and @y must
12764  * come from an event on the @tree_view only where <literal>event->window ==
12765  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12766  * things like popup menus. If @path is non-%NULL, then it will be filled
12767  * with the #GtkTreePath at that point.  This path should be freed with
12768  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12769  * with the column at that point.  @cell_x and @cell_y return the coordinates
12770  * relative to the cell background (i.e. the @background_area passed to
12771  * gtk_cell_renderer_render()).  This function is only meaningful if
12772  * @tree_view is realized.
12773  *
12774  * For converting widget coordinates (eg. the ones you get from
12775  * GtkWidget::query-tooltip), please see
12776  * gtk_tree_view_convert_widget_to_bin_window_coords().
12777  *
12778  * Return value: %TRUE if a row exists at that coordinate.
12779  **/
12780 gboolean
12781 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12782                                gint                x,
12783                                gint                y,
12784                                GtkTreePath       **path,
12785                                GtkTreeViewColumn **column,
12786                                gint               *cell_x,
12787                                gint               *cell_y)
12788 {
12789   GtkRBTree *tree;
12790   GtkRBNode *node;
12791   gint y_offset;
12792
12793   g_return_val_if_fail (tree_view != NULL, FALSE);
12794   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
12795
12796   if (path)
12797     *path = NULL;
12798   if (column)
12799     *column = NULL;
12800
12801   if (tree_view->priv->tree == NULL)
12802     return FALSE;
12803
12804   if (x > tree_view->priv->hadjustment->upper)
12805     return FALSE;
12806
12807   if (x < 0 || y < 0)
12808     return FALSE;
12809
12810   if (column || cell_x)
12811     {
12812       GtkTreeViewColumn *tmp_column;
12813       GtkTreeViewColumn *last_column = NULL;
12814       GList *list;
12815       gint remaining_x = x;
12816       gboolean found = FALSE;
12817       gboolean rtl;
12818
12819       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12820       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12821            list;
12822            list = (rtl ? list->prev : list->next))
12823         {
12824           tmp_column = list->data;
12825
12826           if (tmp_column->visible == FALSE)
12827             continue;
12828
12829           last_column = tmp_column;
12830           if (remaining_x <= tmp_column->width)
12831             {
12832               found = TRUE;
12833
12834               if (column)
12835                 *column = tmp_column;
12836
12837               if (cell_x)
12838                 *cell_x = remaining_x;
12839
12840               break;
12841             }
12842           remaining_x -= tmp_column->width;
12843         }
12844
12845       /* If found is FALSE and there is a last_column, then it the remainder
12846        * space is in that area
12847        */
12848       if (!found)
12849         {
12850           if (last_column)
12851             {
12852               if (column)
12853                 *column = last_column;
12854               
12855               if (cell_x)
12856                 *cell_x = last_column->width + remaining_x;
12857             }
12858           else
12859             {
12860               return FALSE;
12861             }
12862         }
12863     }
12864
12865   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12866                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12867                                       &tree, &node);
12868
12869   if (tree == NULL)
12870     return FALSE;
12871
12872   if (cell_y)
12873     *cell_y = y_offset;
12874
12875   if (path)
12876     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12877
12878   return TRUE;
12879 }
12880
12881
12882 /**
12883  * gtk_tree_view_get_cell_area:
12884  * @tree_view: a #GtkTreeView
12885  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12886  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12887  * @rect: rectangle to fill with cell rect
12888  *
12889  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12890  * row specified by @path and the column specified by @column.  If @path is
12891  * %NULL, or points to a path not currently displayed, the @y and @height fields
12892  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12893  * fields will be filled with 0.  The sum of all cell rects does not cover the
12894  * entire tree; there are extra pixels in between rows, for example. The
12895  * returned rectangle is equivalent to the @cell_area passed to
12896  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12897  * realized.
12898  **/
12899 void
12900 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12901                              GtkTreePath        *path,
12902                              GtkTreeViewColumn  *column,
12903                              GdkRectangle       *rect)
12904 {
12905   GtkRBTree *tree = NULL;
12906   GtkRBNode *node = NULL;
12907   gint vertical_separator;
12908   gint horizontal_separator;
12909
12910   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12911   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12912   g_return_if_fail (rect != NULL);
12913   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12914   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
12915
12916   gtk_widget_style_get (GTK_WIDGET (tree_view),
12917                         "vertical-separator", &vertical_separator,
12918                         "horizontal-separator", &horizontal_separator,
12919                         NULL);
12920
12921   rect->x = 0;
12922   rect->y = 0;
12923   rect->width = 0;
12924   rect->height = 0;
12925
12926   if (column)
12927     {
12928       rect->x = column->button->allocation.x + horizontal_separator/2;
12929       rect->width = column->button->allocation.width - horizontal_separator;
12930     }
12931
12932   if (path)
12933     {
12934       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12935
12936       /* Get vertical coords */
12937       if ((!ret && tree == NULL) || ret)
12938         return;
12939
12940       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12941       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12942
12943       if (column &&
12944           gtk_tree_view_is_expander_column (tree_view, column))
12945         {
12946           gint depth = gtk_tree_path_get_depth (path);
12947           gboolean rtl;
12948
12949           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12950
12951           if (!rtl)
12952             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12953           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12954
12955           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12956             {
12957               if (!rtl)
12958                 rect->x += depth * tree_view->priv->expander_size;
12959               rect->width -= depth * tree_view->priv->expander_size;
12960             }
12961
12962           rect->width = MAX (rect->width, 0);
12963         }
12964     }
12965 }
12966
12967 /**
12968  * gtk_tree_view_get_background_area:
12969  * @tree_view: a #GtkTreeView
12970  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12971  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
12972  * @rect: rectangle to fill with cell background rect
12973  *
12974  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12975  * row specified by @path and the column specified by @column.  If @path is
12976  * %NULL, or points to a node not found in the tree, the @y and @height fields of
12977  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12978  * fields will be filled with 0.  The returned rectangle is equivalent to the
12979  * @background_area passed to gtk_cell_renderer_render().  These background
12980  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
12981  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
12982  * itself, excluding surrounding borders and the tree expander area.
12983  *
12984  **/
12985 void
12986 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
12987                                    GtkTreePath        *path,
12988                                    GtkTreeViewColumn  *column,
12989                                    GdkRectangle       *rect)
12990 {
12991   GtkRBTree *tree = NULL;
12992   GtkRBNode *node = NULL;
12993
12994   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12995   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12996   g_return_if_fail (rect != NULL);
12997
12998   rect->x = 0;
12999   rect->y = 0;
13000   rect->width = 0;
13001   rect->height = 0;
13002
13003   if (path)
13004     {
13005       /* Get vertical coords */
13006
13007       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13008           tree == NULL)
13009         return;
13010
13011       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13012
13013       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13014     }
13015
13016   if (column)
13017     {
13018       gint x2 = 0;
13019
13020       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13021       rect->width = x2 - rect->x;
13022     }
13023 }
13024
13025 /**
13026  * gtk_tree_view_get_visible_rect:
13027  * @tree_view: a #GtkTreeView
13028  * @visible_rect: rectangle to fill
13029  *
13030  * Fills @visible_rect with the currently-visible region of the
13031  * buffer, in tree coordinates. Convert to bin_window coordinates with
13032  * gtk_tree_view_convert_tree_to_bin_window_coords().
13033  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13034  * scrollable area of the tree.
13035  **/
13036 void
13037 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13038                                 GdkRectangle *visible_rect)
13039 {
13040   GtkWidget *widget;
13041
13042   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13043
13044   widget = GTK_WIDGET (tree_view);
13045
13046   if (visible_rect)
13047     {
13048       visible_rect->x = tree_view->priv->hadjustment->value;
13049       visible_rect->y = tree_view->priv->vadjustment->value;
13050       visible_rect->width = widget->allocation.width;
13051       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13052     }
13053 }
13054
13055 /**
13056  * gtk_tree_view_widget_to_tree_coords:
13057  * @tree_view: a #GtkTreeView
13058  * @wx: X coordinate relative to bin_window
13059  * @wy: Y coordinate relative to bin_window
13060  * @tx: return location for tree X coordinate
13061  * @ty: return location for tree Y coordinate
13062  *
13063  * Converts bin_window coordinates to coordinates for the
13064  * tree (the full scrollable area of the tree).
13065  *
13066  * Deprecated: 2.12: Due to historial reasons the name of this function is
13067  * incorrect.  For converting coordinates relative to the widget to
13068  * bin_window coordinates, please see
13069  * gtk_tree_view_convert_widget_to_bin_window_coords().
13070  *
13071  **/
13072 void
13073 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
13074                                       gint         wx,
13075                                       gint         wy,
13076                                       gint        *tx,
13077                                       gint        *ty)
13078 {
13079   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13080
13081   if (tx)
13082     *tx = wx + tree_view->priv->hadjustment->value;
13083   if (ty)
13084     *ty = wy + tree_view->priv->dy;
13085 }
13086
13087 /**
13088  * gtk_tree_view_tree_to_widget_coords:
13089  * @tree_view: a #GtkTreeView
13090  * @tx: tree X coordinate
13091  * @ty: tree Y coordinate
13092  * @wx: return location for X coordinate relative to bin_window
13093  * @wy: return location for Y coordinate relative to bin_window
13094  *
13095  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13096  * to bin_window coordinates.
13097  *
13098  * Deprecated: 2.12: Due to historial reasons the name of this function is
13099  * incorrect.  For converting bin_window coordinates to coordinates relative
13100  * to bin_window, please see
13101  * gtk_tree_view_convert_bin_window_to_widget_coords().
13102  *
13103  **/
13104 void
13105 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
13106                                      gint         tx,
13107                                      gint         ty,
13108                                      gint        *wx,
13109                                      gint        *wy)
13110 {
13111   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13112
13113   if (wx)
13114     *wx = tx - tree_view->priv->hadjustment->value;
13115   if (wy)
13116     *wy = ty - tree_view->priv->dy;
13117 }
13118
13119
13120 /**
13121  * gtk_tree_view_convert_widget_to_tree_coords:
13122  * @tree_view: a #GtkTreeView
13123  * @wx: X coordinate relative to the widget
13124  * @wy: Y coordinate relative to the widget
13125  * @tx: return location for tree X coordinate
13126  * @ty: return location for tree Y coordinate
13127  *
13128  * Converts widget coordinates to coordinates for the
13129  * tree (the full scrollable area of the tree).
13130  *
13131  * Since: 2.12
13132  **/
13133 void
13134 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13135                                              gint         wx,
13136                                              gint         wy,
13137                                              gint        *tx,
13138                                              gint        *ty)
13139 {
13140   gint x, y;
13141
13142   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13143
13144   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13145                                                      wx, wy,
13146                                                      &x, &y);
13147   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13148                                                    x, y,
13149                                                    tx, ty);
13150 }
13151
13152 /**
13153  * gtk_tree_view_convert_tree_to_widget_coords:
13154  * @tree_view: a #GtkTreeView
13155  * @tx: X coordinate relative to the tree
13156  * @ty: Y coordinate relative to the tree
13157  * @wx: return location for widget X coordinate
13158  * @wy: return location for widget Y coordinate
13159  *
13160  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13161  * to widget coordinates.
13162  *
13163  * Since: 2.12
13164  **/
13165 void
13166 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13167                                              gint         tx,
13168                                              gint         ty,
13169                                              gint        *wx,
13170                                              gint        *wy)
13171 {
13172   gint x, y;
13173
13174   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13175
13176   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13177                                                    tx, ty,
13178                                                    &x, &y);
13179   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13180                                                      x, y,
13181                                                      wx, wy);
13182 }
13183
13184 /**
13185  * gtk_tree_view_convert_widget_to_bin_window_coords:
13186  * @tree_view: a #GtkTreeView
13187  * @wx: X coordinate relative to the widget
13188  * @wy: Y coordinate relative to the widget
13189  * @bx: return location for bin_window X coordinate
13190  * @by: return location for bin_window Y coordinate
13191  *
13192  * Converts widget coordinates to coordinates for the bin_window
13193  * (see gtk_tree_view_get_bin_window()).
13194  *
13195  * Since: 2.12
13196  **/
13197 void
13198 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13199                                                    gint         wx,
13200                                                    gint         wy,
13201                                                    gint        *bx,
13202                                                    gint        *by)
13203 {
13204   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13205
13206   if (bx)
13207     *bx = wx + tree_view->priv->hadjustment->value;
13208   if (by)
13209     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13210 }
13211
13212 /**
13213  * gtk_tree_view_convert_bin_window_to_widget_coords:
13214  * @tree_view: a #GtkTreeView
13215  * @bx: bin_window X coordinate
13216  * @by: bin_window Y coordinate
13217  * @wx: return location for widget X coordinate
13218  * @wy: return location for widget Y coordinate
13219  *
13220  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13221  * to widget relative coordinates.
13222  *
13223  * Since: 2.12
13224  **/
13225 void
13226 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13227                                                    gint         bx,
13228                                                    gint         by,
13229                                                    gint        *wx,
13230                                                    gint        *wy)
13231 {
13232   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13233
13234   if (wx)
13235     *wx = bx - tree_view->priv->hadjustment->value;
13236   if (wy)
13237     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13238 }
13239
13240 /**
13241  * gtk_tree_view_convert_tree_to_bin_window_coords:
13242  * @tree_view: a #GtkTreeView
13243  * @tx: tree X coordinate
13244  * @ty: tree Y coordinate
13245  * @bx: return location for X coordinate relative to bin_window
13246  * @by: return location for Y coordinate relative to bin_window
13247  *
13248  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13249  * to bin_window coordinates.
13250  *
13251  * Since: 2.12
13252  **/
13253 void
13254 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13255                                                  gint         tx,
13256                                                  gint         ty,
13257                                                  gint        *bx,
13258                                                  gint        *by)
13259 {
13260   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13261
13262   if (bx)
13263     *bx = tx;
13264   if (by)
13265     *by = ty - tree_view->priv->dy;
13266 }
13267
13268 /**
13269  * gtk_tree_view_convert_bin_window_to_tree_coords:
13270  * @tree_view: a #GtkTreeView
13271  * @bx: X coordinate relative to bin_window
13272  * @by: Y coordinate relative to bin_window
13273  * @tx: return location for tree X coordinate
13274  * @ty: return location for tree Y coordinate
13275  *
13276  * Converts bin_window coordinates to coordinates for the
13277  * tree (the full scrollable area of the tree).
13278  *
13279  * Since: 2.12
13280  **/
13281 void
13282 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13283                                                  gint         bx,
13284                                                  gint         by,
13285                                                  gint        *tx,
13286                                                  gint        *ty)
13287 {
13288   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13289
13290   if (tx)
13291     *tx = bx;
13292   if (ty)
13293     *ty = by + tree_view->priv->dy;
13294 }
13295
13296
13297
13298 /**
13299  * gtk_tree_view_get_visible_range:
13300  * @tree_view: A #GtkTreeView
13301  * @start_path: Return location for start of region, or %NULL.
13302  * @end_path: Return location for end of region, or %NULL.
13303  *
13304  * Sets @start_path and @end_path to be the first and last visible path.
13305  * Note that there may be invisible paths in between.
13306  *
13307  * The paths should be freed with gtk_tree_path_free() after use.
13308  *
13309  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13310  *
13311  * Since: 2.8
13312  **/
13313 gboolean
13314 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13315                                  GtkTreePath **start_path,
13316                                  GtkTreePath **end_path)
13317 {
13318   GtkRBTree *tree;
13319   GtkRBNode *node;
13320   gboolean retval;
13321   
13322   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13323
13324   if (!tree_view->priv->tree)
13325     return FALSE;
13326
13327   retval = TRUE;
13328
13329   if (start_path)
13330     {
13331       _gtk_rbtree_find_offset (tree_view->priv->tree,
13332                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13333                                &tree, &node);
13334       if (node)
13335         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13336       else
13337         retval = FALSE;
13338     }
13339
13340   if (end_path)
13341     {
13342       gint y;
13343
13344       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13345         y = tree_view->priv->height - 1;
13346       else
13347         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13348
13349       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13350       if (node)
13351         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13352       else
13353         retval = FALSE;
13354     }
13355
13356   return retval;
13357 }
13358
13359 static void
13360 unset_reorderable (GtkTreeView *tree_view)
13361 {
13362   if (tree_view->priv->reorderable)
13363     {
13364       tree_view->priv->reorderable = FALSE;
13365       g_object_notify (G_OBJECT (tree_view), "reorderable");
13366     }
13367 }
13368
13369 /**
13370  * gtk_tree_view_enable_model_drag_source:
13371  * @tree_view: a #GtkTreeView
13372  * @start_button_mask: Mask of allowed buttons to start drag
13373  * @targets: the table of targets that the drag will support
13374  * @n_targets: the number of items in @targets
13375  * @actions: the bitmask of possible actions for a drag from this
13376  *    widget
13377  *
13378  * Turns @tree_view into a drag source for automatic DND. Calling this
13379  * method sets #GtkTreeView:reorderable to %FALSE.
13380  **/
13381 void
13382 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13383                                         GdkModifierType           start_button_mask,
13384                                         const GtkTargetEntry     *targets,
13385                                         gint                      n_targets,
13386                                         GdkDragAction             actions)
13387 {
13388   TreeViewDragInfo *di;
13389
13390   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13391
13392   gtk_drag_source_set (GTK_WIDGET (tree_view),
13393                        0,
13394                        targets,
13395                        n_targets,
13396                        actions);
13397
13398   di = ensure_info (tree_view);
13399
13400   di->start_button_mask = start_button_mask;
13401   di->source_actions = actions;
13402   di->source_set = TRUE;
13403
13404   unset_reorderable (tree_view);
13405 }
13406
13407 /**
13408  * gtk_tree_view_enable_model_drag_dest:
13409  * @tree_view: a #GtkTreeView
13410  * @targets: the table of targets that the drag will support
13411  * @n_targets: the number of items in @targets
13412  * @actions: the bitmask of possible actions for a drag from this
13413  *    widget
13414  * 
13415  * Turns @tree_view into a drop destination for automatic DND. Calling
13416  * this method sets #GtkTreeView:reorderable to %FALSE.
13417  **/
13418 void
13419 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13420                                       const GtkTargetEntry     *targets,
13421                                       gint                      n_targets,
13422                                       GdkDragAction             actions)
13423 {
13424   TreeViewDragInfo *di;
13425
13426   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13427
13428   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13429                      0,
13430                      targets,
13431                      n_targets,
13432                      actions);
13433
13434   di = ensure_info (tree_view);
13435   di->dest_set = TRUE;
13436
13437   unset_reorderable (tree_view);
13438 }
13439
13440 /**
13441  * gtk_tree_view_unset_rows_drag_source:
13442  * @tree_view: a #GtkTreeView
13443  *
13444  * Undoes the effect of
13445  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13446  * #GtkTreeView:reorderable to %FALSE.
13447  **/
13448 void
13449 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13450 {
13451   TreeViewDragInfo *di;
13452
13453   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13454
13455   di = get_info (tree_view);
13456
13457   if (di)
13458     {
13459       if (di->source_set)
13460         {
13461           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13462           di->source_set = FALSE;
13463         }
13464
13465       if (!di->dest_set && !di->source_set)
13466         remove_info (tree_view);
13467     }
13468   
13469   unset_reorderable (tree_view);
13470 }
13471
13472 /**
13473  * gtk_tree_view_unset_rows_drag_dest:
13474  * @tree_view: a #GtkTreeView
13475  *
13476  * Undoes the effect of
13477  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13478  * #GtkTreeView:reorderable to %FALSE.
13479  **/
13480 void
13481 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13482 {
13483   TreeViewDragInfo *di;
13484
13485   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13486
13487   di = get_info (tree_view);
13488
13489   if (di)
13490     {
13491       if (di->dest_set)
13492         {
13493           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13494           di->dest_set = FALSE;
13495         }
13496
13497       if (!di->dest_set && !di->source_set)
13498         remove_info (tree_view);
13499     }
13500
13501   unset_reorderable (tree_view);
13502 }
13503
13504 /**
13505  * gtk_tree_view_set_drag_dest_row:
13506  * @tree_view: a #GtkTreeView
13507  * @path: The path of the row to highlight, or %NULL.
13508  * @pos: Specifies whether to drop before, after or into the row
13509  * 
13510  * Sets the row that is highlighted for feedback.
13511  **/
13512 void
13513 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13514                                  GtkTreePath            *path,
13515                                  GtkTreeViewDropPosition pos)
13516 {
13517   GtkTreePath *current_dest;
13518
13519   /* Note; this function is exported to allow a custom DND
13520    * implementation, so it can't touch TreeViewDragInfo
13521    */
13522
13523   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13524
13525   current_dest = NULL;
13526
13527   if (tree_view->priv->drag_dest_row)
13528     {
13529       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13530       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13531     }
13532
13533   /* special case a drop on an empty model */
13534   tree_view->priv->empty_view_drop = 0;
13535
13536   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13537       && gtk_tree_path_get_depth (path) == 1
13538       && gtk_tree_path_get_indices (path)[0] == 0)
13539     {
13540       gint n_children;
13541
13542       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13543                                                    NULL);
13544
13545       if (!n_children)
13546         tree_view->priv->empty_view_drop = 1;
13547     }
13548
13549   tree_view->priv->drag_dest_pos = pos;
13550
13551   if (path)
13552     {
13553       tree_view->priv->drag_dest_row =
13554         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13555       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13556     }
13557   else
13558     tree_view->priv->drag_dest_row = NULL;
13559
13560   if (current_dest)
13561     {
13562       GtkRBTree *tree, *new_tree;
13563       GtkRBNode *node, *new_node;
13564
13565       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13566       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13567
13568       if (tree && node)
13569         {
13570           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13571           if (new_tree && new_node)
13572             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13573
13574           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13575           if (new_tree && new_node)
13576             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13577         }
13578       gtk_tree_path_free (current_dest);
13579     }
13580 }
13581
13582 /**
13583  * gtk_tree_view_get_drag_dest_row:
13584  * @tree_view: a #GtkTreeView
13585  * @path: Return location for the path of the highlighted row, or %NULL.
13586  * @pos: Return location for the drop position, or %NULL
13587  * 
13588  * Gets information about the row that is highlighted for feedback.
13589  **/
13590 void
13591 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13592                                  GtkTreePath             **path,
13593                                  GtkTreeViewDropPosition  *pos)
13594 {
13595   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13596
13597   if (path)
13598     {
13599       if (tree_view->priv->drag_dest_row)
13600         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13601       else
13602         {
13603           if (tree_view->priv->empty_view_drop)
13604             *path = gtk_tree_path_new_from_indices (0, -1);
13605           else
13606             *path = NULL;
13607         }
13608     }
13609
13610   if (pos)
13611     *pos = tree_view->priv->drag_dest_pos;
13612 }
13613
13614 /**
13615  * gtk_tree_view_get_dest_row_at_pos:
13616  * @tree_view: a #GtkTreeView
13617  * @drag_x: the position to determine the destination row for
13618  * @drag_y: the position to determine the destination row for
13619  * @path: Return location for the path of the highlighted row, or %NULL.
13620  * @pos: Return location for the drop position, or %NULL
13621  * 
13622  * Determines the destination row for a given position.  @drag_x and
13623  * @drag_y are expected to be in widget coordinates.
13624  * 
13625  * Return value: whether there is a row at the given position.
13626  **/
13627 gboolean
13628 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13629                                    gint                     drag_x,
13630                                    gint                     drag_y,
13631                                    GtkTreePath            **path,
13632                                    GtkTreeViewDropPosition *pos)
13633 {
13634   gint cell_y;
13635   gint bin_x, bin_y;
13636   gdouble offset_into_row;
13637   gdouble third;
13638   GdkRectangle cell;
13639   GtkTreeViewColumn *column = NULL;
13640   GtkTreePath *tmp_path = NULL;
13641
13642   /* Note; this function is exported to allow a custom DND
13643    * implementation, so it can't touch TreeViewDragInfo
13644    */
13645
13646   g_return_val_if_fail (tree_view != NULL, FALSE);
13647   g_return_val_if_fail (drag_x >= 0, FALSE);
13648   g_return_val_if_fail (drag_y >= 0, FALSE);
13649   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
13650
13651
13652   if (path)
13653     *path = NULL;
13654
13655   if (tree_view->priv->tree == NULL)
13656     return FALSE;
13657
13658   /* If in the top third of a row, we drop before that row; if
13659    * in the bottom third, drop after that row; if in the middle,
13660    * and the row has children, drop into the row.
13661    */
13662   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13663                                                      &bin_x, &bin_y);
13664
13665   if (!gtk_tree_view_get_path_at_pos (tree_view,
13666                                       bin_x,
13667                                       bin_y,
13668                                       &tmp_path,
13669                                       &column,
13670                                       NULL,
13671                                       &cell_y))
13672     return FALSE;
13673
13674   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13675                                      &cell);
13676
13677   offset_into_row = cell_y;
13678
13679   if (path)
13680     *path = tmp_path;
13681   else
13682     gtk_tree_path_free (tmp_path);
13683
13684   tmp_path = NULL;
13685
13686   third = cell.height / 3.0;
13687
13688   if (pos)
13689     {
13690       if (offset_into_row < third)
13691         {
13692           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13693         }
13694       else if (offset_into_row < (cell.height / 2.0))
13695         {
13696           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13697         }
13698       else if (offset_into_row < third * 2.0)
13699         {
13700           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13701         }
13702       else
13703         {
13704           *pos = GTK_TREE_VIEW_DROP_AFTER;
13705         }
13706     }
13707
13708   return TRUE;
13709 }
13710
13711
13712
13713 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13714 /**
13715  * gtk_tree_view_create_row_drag_icon:
13716  * @tree_view: a #GtkTreeView
13717  * @path: a #GtkTreePath in @tree_view
13718  *
13719  * Creates a #GdkPixmap representation of the row at @path.  
13720  * This image is used for a drag icon.
13721  *
13722  * Return value: a newly-allocated pixmap of the drag icon.
13723  **/
13724 GdkPixmap *
13725 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13726                                     GtkTreePath  *path)
13727 {
13728   GtkTreeIter   iter;
13729   GtkRBTree    *tree;
13730   GtkRBNode    *node;
13731   gint cell_offset;
13732   GList *list;
13733   GdkRectangle background_area;
13734   GdkRectangle expose_area;
13735   GtkWidget *widget;
13736   gint depth;
13737   /* start drawing inside the black outline */
13738   gint x = 1, y = 1;
13739   GdkDrawable *drawable;
13740   gint bin_window_width;
13741   gboolean is_separator = FALSE;
13742   gboolean rtl;
13743
13744   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13745   g_return_val_if_fail (path != NULL, NULL);
13746
13747   widget = GTK_WIDGET (tree_view);
13748
13749   if (!GTK_WIDGET_REALIZED (tree_view))
13750     return NULL;
13751
13752   depth = gtk_tree_path_get_depth (path);
13753
13754   _gtk_tree_view_find_node (tree_view,
13755                             path,
13756                             &tree,
13757                             &node);
13758
13759   if (tree == NULL)
13760     return NULL;
13761
13762   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13763                                 &iter,
13764                                 path))
13765     return NULL;
13766   
13767   is_separator = row_is_separator (tree_view, &iter, NULL);
13768
13769   cell_offset = x;
13770
13771   background_area.y = y;
13772   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13773
13774   gdk_drawable_get_size (tree_view->priv->bin_window,
13775                          &bin_window_width, NULL);
13776
13777   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13778                              bin_window_width + 2,
13779                              background_area.height + 2,
13780                              -1);
13781
13782   expose_area.x = 0;
13783   expose_area.y = 0;
13784   expose_area.width = bin_window_width + 2;
13785   expose_area.height = background_area.height + 2;
13786
13787   gdk_draw_rectangle (drawable,
13788                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
13789                       TRUE,
13790                       0, 0,
13791                       bin_window_width + 2,
13792                       background_area.height + 2);
13793
13794   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13795
13796   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13797       list;
13798       list = (rtl ? list->prev : list->next))
13799     {
13800       GtkTreeViewColumn *column = list->data;
13801       GdkRectangle cell_area;
13802       gint vertical_separator;
13803
13804       if (!column->visible)
13805         continue;
13806
13807       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13808                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13809                                                node->children?TRUE:FALSE);
13810
13811       background_area.x = cell_offset;
13812       background_area.width = column->width;
13813
13814       gtk_widget_style_get (widget,
13815                             "vertical-separator", &vertical_separator,
13816                             NULL);
13817
13818       cell_area = background_area;
13819
13820       cell_area.y += vertical_separator / 2;
13821       cell_area.height -= vertical_separator;
13822
13823       if (gtk_tree_view_is_expander_column (tree_view, column))
13824         {
13825           if (!rtl)
13826             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13827           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13828
13829           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13830             {
13831               if (!rtl)
13832                 cell_area.x += depth * tree_view->priv->expander_size;
13833               cell_area.width -= depth * tree_view->priv->expander_size;
13834             }
13835         }
13836
13837       if (gtk_tree_view_column_cell_is_visible (column))
13838         {
13839           if (is_separator)
13840             gtk_paint_hline (widget->style,
13841                              drawable,
13842                              GTK_STATE_NORMAL,
13843                              &cell_area,
13844                              widget,
13845                              NULL,
13846                              cell_area.x,
13847                              cell_area.x + cell_area.width,
13848                              cell_area.y + cell_area.height / 2);
13849           else
13850             _gtk_tree_view_column_cell_render (column,
13851                                                drawable,
13852                                                &background_area,
13853                                                &cell_area,
13854                                                &expose_area,
13855                                                0);
13856         }
13857       cell_offset += column->width;
13858     }
13859
13860   gdk_draw_rectangle (drawable,
13861                       widget->style->black_gc,
13862                       FALSE,
13863                       0, 0,
13864                       bin_window_width + 1,
13865                       background_area.height + 1);
13866
13867   return drawable;
13868 }
13869
13870
13871 /**
13872  * gtk_tree_view_set_destroy_count_func:
13873  * @tree_view: A #GtkTreeView
13874  * @func: Function to be called when a view row is destroyed, or %NULL
13875  * @data: User data to be passed to @func, or %NULL
13876  * @destroy: Destroy notifier for @data, or %NULL
13877  *
13878  * This function should almost never be used.  It is meant for private use by
13879  * ATK for determining the number of visible children that are removed when the
13880  * user collapses a row, or a row is deleted.
13881  **/
13882 void
13883 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13884                                       GtkTreeDestroyCountFunc  func,
13885                                       gpointer                 data,
13886                                       GDestroyNotify           destroy)
13887 {
13888   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13889
13890   if (tree_view->priv->destroy_count_destroy)
13891     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13892
13893   tree_view->priv->destroy_count_func = func;
13894   tree_view->priv->destroy_count_data = data;
13895   tree_view->priv->destroy_count_destroy = destroy;
13896 }
13897
13898
13899 /*
13900  * Interactive search
13901  */
13902
13903 /**
13904  * gtk_tree_view_set_enable_search:
13905  * @tree_view: A #GtkTreeView
13906  * @enable_search: %TRUE, if the user can search interactively
13907  *
13908  * If @enable_search is set, then the user can type in text to search through
13909  * the tree interactively (this is sometimes called "typeahead find").
13910  * 
13911  * Note that even if this is %FALSE, the user can still initiate a search 
13912  * using the "start-interactive-search" key binding.
13913  */
13914 void
13915 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13916                                  gboolean     enable_search)
13917 {
13918   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13919
13920   enable_search = !!enable_search;
13921   
13922   if (tree_view->priv->enable_search != enable_search)
13923     {
13924        tree_view->priv->enable_search = enable_search;
13925        g_object_notify (G_OBJECT (tree_view), "enable-search");
13926     }
13927 }
13928
13929 /**
13930  * gtk_tree_view_get_enable_search:
13931  * @tree_view: A #GtkTreeView
13932  *
13933  * Returns whether or not the tree allows to start interactive searching 
13934  * by typing in text.
13935  *
13936  * Return value: whether or not to let the user search interactively
13937  */
13938 gboolean
13939 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13940 {
13941   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13942
13943   return tree_view->priv->enable_search;
13944 }
13945
13946
13947 /**
13948  * gtk_tree_view_get_search_column:
13949  * @tree_view: A #GtkTreeView
13950  *
13951  * Gets the column searched on by the interactive search code.
13952  *
13953  * Return value: the column the interactive search code searches in.
13954  */
13955 gint
13956 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13957 {
13958   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13959
13960   return (tree_view->priv->search_column);
13961 }
13962
13963 /**
13964  * gtk_tree_view_set_search_column:
13965  * @tree_view: A #GtkTreeView
13966  * @column: the column of the model to search in, or -1 to disable searching
13967  *
13968  * Sets @column as the column where the interactive search code should
13969  * search in for the current model. 
13970  * 
13971  * If the search column is set, users can use the "start-interactive-search"
13972  * key binding to bring up search popup. The enable-search property controls
13973  * whether simply typing text will also start an interactive search.
13974  *
13975  * Note that @column refers to a column of the current model. The search 
13976  * column is reset to -1 when the model is changed.
13977  */
13978 void
13979 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13980                                  gint         column)
13981 {
13982   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13983   g_return_if_fail (column >= -1);
13984
13985   if (tree_view->priv->search_column == column)
13986     return;
13987
13988   tree_view->priv->search_column = column;
13989   g_object_notify (G_OBJECT (tree_view), "search-column");
13990 }
13991
13992 /**
13993  * gtk_tree_view_get_search_equal_func:
13994  * @tree_view: A #GtkTreeView
13995  *
13996  * Returns the compare function currently in use.
13997  *
13998  * Return value: the currently used compare function for the search code.
13999  */
14000
14001 GtkTreeViewSearchEqualFunc
14002 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14003 {
14004   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14005
14006   return tree_view->priv->search_equal_func;
14007 }
14008
14009 /**
14010  * gtk_tree_view_set_search_equal_func:
14011  * @tree_view: A #GtkTreeView
14012  * @search_equal_func: the compare function to use during the search
14013  * @search_user_data: user data to pass to @search_equal_func, or %NULL
14014  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
14015  *
14016  * Sets the compare function for the interactive search capabilities; note
14017  * that somewhat like strcmp() returning 0 for equality
14018  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14019  **/
14020 void
14021 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14022                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14023                                      gpointer                    search_user_data,
14024                                      GDestroyNotify              search_destroy)
14025 {
14026   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14027   g_return_if_fail (search_equal_func != NULL);
14028
14029   if (tree_view->priv->search_destroy)
14030     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14031
14032   tree_view->priv->search_equal_func = search_equal_func;
14033   tree_view->priv->search_user_data = search_user_data;
14034   tree_view->priv->search_destroy = search_destroy;
14035   if (tree_view->priv->search_equal_func == NULL)
14036     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14037 }
14038
14039 /**
14040  * gtk_tree_view_get_search_entry:
14041  * @tree_view: A #GtkTreeView
14042  *
14043  * Returns the #GtkEntry which is currently in use as interactive search
14044  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14045  * will be returned.
14046  *
14047  * Return value: the entry currently in use as search entry.
14048  *
14049  * Since: 2.10
14050  */
14051 GtkEntry *
14052 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14053 {
14054   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14055
14056   if (tree_view->priv->search_custom_entry_set)
14057     return GTK_ENTRY (tree_view->priv->search_entry);
14058
14059   return NULL;
14060 }
14061
14062 /**
14063  * gtk_tree_view_set_search_entry:
14064  * @tree_view: A #GtkTreeView
14065  * @entry: the entry the interactive search code of @tree_view should use or %NULL
14066  *
14067  * Sets the entry which the interactive search code will use for this
14068  * @tree_view.  This is useful when you want to provide a search entry
14069  * in our interface at all time at a fixed position.  Passing %NULL for
14070  * @entry will make the interactive search code use the built-in popup
14071  * entry again.
14072  *
14073  * Since: 2.10
14074  */
14075 void
14076 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14077                                 GtkEntry    *entry)
14078 {
14079   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14080   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14081
14082   if (tree_view->priv->search_custom_entry_set)
14083     {
14084       if (tree_view->priv->search_entry_changed_id)
14085         {
14086           g_signal_handler_disconnect (tree_view->priv->search_entry,
14087                                        tree_view->priv->search_entry_changed_id);
14088           tree_view->priv->search_entry_changed_id = 0;
14089         }
14090       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14091                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14092                                             tree_view);
14093
14094       g_object_unref (tree_view->priv->search_entry);
14095     }
14096   else if (tree_view->priv->search_window)
14097     {
14098       gtk_widget_destroy (tree_view->priv->search_window);
14099
14100       tree_view->priv->search_window = NULL;
14101     }
14102
14103   if (entry)
14104     {
14105       tree_view->priv->search_entry = g_object_ref (entry);
14106       tree_view->priv->search_custom_entry_set = TRUE;
14107
14108       if (tree_view->priv->search_entry_changed_id == 0)
14109         {
14110           tree_view->priv->search_entry_changed_id =
14111             g_signal_connect (tree_view->priv->search_entry, "changed",
14112                               G_CALLBACK (gtk_tree_view_search_init),
14113                               tree_view);
14114         }
14115       
14116         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14117                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14118                           tree_view);
14119
14120         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14121     }
14122   else
14123     {
14124       tree_view->priv->search_entry = NULL;
14125       tree_view->priv->search_custom_entry_set = FALSE;
14126     }
14127 }
14128
14129 /**
14130  * gtk_tree_view_set_search_position_func:
14131  * @tree_view: A #GtkTreeView
14132  * @func: the function to use to position the search dialog, or %NULL
14133  *    to use the default search position function
14134  * @data: user data to pass to @func, or %NULL
14135  * @destroy: Destroy notifier for @data, or %NULL
14136  *
14137  * Sets the function to use when positioning the search dialog.
14138  *
14139  * Since: 2.10
14140  **/
14141 void
14142 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14143                                         GtkTreeViewSearchPositionFunc  func,
14144                                         gpointer                       user_data,
14145                                         GDestroyNotify                 destroy)
14146 {
14147   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14148
14149   if (tree_view->priv->search_position_destroy)
14150     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14151
14152   tree_view->priv->search_position_func = func;
14153   tree_view->priv->search_position_user_data = user_data;
14154   tree_view->priv->search_position_destroy = destroy;
14155   if (tree_view->priv->search_position_func == NULL)
14156     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14157 }
14158
14159 /**
14160  * gtk_tree_view_get_search_position_func:
14161  * @tree_view: A #GtkTreeView
14162  *
14163  * Returns the positioning function currently in use.
14164  *
14165  * Return value: the currently used function for positioning the search dialog.
14166  *
14167  * Since: 2.10
14168  */
14169 GtkTreeViewSearchPositionFunc
14170 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14171 {
14172   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14173
14174   return tree_view->priv->search_position_func;
14175 }
14176
14177
14178 static void
14179 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14180                                   GtkTreeView *tree_view)
14181 {
14182   if (tree_view->priv->disable_popdown)
14183     return;
14184
14185   if (tree_view->priv->search_entry_changed_id)
14186     {
14187       g_signal_handler_disconnect (tree_view->priv->search_entry,
14188                                    tree_view->priv->search_entry_changed_id);
14189       tree_view->priv->search_entry_changed_id = 0;
14190     }
14191   if (tree_view->priv->typeselect_flush_timeout)
14192     {
14193       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14194       tree_view->priv->typeselect_flush_timeout = 0;
14195     }
14196         
14197   if (GTK_WIDGET_VISIBLE (search_dialog))
14198     {
14199       /* send focus-in event */
14200       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
14201       gtk_widget_hide (search_dialog);
14202       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14203       send_focus_change (GTK_WIDGET (tree_view), TRUE);
14204     }
14205 }
14206
14207 static void
14208 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14209                                     GtkWidget   *search_dialog,
14210                                     gpointer     user_data)
14211 {
14212   gint x, y;
14213   gint tree_x, tree_y;
14214   gint tree_width, tree_height;
14215   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
14216   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14217   GtkRequisition requisition;
14218   gint monitor_num;
14219   GdkRectangle monitor;
14220
14221   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14222   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14223
14224   gtk_widget_realize (search_dialog);
14225
14226   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14227   gdk_drawable_get_size (tree_window,
14228                          &tree_width,
14229                          &tree_height);
14230   gtk_widget_size_request (search_dialog, &requisition);
14231
14232   if (tree_x + tree_width > gdk_screen_get_width (screen))
14233     x = gdk_screen_get_width (screen) - requisition.width;
14234   else if (tree_x + tree_width - requisition.width < 0)
14235     x = 0;
14236   else
14237     x = tree_x + tree_width - requisition.width;
14238
14239   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14240     y = gdk_screen_get_height (screen) - requisition.height;
14241   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14242     y = 0;
14243   else
14244     y = tree_y + tree_height;
14245
14246   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14247 }
14248
14249 static void
14250 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14251                                       GtkMenu  *menu,
14252                                       gpointer  data)
14253 {
14254   GtkTreeView *tree_view = (GtkTreeView *)data;
14255
14256   tree_view->priv->disable_popdown = 1;
14257   g_signal_connect (menu, "hide",
14258                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14259 }
14260
14261 /* Because we're visible but offscreen, we just set a flag in the preedit
14262  * callback.
14263  */
14264 static void
14265 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14266                                       GtkTreeView  *tree_view)
14267 {
14268   tree_view->priv->imcontext_changed = 1;
14269   if (tree_view->priv->typeselect_flush_timeout)
14270     {
14271       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14272       tree_view->priv->typeselect_flush_timeout =
14273         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14274                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14275                        tree_view);
14276     }
14277
14278 }
14279
14280 static void
14281 gtk_tree_view_search_activate (GtkEntry    *entry,
14282                                GtkTreeView *tree_view)
14283 {
14284   GtkTreePath *path;
14285   GtkRBNode *node;
14286   GtkRBTree *tree;
14287
14288   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14289                                     tree_view);
14290
14291   /* If we have a row selected and it's the cursor row, we activate
14292    * the row XXX */
14293   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14294     {
14295       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14296       
14297       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14298       
14299       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14300         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14301       
14302       gtk_tree_path_free (path);
14303     }
14304 }
14305
14306 static gboolean
14307 gtk_tree_view_real_search_enable_popdown (gpointer data)
14308 {
14309   GtkTreeView *tree_view = (GtkTreeView *)data;
14310
14311   tree_view->priv->disable_popdown = 0;
14312
14313   return FALSE;
14314 }
14315
14316 static void
14317 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14318                                      gpointer   data)
14319 {
14320   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14321 }
14322
14323 static gboolean
14324 gtk_tree_view_search_delete_event (GtkWidget *widget,
14325                                    GdkEventAny *event,
14326                                    GtkTreeView *tree_view)
14327 {
14328   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14329
14330   gtk_tree_view_search_dialog_hide (widget, tree_view);
14331
14332   return TRUE;
14333 }
14334
14335 static gboolean
14336 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14337                                          GdkEventButton *event,
14338                                          GtkTreeView *tree_view)
14339 {
14340   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14341
14342   gtk_tree_view_search_dialog_hide (widget, tree_view);
14343
14344   if (event->window == tree_view->priv->bin_window)
14345     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14346
14347   return TRUE;
14348 }
14349
14350 static gboolean
14351 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14352                                    GdkEventScroll *event,
14353                                    GtkTreeView *tree_view)
14354 {
14355   gboolean retval = FALSE;
14356
14357   if (event->direction == GDK_SCROLL_UP)
14358     {
14359       gtk_tree_view_search_move (widget, tree_view, TRUE);
14360       retval = TRUE;
14361     }
14362   else if (event->direction == GDK_SCROLL_DOWN)
14363     {
14364       gtk_tree_view_search_move (widget, tree_view, FALSE);
14365       retval = TRUE;
14366     }
14367
14368   /* renew the flush timeout */
14369   if (retval && tree_view->priv->typeselect_flush_timeout
14370       && !tree_view->priv->search_custom_entry_set)
14371     {
14372       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14373       tree_view->priv->typeselect_flush_timeout =
14374         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14375                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14376                        tree_view);
14377     }
14378
14379   return retval;
14380 }
14381
14382 static gboolean
14383 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14384                                       GdkEventKey *event,
14385                                       GtkTreeView *tree_view)
14386 {
14387   gboolean retval = FALSE;
14388
14389   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14390   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14391
14392   /* close window and cancel the search */
14393   if (!tree_view->priv->search_custom_entry_set
14394       && (event->keyval == GDK_Escape ||
14395           event->keyval == GDK_Tab ||
14396             event->keyval == GDK_KP_Tab ||
14397             event->keyval == GDK_ISO_Left_Tab))
14398     {
14399       gtk_tree_view_search_dialog_hide (widget, tree_view);
14400       return TRUE;
14401     }
14402
14403   /* select previous matching iter */
14404   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
14405     {
14406       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14407         gtk_widget_error_bell (widget);
14408
14409       retval = TRUE;
14410     }
14411
14412   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
14413       && (event->keyval == GDK_g || event->keyval == GDK_G))
14414     {
14415       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14416         gtk_widget_error_bell (widget);
14417
14418       retval = TRUE;
14419     }
14420
14421   /* select next matching iter */
14422   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
14423     {
14424       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14425         gtk_widget_error_bell (widget);
14426
14427       retval = TRUE;
14428     }
14429
14430   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
14431       && (event->keyval == GDK_g || event->keyval == GDK_G))
14432     {
14433       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14434         gtk_widget_error_bell (widget);
14435
14436       retval = TRUE;
14437     }
14438
14439   /* renew the flush timeout */
14440   if (retval && tree_view->priv->typeselect_flush_timeout
14441       && !tree_view->priv->search_custom_entry_set)
14442     {
14443       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14444       tree_view->priv->typeselect_flush_timeout =
14445         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14446                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14447                        tree_view);
14448     }
14449
14450   return retval;
14451 }
14452
14453 /*  this function returns FALSE if there is a search string but
14454  *  nothing was found, and TRUE otherwise.
14455  */
14456 static gboolean
14457 gtk_tree_view_search_move (GtkWidget   *window,
14458                            GtkTreeView *tree_view,
14459                            gboolean     up)
14460 {
14461   gboolean ret;
14462   gint len;
14463   gint count = 0;
14464   const gchar *text;
14465   GtkTreeIter iter;
14466   GtkTreeModel *model;
14467   GtkTreeSelection *selection;
14468
14469   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14470
14471   g_return_val_if_fail (text != NULL, FALSE);
14472
14473   len = strlen (text);
14474
14475   if (up && tree_view->priv->selected_iter == 1)
14476     return strlen (text) < 1;
14477
14478   len = strlen (text);
14479
14480   if (len < 1)
14481     return TRUE;
14482
14483   model = gtk_tree_view_get_model (tree_view);
14484   selection = gtk_tree_view_get_selection (tree_view);
14485
14486   /* search */
14487   gtk_tree_selection_unselect_all (selection);
14488   if (!gtk_tree_model_get_iter_first (model, &iter))
14489     return TRUE;
14490
14491   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14492                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14493
14494   if (ret)
14495     {
14496       /* found */
14497       tree_view->priv->selected_iter += up?(-1):(1);
14498       return TRUE;
14499     }
14500   else
14501     {
14502       /* return to old iter */
14503       count = 0;
14504       gtk_tree_model_get_iter_first (model, &iter);
14505       gtk_tree_view_search_iter (model, selection,
14506                                  &iter, text,
14507                                  &count, tree_view->priv->selected_iter);
14508       return FALSE;
14509     }
14510 }
14511
14512 static gboolean
14513 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14514                                  gint          column,
14515                                  const gchar  *key,
14516                                  GtkTreeIter  *iter,
14517                                  gpointer      search_data)
14518 {
14519   gboolean retval = TRUE;
14520   const gchar *str;
14521   gchar *normalized_string;
14522   gchar *normalized_key;
14523   gchar *case_normalized_string = NULL;
14524   gchar *case_normalized_key = NULL;
14525   GValue value = {0,};
14526   GValue transformed = {0,};
14527
14528   gtk_tree_model_get_value (model, iter, column, &value);
14529
14530   g_value_init (&transformed, G_TYPE_STRING);
14531
14532   if (!g_value_transform (&value, &transformed))
14533     {
14534       g_value_unset (&value);
14535       return TRUE;
14536     }
14537
14538   g_value_unset (&value);
14539
14540   str = g_value_get_string (&transformed);
14541   if (!str)
14542     {
14543       g_value_unset (&transformed);
14544       return TRUE;
14545     }
14546
14547   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14548   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14549
14550   if (normalized_string && normalized_key)
14551     {
14552       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14553       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14554
14555       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14556         retval = FALSE;
14557     }
14558
14559   g_value_unset (&transformed);
14560   g_free (normalized_key);
14561   g_free (normalized_string);
14562   g_free (case_normalized_key);
14563   g_free (case_normalized_string);
14564
14565   return retval;
14566 }
14567
14568 static gboolean
14569 gtk_tree_view_search_iter (GtkTreeModel     *model,
14570                            GtkTreeSelection *selection,
14571                            GtkTreeIter      *iter,
14572                            const gchar      *text,
14573                            gint             *count,
14574                            gint              n)
14575 {
14576   GtkRBTree *tree = NULL;
14577   GtkRBNode *node = NULL;
14578   GtkTreePath *path;
14579
14580   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14581
14582   path = gtk_tree_model_get_path (model, iter);
14583   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14584
14585   do
14586     {
14587       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14588         {
14589           (*count)++;
14590           if (*count == n)
14591             {
14592               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14593                                             TRUE, 0.5, 0.0);
14594               gtk_tree_selection_select_iter (selection, iter);
14595               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14596
14597               if (path)
14598                 gtk_tree_path_free (path);
14599
14600               return TRUE;
14601             }
14602         }
14603
14604       if (node->children)
14605         {
14606           gboolean has_child;
14607           GtkTreeIter tmp;
14608
14609           tree = node->children;
14610           node = tree->root;
14611
14612           while (node->left != tree->nil)
14613             node = node->left;
14614
14615           tmp = *iter;
14616           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14617           gtk_tree_path_down (path);
14618
14619           /* sanity check */
14620           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14621         }
14622       else
14623         {
14624           gboolean done = FALSE;
14625
14626           do
14627             {
14628               node = _gtk_rbtree_next (tree, node);
14629
14630               if (node)
14631                 {
14632                   gboolean has_next;
14633
14634                   has_next = gtk_tree_model_iter_next (model, iter);
14635
14636                   done = TRUE;
14637                   gtk_tree_path_next (path);
14638
14639                   /* sanity check */
14640                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14641                 }
14642               else
14643                 {
14644                   gboolean has_parent;
14645                   GtkTreeIter tmp_iter = *iter;
14646
14647                   node = tree->parent_node;
14648                   tree = tree->parent_tree;
14649
14650                   if (!tree)
14651                     {
14652                       if (path)
14653                         gtk_tree_path_free (path);
14654
14655                       /* we've run out of tree, done with this func */
14656                       return FALSE;
14657                     }
14658
14659                   has_parent = gtk_tree_model_iter_parent (model,
14660                                                            iter,
14661                                                            &tmp_iter);
14662                   gtk_tree_path_up (path);
14663
14664                   /* sanity check */
14665                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14666                 }
14667             }
14668           while (!done);
14669         }
14670     }
14671   while (1);
14672
14673   return FALSE;
14674 }
14675
14676 static void
14677 gtk_tree_view_search_init (GtkWidget   *entry,
14678                            GtkTreeView *tree_view)
14679 {
14680   gint ret;
14681   gint len;
14682   gint count = 0;
14683   const gchar *text;
14684   GtkTreeIter iter;
14685   GtkTreeModel *model;
14686   GtkTreeSelection *selection;
14687
14688   g_return_if_fail (GTK_IS_ENTRY (entry));
14689   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14690
14691   text = gtk_entry_get_text (GTK_ENTRY (entry));
14692   len = strlen (text);
14693   model = gtk_tree_view_get_model (tree_view);
14694   selection = gtk_tree_view_get_selection (tree_view);
14695
14696   /* search */
14697   gtk_tree_selection_unselect_all (selection);
14698   if (tree_view->priv->typeselect_flush_timeout
14699       && !tree_view->priv->search_custom_entry_set)
14700     {
14701       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14702       tree_view->priv->typeselect_flush_timeout =
14703         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14704                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14705                        tree_view);
14706     }
14707
14708   if (len < 1)
14709     return;
14710
14711   if (!gtk_tree_model_get_iter_first (model, &iter))
14712     return;
14713
14714   ret = gtk_tree_view_search_iter (model, selection,
14715                                    &iter, text,
14716                                    &count, 1);
14717
14718   if (ret)
14719     tree_view->priv->selected_iter = 1;
14720 }
14721
14722 static void
14723 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14724                              GtkTreeView     *tree_view)
14725 {
14726   if (tree_view->priv->edited_column == NULL)
14727     return;
14728
14729   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14730   tree_view->priv->edited_column = NULL;
14731
14732   if (GTK_WIDGET_HAS_FOCUS (cell_editable))
14733     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14734
14735   g_signal_handlers_disconnect_by_func (cell_editable,
14736                                         gtk_tree_view_remove_widget,
14737                                         tree_view);
14738
14739   gtk_container_remove (GTK_CONTAINER (tree_view),
14740                         GTK_WIDGET (cell_editable));  
14741
14742   /* FIXME should only redraw a single node */
14743   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14744 }
14745
14746 static gboolean
14747 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14748                              GtkTreePath *cursor_path)
14749 {
14750   GtkTreeIter iter;
14751   GdkRectangle background_area;
14752   GdkRectangle cell_area;
14753   GtkCellEditable *editable_widget = NULL;
14754   gchar *path_string;
14755   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14756   gint retval = FALSE;
14757   GtkRBTree *cursor_tree;
14758   GtkRBNode *cursor_node;
14759
14760   g_assert (tree_view->priv->focus_column);
14761
14762   if (! GTK_WIDGET_REALIZED (tree_view))
14763     return FALSE;
14764
14765   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14766       cursor_node == NULL)
14767     return FALSE;
14768
14769   path_string = gtk_tree_path_to_string (cursor_path);
14770   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14771
14772   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14773
14774   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14775                                            tree_view->priv->model,
14776                                            &iter,
14777                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14778                                            cursor_node->children?TRUE:FALSE);
14779   gtk_tree_view_get_background_area (tree_view,
14780                                      cursor_path,
14781                                      tree_view->priv->focus_column,
14782                                      &background_area);
14783   gtk_tree_view_get_cell_area (tree_view,
14784                                cursor_path,
14785                                tree_view->priv->focus_column,
14786                                &cell_area);
14787
14788   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14789                                         &editable_widget,
14790                                         NULL,
14791                                         path_string,
14792                                         &background_area,
14793                                         &cell_area,
14794                                         flags))
14795     {
14796       retval = TRUE;
14797       if (editable_widget != NULL)
14798         {
14799           gint left, right;
14800           GdkRectangle area;
14801           GtkCellRenderer *cell;
14802
14803           area = cell_area;
14804           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14805
14806           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14807
14808           area.x += left;
14809           area.width -= right + left;
14810
14811           gtk_tree_view_real_start_editing (tree_view,
14812                                             tree_view->priv->focus_column,
14813                                             cursor_path,
14814                                             editable_widget,
14815                                             &area,
14816                                             NULL,
14817                                             flags);
14818         }
14819
14820     }
14821   g_free (path_string);
14822   return retval;
14823 }
14824
14825 static void
14826 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14827                                   GtkTreeViewColumn *column,
14828                                   GtkTreePath       *path,
14829                                   GtkCellEditable   *cell_editable,
14830                                   GdkRectangle      *cell_area,
14831                                   GdkEvent          *event,
14832                                   guint              flags)
14833 {
14834   gint pre_val = tree_view->priv->vadjustment->value;
14835   GtkRequisition requisition;
14836
14837   tree_view->priv->edited_column = column;
14838   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14839
14840   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14841   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14842
14843   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
14844
14845   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14846
14847   if (requisition.height < cell_area->height)
14848     {
14849       gint diff = cell_area->height - requisition.height;
14850       gtk_tree_view_put (tree_view,
14851                          GTK_WIDGET (cell_editable),
14852                          cell_area->x, cell_area->y + diff/2,
14853                          cell_area->width, requisition.height);
14854     }
14855   else
14856     {
14857       gtk_tree_view_put (tree_view,
14858                          GTK_WIDGET (cell_editable),
14859                          cell_area->x, cell_area->y,
14860                          cell_area->width, cell_area->height);
14861     }
14862
14863   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14864                                    (GdkEvent *)event);
14865
14866   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14867   g_signal_connect (cell_editable, "remove-widget",
14868                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14869 }
14870
14871 static void
14872 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14873                             gboolean     cancel_editing)
14874 {
14875   GtkTreeViewColumn *column;
14876   GtkCellRenderer *cell;
14877
14878   if (tree_view->priv->edited_column == NULL)
14879     return;
14880
14881   /*
14882    * This is very evil. We need to do this, because
14883    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14884    * later on. If gtk_tree_view_row_changed notices
14885    * tree_view->priv->edited_column != NULL, it'll call
14886    * gtk_tree_view_stop_editing again. Bad things will happen then.
14887    *
14888    * Please read that again if you intend to modify anything here.
14889    */
14890
14891   column = tree_view->priv->edited_column;
14892   tree_view->priv->edited_column = NULL;
14893
14894   cell = _gtk_tree_view_column_get_edited_cell (column);
14895   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14896
14897   if (!cancel_editing)
14898     gtk_cell_editable_editing_done (column->editable_widget);
14899
14900   tree_view->priv->edited_column = column;
14901
14902   gtk_cell_editable_remove_widget (column->editable_widget);
14903 }
14904
14905
14906 /**
14907  * gtk_tree_view_set_hover_selection:
14908  * @tree_view: a #GtkTreeView
14909  * @hover: %TRUE to enable hover selection mode
14910  *
14911  * Enables of disables the hover selection mode of @tree_view.
14912  * Hover selection makes the selected row follow the pointer.
14913  * Currently, this works only for the selection modes 
14914  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14915  * 
14916  * Since: 2.6
14917  **/
14918 void     
14919 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14920                                    gboolean     hover)
14921 {
14922   hover = hover != FALSE;
14923
14924   if (hover != tree_view->priv->hover_selection)
14925     {
14926       tree_view->priv->hover_selection = hover;
14927
14928       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14929     }
14930 }
14931
14932 /**
14933  * gtk_tree_view_get_hover_selection:
14934  * @tree_view: a #GtkTreeView
14935  * 
14936  * Returns whether hover selection mode is turned on for @tree_view.
14937  * 
14938  * Return value: %TRUE if @tree_view is in hover selection mode
14939  *
14940  * Since: 2.6 
14941  **/
14942 gboolean 
14943 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14944 {
14945   return tree_view->priv->hover_selection;
14946 }
14947
14948 /**
14949  * gtk_tree_view_set_hover_expand:
14950  * @tree_view: a #GtkTreeView
14951  * @expand: %TRUE to enable hover selection mode
14952  *
14953  * Enables of disables the hover expansion mode of @tree_view.
14954  * Hover expansion makes rows expand or collapse if the pointer 
14955  * moves over them.
14956  * 
14957  * Since: 2.6
14958  **/
14959 void     
14960 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14961                                 gboolean     expand)
14962 {
14963   expand = expand != FALSE;
14964
14965   if (expand != tree_view->priv->hover_expand)
14966     {
14967       tree_view->priv->hover_expand = expand;
14968
14969       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14970     }
14971 }
14972
14973 /**
14974  * gtk_tree_view_get_hover_expand:
14975  * @tree_view: a #GtkTreeView
14976  * 
14977  * Returns whether hover expansion mode is turned on for @tree_view.
14978  * 
14979  * Return value: %TRUE if @tree_view is in hover expansion mode
14980  *
14981  * Since: 2.6 
14982  **/
14983 gboolean 
14984 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14985 {
14986   return tree_view->priv->hover_expand;
14987 }
14988
14989 /**
14990  * gtk_tree_view_set_rubber_banding:
14991  * @tree_view: a #GtkTreeView
14992  * @enable: %TRUE to enable rubber banding
14993  *
14994  * Enables or disables rubber banding in @tree_view.  If the selection mode
14995  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14996  * multiple rows by dragging the mouse.
14997  * 
14998  * Since: 2.10
14999  **/
15000 void
15001 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15002                                   gboolean     enable)
15003 {
15004   enable = enable != FALSE;
15005
15006   if (enable != tree_view->priv->rubber_banding_enable)
15007     {
15008       tree_view->priv->rubber_banding_enable = enable;
15009
15010       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15011     }
15012 }
15013
15014 /**
15015  * gtk_tree_view_get_rubber_banding:
15016  * @tree_view: a #GtkTreeView
15017  * 
15018  * Returns whether rubber banding is turned on for @tree_view.  If the
15019  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15020  * user to select multiple rows by dragging the mouse.
15021  * 
15022  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15023  *
15024  * Since: 2.10
15025  **/
15026 gboolean
15027 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15028 {
15029   return tree_view->priv->rubber_banding_enable;
15030 }
15031
15032 /**
15033  * gtk_tree_view_is_rubber_banding_active:
15034  * @tree_view: a #GtkTreeView
15035  * 
15036  * Returns whether a rubber banding operation is currently being done
15037  * in @tree_view.
15038  *
15039  * Return value: %TRUE if a rubber banding operation is currently being
15040  * done in @tree_view.
15041  *
15042  * Since: 2.12
15043  **/
15044 gboolean
15045 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15046 {
15047   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15048
15049   if (tree_view->priv->rubber_banding_enable
15050       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15051     return TRUE;
15052
15053   return FALSE;
15054 }
15055
15056 /**
15057  * gtk_tree_view_get_row_separator_func:
15058  * @tree_view: a #GtkTreeView
15059  * 
15060  * Returns the current row separator function.
15061  * 
15062  * Return value: the current row separator function.
15063  *
15064  * Since: 2.6
15065  **/
15066 GtkTreeViewRowSeparatorFunc 
15067 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15068 {
15069   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15070
15071   return tree_view->priv->row_separator_func;
15072 }
15073
15074 /**
15075  * gtk_tree_view_set_row_separator_func:
15076  * @tree_view: a #GtkTreeView
15077  * @func: a #GtkTreeViewRowSeparatorFunc
15078  * @data: user data to pass to @func, or %NULL
15079  * @destroy: destroy notifier for @data, or %NULL
15080  * 
15081  * Sets the row separator function, which is used to determine
15082  * whether a row should be drawn as a separator. If the row separator
15083  * function is %NULL, no separators are drawn. This is the default value.
15084  *
15085  * Since: 2.6
15086  **/
15087 void
15088 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15089                                       GtkTreeViewRowSeparatorFunc  func,
15090                                       gpointer                     data,
15091                                       GDestroyNotify               destroy)
15092 {
15093   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15094
15095   if (tree_view->priv->row_separator_destroy)
15096     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15097
15098   tree_view->priv->row_separator_func = func;
15099   tree_view->priv->row_separator_data = data;
15100   tree_view->priv->row_separator_destroy = destroy;
15101 }
15102
15103   
15104 static void
15105 gtk_tree_view_grab_notify (GtkWidget *widget,
15106                            gboolean   was_grabbed)
15107 {
15108   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15109
15110   tree_view->priv->in_grab = !was_grabbed;
15111
15112   if (!was_grabbed)
15113     {
15114       tree_view->priv->pressed_button = -1;
15115
15116       if (tree_view->priv->rubber_band_status)
15117         gtk_tree_view_stop_rubber_band (tree_view);
15118     }
15119 }
15120
15121 static void
15122 gtk_tree_view_state_changed (GtkWidget      *widget,
15123                              GtkStateType    previous_state)
15124 {
15125   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15126
15127   if (GTK_WIDGET_REALIZED (widget))
15128     {
15129       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
15130       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
15131     }
15132
15133   gtk_widget_queue_draw (widget);
15134 }
15135
15136 /**
15137  * gtk_tree_view_get_grid_lines:
15138  * @tree_view: a #GtkTreeView
15139  *
15140  * Returns which grid lines are enabled in @tree_view.
15141  *
15142  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15143  * are enabled.
15144  *
15145  * Since: 2.10
15146  */
15147 GtkTreeViewGridLines
15148 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15149 {
15150   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15151
15152   return tree_view->priv->grid_lines;
15153 }
15154
15155 /**
15156  * gtk_tree_view_set_grid_lines:
15157  * @tree_view: a #GtkTreeView
15158  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15159  * enable.
15160  *
15161  * Sets which grid lines to draw in @tree_view.
15162  *
15163  * Since: 2.10
15164  */
15165 void
15166 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15167                               GtkTreeViewGridLines   grid_lines)
15168 {
15169   GtkTreeViewPrivate *priv;
15170   GtkWidget *widget;
15171   GtkTreeViewGridLines old_grid_lines;
15172
15173   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15174
15175   priv = tree_view->priv;
15176   widget = GTK_WIDGET (tree_view);
15177
15178   old_grid_lines = priv->grid_lines;
15179   priv->grid_lines = grid_lines;
15180   
15181   if (GTK_WIDGET_REALIZED (widget))
15182     {
15183       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15184           priv->grid_line_gc)
15185         {
15186           g_object_unref (priv->grid_line_gc);
15187           priv->grid_line_gc = NULL;
15188         }
15189       
15190       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15191           !priv->grid_line_gc)
15192         {
15193           gint line_width;
15194           gint8 *dash_list;
15195
15196           gtk_widget_style_get (widget,
15197                                 "grid-line-width", &line_width,
15198                                 "grid-line-pattern", (gchar *)&dash_list,
15199                                 NULL);
15200       
15201           priv->grid_line_gc = gdk_gc_new (widget->window);
15202           gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
15203           
15204           gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
15205                                       GDK_LINE_ON_OFF_DASH,
15206                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15207           gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
15208
15209           g_free (dash_list);
15210         }      
15211     }
15212
15213   if (old_grid_lines != grid_lines)
15214     {
15215       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15216       
15217       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15218     }
15219 }
15220
15221 /**
15222  * gtk_tree_view_get_enable_tree_lines:
15223  * @tree_view: a #GtkTreeView.
15224  *
15225  * Returns whether or not tree lines are drawn in @tree_view.
15226  *
15227  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15228  * otherwise.
15229  *
15230  * Since: 2.10
15231  */
15232 gboolean
15233 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15234 {
15235   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15236
15237   return tree_view->priv->tree_lines_enabled;
15238 }
15239
15240 /**
15241  * gtk_tree_view_set_enable_tree_lines:
15242  * @tree_view: a #GtkTreeView
15243  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15244  *
15245  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15246  * This does not have any visible effects for lists.
15247  *
15248  * Since: 2.10
15249  */
15250 void
15251 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15252                                      gboolean     enabled)
15253 {
15254   GtkTreeViewPrivate *priv;
15255   GtkWidget *widget;
15256   gboolean was_enabled;
15257
15258   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15259
15260   enabled = enabled != FALSE;
15261
15262   priv = tree_view->priv;
15263   widget = GTK_WIDGET (tree_view);
15264
15265   was_enabled = priv->tree_lines_enabled;
15266
15267   priv->tree_lines_enabled = enabled;
15268
15269   if (GTK_WIDGET_REALIZED (widget))
15270     {
15271       if (!enabled && priv->tree_line_gc)
15272         {
15273           g_object_unref (priv->tree_line_gc);
15274           priv->tree_line_gc = NULL;
15275         }
15276       
15277       if (enabled && !priv->tree_line_gc)
15278         {
15279           gint line_width;
15280           gint8 *dash_list;
15281           gtk_widget_style_get (widget,
15282                                 "tree-line-width", &line_width,
15283                                 "tree-line-pattern", (gchar *)&dash_list,
15284                                 NULL);
15285           
15286           priv->tree_line_gc = gdk_gc_new (widget->window);
15287           gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc);
15288           
15289           gdk_gc_set_line_attributes (priv->tree_line_gc, line_width,
15290                                       GDK_LINE_ON_OFF_DASH,
15291                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15292           gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2);
15293
15294           g_free (dash_list);
15295         }
15296     }
15297
15298   if (was_enabled != enabled)
15299     {
15300       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15301
15302       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15303     }
15304 }
15305
15306
15307 /**
15308  * gtk_tree_view_set_show_expanders:
15309  * @tree_view: a #GtkTreeView
15310  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15311  *
15312  * Sets whether to draw and enable expanders and indent child rows in
15313  * @tree_view.  When disabled there will be no expanders visible in trees
15314  * and there will be no way to expand and collapse rows by default.  Also
15315  * note that hiding the expanders will disable the default indentation.  You
15316  * can set a custom indentation in this case using
15317  * gtk_tree_view_set_level_indentation().
15318  * This does not have any visible effects for lists.
15319  *
15320  * Since: 2.12
15321  */
15322 void
15323 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15324                                   gboolean     enabled)
15325 {
15326   gboolean was_enabled;
15327
15328   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15329
15330   enabled = enabled != FALSE;
15331   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15332
15333   if (enabled)
15334     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15335   else
15336     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15337
15338   if (enabled != was_enabled)
15339     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15340 }
15341
15342 /**
15343  * gtk_tree_view_get_show_expanders:
15344  * @tree_view: a #GtkTreeView.
15345  *
15346  * Returns whether or not expanders are drawn in @tree_view.
15347  *
15348  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15349  * otherwise.
15350  *
15351  * Since: 2.12
15352  */
15353 gboolean
15354 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15355 {
15356   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15357
15358   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15359 }
15360
15361 /**
15362  * gtk_tree_view_set_level_indentation:
15363  * @tree_view: a #GtkTreeView
15364  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15365  *
15366  * Sets the amount of extra indentation for child levels to use in @tree_view
15367  * in addition to the default indentation.  The value should be specified in
15368  * pixels, a value of 0 disables this feature and in this case only the default
15369  * indentation will be used.
15370  * This does not have any visible effects for lists.
15371  *
15372  * Since: 2.12
15373  */
15374 void
15375 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15376                                      gint         indentation)
15377 {
15378   tree_view->priv->level_indentation = indentation;
15379
15380   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15381 }
15382
15383 /**
15384  * gtk_tree_view_get_level_indentation:
15385  * @tree_view: a #GtkTreeView.
15386  *
15387  * Returns the amount, in pixels, of extra indentation for child levels
15388  * in @tree_view.
15389  *
15390  * Return value: the amount of extra indentation for child levels in
15391  * @tree_view.  A return value of 0 means that this feature is disabled.
15392  *
15393  * Since: 2.12
15394  */
15395 gint
15396 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15397 {
15398   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15399
15400   return tree_view->priv->level_indentation;
15401 }
15402
15403 /**
15404  * gtk_tree_view_set_tooltip_row:
15405  * @tree_view: a #GtkTreeView
15406  * @tooltip: a #GtkTooltip
15407  * @path: a #GtkTreePath
15408  *
15409  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15410  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15411  * See also gtk_tooltip_set_tip_area().
15412  *
15413  * Since: 2.12
15414  */
15415 void
15416 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15417                                GtkTooltip  *tooltip,
15418                                GtkTreePath *path)
15419 {
15420   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15421   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15422
15423   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15424 }
15425
15426 /**
15427  * gtk_tree_view_set_tooltip_cell:
15428  * @tree_view: a #GtkTreeView
15429  * @tooltip: a #GtkTooltip
15430  * @path: a #GtkTreePath or %NULL
15431  * @column: a #GtkTreeViewColumn or %NULL
15432  * @cell: a #GtkCellRenderer or %NULL
15433  *
15434  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15435  * in common.  For example if @path is %NULL and @column is set, the tip
15436  * area will be set to the full area covered by @column.  See also
15437  * gtk_tooltip_set_tip_area().
15438  *
15439  * Note that if @path is not specified and @cell is set and part of a column
15440  * containing the expander, the tooltip might not show and hide at the correct
15441  * position.  In such cases @path must be set to the current node under the
15442  * mouse cursor for this function to operate correctly.
15443  *
15444  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15445  *
15446  * Since: 2.12
15447  */
15448 void
15449 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15450                                 GtkTooltip        *tooltip,
15451                                 GtkTreePath       *path,
15452                                 GtkTreeViewColumn *column,
15453                                 GtkCellRenderer   *cell)
15454 {
15455   GdkRectangle rect;
15456
15457   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15458   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15459   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15460   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15461
15462   /* Determine x values. */
15463   if (column && cell)
15464     {
15465       GdkRectangle tmp;
15466       gint start, width;
15467
15468       /* We always pass in path here, whether it is NULL or not.
15469        * For cells in expander columns path must be specified so that
15470        * we can correctly account for the indentation.  This also means
15471        * that the tooltip is constrained vertically by the "Determine y
15472        * values" code below; this is not a real problem since cells actually
15473        * don't stretch vertically in constrast to columns.
15474        */
15475       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15476       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15477
15478       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15479                                                          tmp.x + start, 0,
15480                                                          &rect.x, NULL);
15481       rect.width = width;
15482     }
15483   else if (column)
15484     {
15485       GdkRectangle tmp;
15486
15487       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15488       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15489                                                          tmp.x, 0,
15490                                                          &rect.x, NULL);
15491       rect.width = tmp.width;
15492     }
15493   else
15494     {
15495       rect.x = 0;
15496       rect.width = GTK_WIDGET (tree_view)->allocation.width;
15497     }
15498
15499   /* Determine y values. */
15500   if (path)
15501     {
15502       GdkRectangle tmp;
15503
15504       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15505       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15506                                                          0, tmp.y,
15507                                                          NULL, &rect.y);
15508       rect.height = tmp.height;
15509     }
15510   else
15511     {
15512       rect.y = 0;
15513       rect.height = tree_view->priv->vadjustment->page_size;
15514     }
15515
15516   gtk_tooltip_set_tip_area (tooltip, &rect);
15517 }
15518
15519 /**
15520  * gtk_tree_view_get_tooltip_context:
15521  * @tree_view: a #GtkTreeView
15522  * @x: the x coordinate (relative to widget coordinates)
15523  * @y: the y coordinate (relative to widget coordinates)
15524  * @keyboard_tip: whether this is a keyboard tooltip or not
15525  * @model: a pointer to receive a #GtkTreeModel or %NULL
15526  * @path: a pointer to receive a #GtkTreePath or %NULL
15527  * @iter: a pointer to receive a #GtkTreeIter or %NULL
15528  *
15529  * This function is supposed to be used in a #GtkWidget::query-tooltip
15530  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15531  * which are received in the signal handler, should be passed to this
15532  * function without modification.
15533  *
15534  * The return value indicates whether there is a tree view row at the given
15535  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15536  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15537  * @model, @path and @iter which have been provided will be set to point to
15538  * that row and the corresponding model.  @x and @y will always be converted
15539  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15540  *
15541  * Return value: whether or not the given tooltip context points to a row.
15542  *
15543  * Since: 2.12
15544  */
15545 gboolean
15546 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15547                                    gint          *x,
15548                                    gint          *y,
15549                                    gboolean       keyboard_tip,
15550                                    GtkTreeModel **model,
15551                                    GtkTreePath  **path,
15552                                    GtkTreeIter   *iter)
15553 {
15554   GtkTreePath *tmppath = NULL;
15555
15556   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15557   g_return_val_if_fail (x != NULL, FALSE);
15558   g_return_val_if_fail (y != NULL, FALSE);
15559
15560   if (keyboard_tip)
15561     {
15562       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15563
15564       if (!tmppath)
15565         return FALSE;
15566     }
15567   else
15568     {
15569       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15570                                                          x, y);
15571
15572       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15573                                           &tmppath, NULL, NULL, NULL))
15574         return FALSE;
15575     }
15576
15577   if (model)
15578     *model = gtk_tree_view_get_model (tree_view);
15579
15580   if (iter)
15581     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15582                              iter, tmppath);
15583
15584   if (path)
15585     *path = tmppath;
15586   else
15587     gtk_tree_path_free (tmppath);
15588
15589   return TRUE;
15590 }
15591
15592 static gboolean
15593 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15594                                     gint        x,
15595                                     gint        y,
15596                                     gboolean    keyboard_tip,
15597                                     GtkTooltip *tooltip,
15598                                     gpointer    data)
15599 {
15600   GValue value = { 0, };
15601   GValue transformed = { 0, };
15602   GtkTreeIter iter;
15603   GtkTreePath *path;
15604   GtkTreeModel *model;
15605   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15606
15607   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15608                                           &x, &y,
15609                                           keyboard_tip,
15610                                           &model, &path, &iter))
15611     return FALSE;
15612
15613   gtk_tree_model_get_value (model, &iter,
15614                             tree_view->priv->tooltip_column, &value);
15615
15616   g_value_init (&transformed, G_TYPE_STRING);
15617
15618   if (!g_value_transform (&value, &transformed))
15619     {
15620       g_value_unset (&value);
15621       gtk_tree_path_free (path);
15622
15623       return FALSE;
15624     }
15625
15626   g_value_unset (&value);
15627
15628   if (!g_value_get_string (&transformed))
15629     {
15630       g_value_unset (&transformed);
15631       gtk_tree_path_free (path);
15632
15633       return FALSE;
15634     }
15635
15636   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15637   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15638
15639   gtk_tree_path_free (path);
15640   g_value_unset (&transformed);
15641
15642   return TRUE;
15643 }
15644
15645 /**
15646  * gtk_tree_view_set_tooltip_column:
15647  * @tree_view: a #GtkTreeView
15648  * @column: an integer, which is a valid column number for @tree_view's model
15649  *
15650  * If you only plan to have simple (text-only) tooltips on full rows, you
15651  * can use this function to have #GtkTreeView handle these automatically
15652  * for you. @column should be set to the column in @tree_view's model
15653  * containing the tooltip texts, or -1 to disable this feature.
15654  *
15655  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15656  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15657  *
15658  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15659  * so &amp;, &lt;, etc have to be escaped in the text.
15660  *
15661  * Since: 2.12
15662  */
15663 void
15664 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15665                                   gint         column)
15666 {
15667   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15668
15669   if (column == tree_view->priv->tooltip_column)
15670     return;
15671
15672   if (column == -1)
15673     {
15674       g_signal_handlers_disconnect_by_func (tree_view,
15675                                             gtk_tree_view_set_tooltip_query_cb,
15676                                             NULL);
15677       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15678     }
15679   else
15680     {
15681       if (tree_view->priv->tooltip_column == -1)
15682         {
15683           g_signal_connect (tree_view, "query-tooltip",
15684                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15685           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15686         }
15687     }
15688
15689   tree_view->priv->tooltip_column = column;
15690   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15691 }
15692
15693 /**
15694  * gtk_tree_view_get_tooltip_column:
15695  * @tree_view: a #GtkTreeView
15696  *
15697  * Returns the column of @tree_view's model which is being used for
15698  * displaying tooltips on @tree_view's rows.
15699  *
15700  * Return value: the index of the tooltip column that is currently being
15701  * used, or -1 if this is disabled.
15702  *
15703  * Since: 2.12
15704  */
15705 gint
15706 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15707 {
15708   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15709
15710   return tree_view->priv->tooltip_column;
15711 }
15712
15713 #define __GTK_TREE_VIEW_C__
15714 #include "gtkaliasdef.c"