]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Fix #477175, reported by Juri Pakaste.
[~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_NUM_ROWS_PER_IDLE 500
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 *source_target_list;
96   GdkDragAction source_actions;
97
98   GtkTargetList *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                                                               GdkRectangle      *clip_rect);
325 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView       *tree_view,
326                                                               GtkRBTree         *tree,
327                                                               GtkRBNode         *node,
328                                                               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 gboolean do_expand_collapse                           (GtkTreeView       *tree_view);
395 static void     gtk_tree_view_stop_rubber_band                (GtkTreeView       *tree_view);
396
397 /* interactive search */
398 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
399 static void     gtk_tree_view_search_dialog_hide     (GtkWidget        *search_dialog,
400                                                          GtkTreeView      *tree_view);
401 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
402                                                          GtkWidget        *search_dialog,
403                                                          gpointer          user_data);
404 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
405                                                          GtkMenu          *menu,
406                                                          gpointer          data);
407 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
408                                                          GtkTreeView      *tree_view);
409 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
410                                                          GtkTreeView      *tree_view);
411 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
412 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
413                                                          gpointer          data);
414 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
415                                                          GdkEventAny      *event,
416                                                          GtkTreeView      *tree_view);
417 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
418                                                          GdkEventButton   *event,
419                                                          GtkTreeView      *tree_view);
420 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
421                                                          GdkEventScroll   *event,
422                                                          GtkTreeView      *tree_view);
423 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
424                                                          GdkEventKey      *event,
425                                                          GtkTreeView      *tree_view);
426 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
427                                                          GtkTreeView      *tree_view,
428                                                          gboolean          up);
429 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
430                                                          gint              column,
431                                                          const gchar      *key,
432                                                          GtkTreeIter      *iter,
433                                                          gpointer          search_data);
434 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
435                                                          GtkTreeSelection *selection,
436                                                          GtkTreeIter      *iter,
437                                                          const gchar      *text,
438                                                          gint             *count,
439                                                          gint              n);
440 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
441                                                          GtkTreeView      *tree_view);
442 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
443                                                          GtkWidget        *child_widget,
444                                                          gint              x,
445                                                          gint              y,
446                                                          gint              width,
447                                                          gint              height);
448 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
449                                                          GtkTreePath      *cursor_path);
450 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
451                                               GtkTreeViewColumn *column,
452                                               GtkTreePath       *path,
453                                               GtkCellEditable   *cell_editable,
454                                               GdkRectangle      *cell_area,
455                                               GdkEvent          *event,
456                                               guint              flags);
457 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
458                                                          gboolean     cancel_editing);
459 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
460                                                              gboolean     keybinding);
461 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
462 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
463                                                          GtkTreeViewColumn *column,
464                                                          gint               drop_position);
465
466 /* GtkBuildable */
467 static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
468                                                GtkBuilder  *builder,
469                                                GObject     *child,
470                                                const gchar *type);
471 static void gtk_tree_view_buildable_init      (GtkBuildableIface *iface);
472
473
474 static gboolean scroll_row_timeout                   (gpointer     data);
475 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
476 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
477
478 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
479
480 \f
481
482 /* GType Methods
483  */
484
485 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
486                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
487                                                 gtk_tree_view_buildable_init))
488
489 static void
490 gtk_tree_view_class_init (GtkTreeViewClass *class)
491 {
492   GObjectClass *o_class;
493   GtkObjectClass *object_class;
494   GtkWidgetClass *widget_class;
495   GtkContainerClass *container_class;
496   GtkBindingSet *binding_set;
497
498   binding_set = gtk_binding_set_by_class (class);
499
500   o_class = (GObjectClass *) class;
501   object_class = (GtkObjectClass *) class;
502   widget_class = (GtkWidgetClass *) class;
503   container_class = (GtkContainerClass *) class;
504
505   /* GObject signals */
506   o_class->set_property = gtk_tree_view_set_property;
507   o_class->get_property = gtk_tree_view_get_property;
508   o_class->finalize = gtk_tree_view_finalize;
509
510   /* GtkObject signals */
511   object_class->destroy = gtk_tree_view_destroy;
512
513   /* GtkWidget signals */
514   widget_class->map = gtk_tree_view_map;
515   widget_class->realize = gtk_tree_view_realize;
516   widget_class->unrealize = gtk_tree_view_unrealize;
517   widget_class->size_request = gtk_tree_view_size_request;
518   widget_class->size_allocate = gtk_tree_view_size_allocate;
519   widget_class->button_press_event = gtk_tree_view_button_press;
520   widget_class->button_release_event = gtk_tree_view_button_release;
521   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
522   /*widget_class->configure_event = gtk_tree_view_configure;*/
523   widget_class->motion_notify_event = gtk_tree_view_motion;
524   widget_class->expose_event = gtk_tree_view_expose;
525   widget_class->key_press_event = gtk_tree_view_key_press;
526   widget_class->key_release_event = gtk_tree_view_key_release;
527   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
528   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
529   widget_class->focus_out_event = gtk_tree_view_focus_out;
530   widget_class->drag_begin = gtk_tree_view_drag_begin;
531   widget_class->drag_end = gtk_tree_view_drag_end;
532   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
533   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
534   widget_class->drag_leave = gtk_tree_view_drag_leave;
535   widget_class->drag_motion = gtk_tree_view_drag_motion;
536   widget_class->drag_drop = gtk_tree_view_drag_drop;
537   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
538   widget_class->focus = gtk_tree_view_focus;
539   widget_class->grab_focus = gtk_tree_view_grab_focus;
540   widget_class->style_set = gtk_tree_view_style_set;
541   widget_class->grab_notify = gtk_tree_view_grab_notify;
542   widget_class->state_changed = gtk_tree_view_state_changed;
543
544   /* GtkContainer signals */
545   container_class->remove = gtk_tree_view_remove;
546   container_class->forall = gtk_tree_view_forall;
547   container_class->set_focus_child = gtk_tree_view_set_focus_child;
548
549   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
550   class->move_cursor = gtk_tree_view_real_move_cursor;
551   class->select_all = gtk_tree_view_real_select_all;
552   class->unselect_all = gtk_tree_view_real_unselect_all;
553   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
554   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
555   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
556   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
557   class->start_interactive_search = gtk_tree_view_start_interactive_search;
558
559   /* Properties */
560
561   g_object_class_install_property (o_class,
562                                    PROP_MODEL,
563                                    g_param_spec_object ("model",
564                                                         P_("TreeView Model"),
565                                                         P_("The model for the tree view"),
566                                                         GTK_TYPE_TREE_MODEL,
567                                                         GTK_PARAM_READWRITE));
568
569   g_object_class_install_property (o_class,
570                                    PROP_HADJUSTMENT,
571                                    g_param_spec_object ("hadjustment",
572                                                         P_("Horizontal Adjustment"),
573                                                         P_("Horizontal Adjustment for the widget"),
574                                                         GTK_TYPE_ADJUSTMENT,
575                                                         GTK_PARAM_READWRITE));
576
577   g_object_class_install_property (o_class,
578                                    PROP_VADJUSTMENT,
579                                    g_param_spec_object ("vadjustment",
580                                                         P_("Vertical Adjustment"),
581                                                         P_("Vertical Adjustment for the widget"),
582                                                         GTK_TYPE_ADJUSTMENT,
583                                                         GTK_PARAM_READWRITE));
584
585   g_object_class_install_property (o_class,
586                                    PROP_HEADERS_VISIBLE,
587                                    g_param_spec_boolean ("headers-visible",
588                                                          P_("Headers Visible"),
589                                                          P_("Show the column header buttons"),
590                                                          TRUE,
591                                                          GTK_PARAM_READWRITE));
592
593   g_object_class_install_property (o_class,
594                                    PROP_HEADERS_CLICKABLE,
595                                    g_param_spec_boolean ("headers-clickable",
596                                                          P_("Headers Clickable"),
597                                                          P_("Column headers respond to click events"),
598                                                          TRUE,
599                                                          GTK_PARAM_READWRITE));
600
601   g_object_class_install_property (o_class,
602                                    PROP_EXPANDER_COLUMN,
603                                    g_param_spec_object ("expander-column",
604                                                         P_("Expander Column"),
605                                                         P_("Set the column for the expander column"),
606                                                         GTK_TYPE_TREE_VIEW_COLUMN,
607                                                         GTK_PARAM_READWRITE));
608
609   g_object_class_install_property (o_class,
610                                    PROP_REORDERABLE,
611                                    g_param_spec_boolean ("reorderable",
612                                                          P_("Reorderable"),
613                                                          P_("View is reorderable"),
614                                                          FALSE,
615                                                          GTK_PARAM_READWRITE));
616
617   g_object_class_install_property (o_class,
618                                    PROP_RULES_HINT,
619                                    g_param_spec_boolean ("rules-hint",
620                                                          P_("Rules Hint"),
621                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
622                                                          FALSE,
623                                                          GTK_PARAM_READWRITE));
624
625     g_object_class_install_property (o_class,
626                                      PROP_ENABLE_SEARCH,
627                                      g_param_spec_boolean ("enable-search",
628                                                            P_("Enable Search"),
629                                                            P_("View allows user to search through columns interactively"),
630                                                            TRUE,
631                                                            GTK_PARAM_READWRITE));
632
633     g_object_class_install_property (o_class,
634                                      PROP_SEARCH_COLUMN,
635                                      g_param_spec_int ("search-column",
636                                                        P_("Search Column"),
637                                                        P_("Model column to search through when searching through code"),
638                                                        -1,
639                                                        G_MAXINT,
640                                                        -1,
641                                                        GTK_PARAM_READWRITE));
642
643     /**
644      * GtkTreeView:fixed-height-mode:
645      *
646      * Setting the ::fixed-height-mode property to %TRUE speeds up 
647      * #GtkTreeView by assuming that all rows have the same height. 
648      * Only enable this option if all rows are the same height.  
649      * Please see gtk_tree_view_set_fixed_height_mode() for more 
650      * information on this option.
651      *
652      * Since: 2.4
653      **/
654     g_object_class_install_property (o_class,
655                                      PROP_FIXED_HEIGHT_MODE,
656                                      g_param_spec_boolean ("fixed-height-mode",
657                                                            P_("Fixed Height Mode"),
658                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
659                                                            FALSE,
660                                                            GTK_PARAM_READWRITE));
661     
662     /**
663      * GtkTreeView:hover-selection:
664      * 
665      * Enables of disables the hover selection mode of @tree_view.
666      * Hover selection makes the selected row follow the pointer.
667      * Currently, this works only for the selection modes 
668      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
669      *
670      * This mode is primarily indended for treeviews in popups, e.g.
671      * in #GtkComboBox or #GtkEntryCompletion.
672      *
673      * Since: 2.6
674      */
675     g_object_class_install_property (o_class,
676                                      PROP_HOVER_SELECTION,
677                                      g_param_spec_boolean ("hover-selection",
678                                                            P_("Hover Selection"),
679                                                            P_("Whether the selection should follow the pointer"),
680                                                            FALSE,
681                                                            GTK_PARAM_READWRITE));
682
683     /**
684      * GtkTreeView:hover-expand:
685      * 
686      * Enables of disables the hover expansion mode of @tree_view.
687      * Hover expansion makes rows expand or collaps if the pointer moves 
688      * over them.
689      *
690      * This mode is primarily indended for treeviews in popups, e.g.
691      * in #GtkComboBox or #GtkEntryCompletion.
692      *
693      * Since: 2.6
694      */
695     g_object_class_install_property (o_class,
696                                      PROP_HOVER_EXPAND,
697                                      g_param_spec_boolean ("hover-expand",
698                                                            P_("Hover Expand"),
699                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
700                                                            FALSE,
701                                                            GTK_PARAM_READWRITE));
702
703     /**
704      * GtkTreeView:show-expanders:
705      *
706      * %TRUE if the view has expanders.
707      *
708      * Since: 2.12
709      */
710     g_object_class_install_property (o_class,
711                                      PROP_SHOW_EXPANDERS,
712                                      g_param_spec_boolean ("show-expanders",
713                                                            P_("Show Expanders"),
714                                                            P_("View has expanders"),
715                                                            TRUE,
716                                                            GTK_PARAM_READWRITE));
717
718     /**
719      * GtkTreeView:level-indentation:
720      *
721      * Extra indentation for each level.
722      *
723      * Since: 2.12
724      */
725     g_object_class_install_property (o_class,
726                                      PROP_LEVEL_INDENTATION,
727                                      g_param_spec_int ("level-indentation",
728                                                        P_("Level Indentation"),
729                                                        P_("Extra indentation for each level"),
730                                                        0,
731                                                        G_MAXINT,
732                                                        0,
733                                                        GTK_PARAM_READWRITE));
734
735     g_object_class_install_property (o_class,
736                                      PROP_RUBBER_BANDING,
737                                      g_param_spec_boolean ("rubber-banding",
738                                                            P_("Rubber Banding"),
739                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
740                                                            FALSE,
741                                                            GTK_PARAM_READWRITE));
742
743     g_object_class_install_property (o_class,
744                                      PROP_ENABLE_GRID_LINES,
745                                      g_param_spec_enum ("enable-grid-lines",
746                                                         P_("Enable Grid Lines"),
747                                                         P_("Whether grid lines should be drawn in the tree view"),
748                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
749                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
750                                                         GTK_PARAM_READWRITE));
751
752     g_object_class_install_property (o_class,
753                                      PROP_ENABLE_TREE_LINES,
754                                      g_param_spec_boolean ("enable-tree-lines",
755                                                            P_("Enable Tree Lines"),
756                                                            P_("Whether tree lines should be drawn in the tree view"),
757                                                            FALSE,
758                                                            GTK_PARAM_READWRITE));
759
760     g_object_class_install_property (o_class,
761                                      PROP_TOOLTIP_COLUMN,
762                                      g_param_spec_int ("tooltip-column",
763                                                        P_("Tooltip Column"),
764                                                        P_("The column in the model containing the tooltip texts for the rows"),
765                                                        -1,
766                                                        G_MAXINT,
767                                                        -1,
768                                                        GTK_PARAM_READWRITE));
769
770   /* Style properties */
771 #define _TREE_VIEW_EXPANDER_SIZE 12
772 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
773 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
774     
775   gtk_widget_class_install_style_property (widget_class,
776                                            g_param_spec_int ("expander-size",
777                                                              P_("Expander Size"),
778                                                              P_("Size of the expander arrow"),
779                                                              0,
780                                                              G_MAXINT,
781                                                              _TREE_VIEW_EXPANDER_SIZE,
782                                                              GTK_PARAM_READABLE));
783
784   gtk_widget_class_install_style_property (widget_class,
785                                            g_param_spec_int ("vertical-separator",
786                                                              P_("Vertical Separator Width"),
787                                                              P_("Vertical space between cells.  Must be an even number"),
788                                                              0,
789                                                              G_MAXINT,
790                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
791                                                              GTK_PARAM_READABLE));
792
793   gtk_widget_class_install_style_property (widget_class,
794                                            g_param_spec_int ("horizontal-separator",
795                                                              P_("Horizontal Separator Width"),
796                                                              P_("Horizontal space between cells.  Must be an even number"),
797                                                              0,
798                                                              G_MAXINT,
799                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
800                                                              GTK_PARAM_READABLE));
801
802   gtk_widget_class_install_style_property (widget_class,
803                                            g_param_spec_boolean ("allow-rules",
804                                                                  P_("Allow Rules"),
805                                                                  P_("Allow drawing of alternating color rows"),
806                                                                  TRUE,
807                                                                  GTK_PARAM_READABLE));
808
809   gtk_widget_class_install_style_property (widget_class,
810                                            g_param_spec_boolean ("indent-expanders",
811                                                                  P_("Indent Expanders"),
812                                                                  P_("Make the expanders indented"),
813                                                                  TRUE,
814                                                                  GTK_PARAM_READABLE));
815
816   gtk_widget_class_install_style_property (widget_class,
817                                            g_param_spec_boxed ("even-row-color",
818                                                                P_("Even Row Color"),
819                                                                P_("Color to use for even rows"),
820                                                                GDK_TYPE_COLOR,
821                                                                GTK_PARAM_READABLE));
822
823   gtk_widget_class_install_style_property (widget_class,
824                                            g_param_spec_boxed ("odd-row-color",
825                                                                P_("Odd Row Color"),
826                                                                P_("Color to use for odd rows"),
827                                                                GDK_TYPE_COLOR,
828                                                                GTK_PARAM_READABLE));
829
830   gtk_widget_class_install_style_property (widget_class,
831                                            g_param_spec_boolean ("row-ending-details",
832                                                                  P_("Row Ending details"),
833                                                                  P_("Enable extended row background theming"),
834                                                                  FALSE,
835                                                                  GTK_PARAM_READABLE));
836
837   gtk_widget_class_install_style_property (widget_class,
838                                            g_param_spec_int ("grid-line-width",
839                                                              P_("Grid line width"),
840                                                              P_("Width, in pixels, of the tree view grid lines"),
841                                                              0, G_MAXINT, 1,
842                                                              GTK_PARAM_READABLE));
843
844   gtk_widget_class_install_style_property (widget_class,
845                                            g_param_spec_int ("tree-line-width",
846                                                              P_("Tree line width"),
847                                                              P_("Width, in pixels, of the tree view lines"),
848                                                              0, G_MAXINT, 1,
849                                                              GTK_PARAM_READABLE));
850
851   gtk_widget_class_install_style_property (widget_class,
852                                            g_param_spec_string ("grid-line-pattern",
853                                                                 P_("Grid line pattern"),
854                                                                 P_("Dash pattern used to draw the tree view grid lines"),
855                                                                 "\1\1",
856                                                                 GTK_PARAM_READABLE));
857
858   gtk_widget_class_install_style_property (widget_class,
859                                            g_param_spec_string ("tree-line-pattern",
860                                                                 P_("Tree line pattern"),
861                                                                 P_("Dash pattern used to draw the tree view lines"),
862                                                                 "\1\1",
863                                                                 GTK_PARAM_READABLE));
864
865   /* Signals */
866   widget_class->set_scroll_adjustments_signal =
867     g_signal_new (I_("set_scroll_adjustments"),
868                   G_TYPE_FROM_CLASS (o_class),
869                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
870                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
871                   NULL, NULL,
872                   _gtk_marshal_VOID__OBJECT_OBJECT,
873                   G_TYPE_NONE, 2,
874                   GTK_TYPE_ADJUSTMENT,
875                   GTK_TYPE_ADJUSTMENT);
876
877   /**
878    * GtkTreeView::row-activated:
879    * @tree_view: the object on which the signal is emitted
880    * @path: the #GtkTreePath for the activated row
881    * @column: the #GtkTreeViewColumn in which the activation occurred
882    *
883    * The "row-activated" signal is emitted when the method
884    * gtk_tree_view_row_activated() is called or the user double clicks 
885    * a treeview row. It is also emitted when a non-editable row is 
886    * selected and one of the keys: Space, Shift+Space, Return or 
887    * Enter is pressed.
888    * 
889    * For selection handling refer to the <link linkend="TreeWidget">tree 
890    * widget conceptual overview</link> as well as #GtkTreeSelection.
891    */
892   tree_view_signals[ROW_ACTIVATED] =
893     g_signal_new (I_("row_activated"),
894                   G_TYPE_FROM_CLASS (o_class),
895                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
896                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
897                   NULL, NULL,
898                   _gtk_marshal_VOID__BOXED_OBJECT,
899                   G_TYPE_NONE, 2,
900                   GTK_TYPE_TREE_PATH,
901                   GTK_TYPE_TREE_VIEW_COLUMN);
902
903   /**
904    * GtkTreeView::test-expand-row:
905    * @tree_view: the object on which the signal is emitted
906    * @iter: the tree iter of the row to expand
907    * @path: a tree path that points to the row 
908    * 
909    * The given row is about to be expanded (show its children nodes). Use this
910    * signal if you need to control the expandability of individual rows.
911    *
912    * Returns: %FALSE to allow expansion, %TRUE to reject
913    */
914   tree_view_signals[TEST_EXPAND_ROW] =
915     g_signal_new (I_("test-expand-row"),
916                   G_TYPE_FROM_CLASS (o_class),
917                   G_SIGNAL_RUN_LAST,
918                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
919                   _gtk_boolean_handled_accumulator, NULL,
920                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
921                   G_TYPE_BOOLEAN, 2,
922                   GTK_TYPE_TREE_ITER,
923                   GTK_TYPE_TREE_PATH);
924
925   /**
926    * GtkTreeView::test-collapse-row:
927    * @tree_view: the object on which the signal is emitted
928    * @iter: the tree iter of the row to collapse
929    * @path: a tree path that points to the row 
930    * 
931    * The given row is about to be collapsed (hide its children nodes). Use this
932    * signal if you need to control the collapsibility of individual rows.
933    *
934    * Returns: %FALSE to allow collapsing, %TRUE to reject
935    */
936   tree_view_signals[TEST_COLLAPSE_ROW] =
937     g_signal_new (I_("test-collapse-row"),
938                   G_TYPE_FROM_CLASS (o_class),
939                   G_SIGNAL_RUN_LAST,
940                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
941                   _gtk_boolean_handled_accumulator, NULL,
942                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
943                   G_TYPE_BOOLEAN, 2,
944                   GTK_TYPE_TREE_ITER,
945                   GTK_TYPE_TREE_PATH);
946
947   /**
948    * GtkTreeView::row-expanded:
949    * @tree_view: the object on which the signal is emitted
950    * @iter: the tree iter of the expanded row
951    * @path: a tree path that points to the row 
952    * 
953    * The given row has been expanded (child nodes are shown).
954    */
955   tree_view_signals[ROW_EXPANDED] =
956     g_signal_new (I_("row-expanded"),
957                   G_TYPE_FROM_CLASS (o_class),
958                   G_SIGNAL_RUN_LAST,
959                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
960                   NULL, NULL,
961                   _gtk_marshal_VOID__BOXED_BOXED,
962                   G_TYPE_NONE, 2,
963                   GTK_TYPE_TREE_ITER,
964                   GTK_TYPE_TREE_PATH);
965
966   /**
967    * GtkTreeView::row-collapsed:
968    * @tree_view: the object on which the signal is emitted
969    * @iter: the tree iter of the collapsed row
970    * @path: a tree path that points to the row 
971    * 
972    * The given row has been collapsed (child nodes are hidden).
973    */
974   tree_view_signals[ROW_COLLAPSED] =
975     g_signal_new (I_("row-collapsed"),
976                   G_TYPE_FROM_CLASS (o_class),
977                   G_SIGNAL_RUN_LAST,
978                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
979                   NULL, NULL,
980                   _gtk_marshal_VOID__BOXED_BOXED,
981                   G_TYPE_NONE, 2,
982                   GTK_TYPE_TREE_ITER,
983                   GTK_TYPE_TREE_PATH);
984
985   /**
986    * GtkTreeView::columns-changed:
987    * @tree_view: the object on which the signal is emitted 
988    * 
989    * The number of columns of the treeview has changed.
990    */
991   tree_view_signals[COLUMNS_CHANGED] =
992     g_signal_new (I_("columns-changed"),
993                   G_TYPE_FROM_CLASS (o_class),
994                   G_SIGNAL_RUN_LAST,
995                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
996                   NULL, NULL,
997                   _gtk_marshal_NONE__NONE,
998                   G_TYPE_NONE, 0);
999
1000   /**
1001    * GtkTreeView::cursor-changed:
1002    * @tree_view: the object on which the signal is emitted
1003    * 
1004    * The position of the cursor (focused cell) has changed.
1005    */
1006   tree_view_signals[CURSOR_CHANGED] =
1007     g_signal_new (I_("cursor-changed"),
1008                   G_TYPE_FROM_CLASS (o_class),
1009                   G_SIGNAL_RUN_LAST,
1010                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1011                   NULL, NULL,
1012                   _gtk_marshal_NONE__NONE,
1013                   G_TYPE_NONE, 0);
1014
1015   tree_view_signals[MOVE_CURSOR] =
1016     g_signal_new (I_("move_cursor"),
1017                   G_TYPE_FROM_CLASS (object_class),
1018                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1019                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1020                   NULL, NULL,
1021                   _gtk_marshal_BOOLEAN__ENUM_INT,
1022                   G_TYPE_BOOLEAN, 2,
1023                   GTK_TYPE_MOVEMENT_STEP,
1024                   G_TYPE_INT);
1025
1026   tree_view_signals[SELECT_ALL] =
1027     g_signal_new (I_("select_all"),
1028                   G_TYPE_FROM_CLASS (object_class),
1029                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1030                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1031                   NULL, NULL,
1032                   _gtk_marshal_BOOLEAN__NONE,
1033                   G_TYPE_BOOLEAN, 0);
1034
1035   tree_view_signals[UNSELECT_ALL] =
1036     g_signal_new (I_("unselect_all"),
1037                   G_TYPE_FROM_CLASS (object_class),
1038                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1039                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1040                   NULL, NULL,
1041                   _gtk_marshal_BOOLEAN__NONE,
1042                   G_TYPE_BOOLEAN, 0);
1043
1044   tree_view_signals[SELECT_CURSOR_ROW] =
1045     g_signal_new (I_("select_cursor_row"),
1046                   G_TYPE_FROM_CLASS (object_class),
1047                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1048                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1049                   NULL, NULL,
1050                   _gtk_marshal_BOOLEAN__BOOLEAN,
1051                   G_TYPE_BOOLEAN, 1,
1052                   G_TYPE_BOOLEAN);
1053
1054   tree_view_signals[TOGGLE_CURSOR_ROW] =
1055     g_signal_new (I_("toggle_cursor_row"),
1056                   G_TYPE_FROM_CLASS (object_class),
1057                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1058                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1059                   NULL, NULL,
1060                   _gtk_marshal_BOOLEAN__NONE,
1061                   G_TYPE_BOOLEAN, 0);
1062
1063   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1064     g_signal_new (I_("expand_collapse_cursor_row"),
1065                   G_TYPE_FROM_CLASS (object_class),
1066                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1067                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1068                   NULL, NULL,
1069                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1070                   G_TYPE_BOOLEAN, 3,
1071                   G_TYPE_BOOLEAN,
1072                   G_TYPE_BOOLEAN,
1073                   G_TYPE_BOOLEAN);
1074
1075   tree_view_signals[SELECT_CURSOR_PARENT] =
1076     g_signal_new (I_("select_cursor_parent"),
1077                   G_TYPE_FROM_CLASS (object_class),
1078                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1079                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1080                   NULL, NULL,
1081                   _gtk_marshal_BOOLEAN__NONE,
1082                   G_TYPE_BOOLEAN, 0);
1083
1084   tree_view_signals[START_INTERACTIVE_SEARCH] =
1085     g_signal_new (I_("start_interactive_search"),
1086                   G_TYPE_FROM_CLASS (object_class),
1087                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1088                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1089                   NULL, NULL,
1090                   _gtk_marshal_BOOLEAN__NONE,
1091                   G_TYPE_BOOLEAN, 0);
1092
1093   /* Key bindings */
1094   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
1095                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1096   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
1097                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1098
1099   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
1100                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1101   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
1102                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1103
1104   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
1105                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1106
1107   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
1108                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1109
1110   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
1111                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1112   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
1113                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1114
1115   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
1116                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1117   gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
1118                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1119
1120   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
1121                                   GTK_MOVEMENT_PAGES, -1);
1122   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
1123                                   GTK_MOVEMENT_PAGES, -1);
1124
1125   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
1126                                   GTK_MOVEMENT_PAGES, 1);
1127   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
1128                                   GTK_MOVEMENT_PAGES, 1);
1129
1130
1131   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move_cursor", 2,
1132                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1133                                 G_TYPE_INT, 1);
1134
1135   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move_cursor", 2,
1136                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1137                                 G_TYPE_INT, -1);
1138
1139   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move_cursor", 2,
1140                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1141                                 G_TYPE_INT, 1);
1142
1143   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move_cursor", 2,
1144                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1145                                 G_TYPE_INT, -1);
1146
1147   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
1148                                 "move_cursor", 2,
1149                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1150                                 G_TYPE_INT, 1);
1151
1152   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
1153                                 "move_cursor", 2,
1154                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1155                                 G_TYPE_INT, -1);
1156
1157   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1158                                 "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_KP_Left, 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_space, GDK_CONTROL_MASK, "toggle_cursor_row", 0);
1168
1169   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
1170   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select_all", 0);
1171
1172   gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect_all", 0);
1173   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect_all", 0);
1174
1175   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select_cursor_row", 1,
1176                                 G_TYPE_BOOLEAN, TRUE);
1177
1178   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 1,
1179                                 G_TYPE_BOOLEAN, TRUE);
1180   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select_cursor_row", 1,
1181                                 G_TYPE_BOOLEAN, TRUE);
1182   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select_cursor_row", 1,
1183                                 G_TYPE_BOOLEAN, TRUE);
1184   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select_cursor_row", 1,
1185                                 G_TYPE_BOOLEAN, TRUE);
1186
1187   /* expand and collapse rows */
1188   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3,
1189                                 G_TYPE_BOOLEAN, TRUE,
1190                                 G_TYPE_BOOLEAN, TRUE,
1191                                 G_TYPE_BOOLEAN, FALSE);
1192
1193   gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
1194                                 "expand_collapse_cursor_row", 3,
1195                                 G_TYPE_BOOLEAN, TRUE,
1196                                 G_TYPE_BOOLEAN, TRUE,
1197                                 G_TYPE_BOOLEAN, TRUE);
1198   gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
1199                                 "expand_collapse_cursor_row", 3,
1200                                 G_TYPE_BOOLEAN, TRUE,
1201                                 G_TYPE_BOOLEAN, TRUE,
1202                                 G_TYPE_BOOLEAN, TRUE);
1203
1204   gtk_binding_entry_add_signal (binding_set, GDK_slash, 0,
1205                                 "expand_collapse_cursor_row", 3,
1206                                 G_TYPE_BOOLEAN, TRUE,
1207                                 G_TYPE_BOOLEAN, FALSE,
1208                                 G_TYPE_BOOLEAN, FALSE);
1209   gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
1210                                 "expand_collapse_cursor_row", 3,
1211                                 G_TYPE_BOOLEAN, TRUE,
1212                                 G_TYPE_BOOLEAN, FALSE,
1213                                 G_TYPE_BOOLEAN, FALSE);
1214
1215   /* Not doable on US keyboards */
1216   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1217                                 G_TYPE_BOOLEAN, TRUE,
1218                                 G_TYPE_BOOLEAN, TRUE,
1219                                 G_TYPE_BOOLEAN, TRUE);
1220   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand_collapse_cursor_row", 3,
1221                                 G_TYPE_BOOLEAN, TRUE,
1222                                 G_TYPE_BOOLEAN, TRUE,
1223                                 G_TYPE_BOOLEAN, FALSE);
1224   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1225                                 G_TYPE_BOOLEAN, TRUE,
1226                                 G_TYPE_BOOLEAN, TRUE,
1227                                 G_TYPE_BOOLEAN, TRUE);
1228   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1229                                 G_TYPE_BOOLEAN, TRUE,
1230                                 G_TYPE_BOOLEAN, TRUE,
1231                                 G_TYPE_BOOLEAN, TRUE);
1232   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
1233                                 "expand_collapse_cursor_row", 3,
1234                                 G_TYPE_BOOLEAN, FALSE,
1235                                 G_TYPE_BOOLEAN, TRUE,
1236                                 G_TYPE_BOOLEAN, TRUE);
1237   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
1238                                 "expand_collapse_cursor_row", 3,
1239                                 G_TYPE_BOOLEAN, FALSE,
1240                                 G_TYPE_BOOLEAN, TRUE,
1241                                 G_TYPE_BOOLEAN, TRUE);
1242   gtk_binding_entry_add_signal (binding_set, GDK_Right,
1243                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1244                                 "expand_collapse_cursor_row", 3,
1245                                 G_TYPE_BOOLEAN, FALSE,
1246                                 G_TYPE_BOOLEAN, TRUE,
1247                                 G_TYPE_BOOLEAN, TRUE);
1248   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
1249                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1250                                 "expand_collapse_cursor_row", 3,
1251                                 G_TYPE_BOOLEAN, FALSE,
1252                                 G_TYPE_BOOLEAN, TRUE,
1253                                 G_TYPE_BOOLEAN, TRUE);
1254
1255   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand_collapse_cursor_row", 3,
1256                                 G_TYPE_BOOLEAN, TRUE,
1257                                 G_TYPE_BOOLEAN, FALSE,
1258                                 G_TYPE_BOOLEAN, FALSE);
1259   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1260                                 G_TYPE_BOOLEAN, TRUE,
1261                                 G_TYPE_BOOLEAN, FALSE,
1262                                 G_TYPE_BOOLEAN, TRUE);
1263   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand_collapse_cursor_row", 3,
1264                                 G_TYPE_BOOLEAN, TRUE,
1265                                 G_TYPE_BOOLEAN, FALSE,
1266                                 G_TYPE_BOOLEAN, FALSE);
1267   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1268                                 G_TYPE_BOOLEAN, TRUE,
1269                                 G_TYPE_BOOLEAN, FALSE,
1270                                 G_TYPE_BOOLEAN, TRUE);
1271   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
1272                                 "expand_collapse_cursor_row", 3,
1273                                 G_TYPE_BOOLEAN, FALSE,
1274                                 G_TYPE_BOOLEAN, FALSE,
1275                                 G_TYPE_BOOLEAN, TRUE);
1276   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
1277                                 "expand_collapse_cursor_row", 3,
1278                                 G_TYPE_BOOLEAN, FALSE,
1279                                 G_TYPE_BOOLEAN, FALSE,
1280                                 G_TYPE_BOOLEAN, TRUE);
1281   gtk_binding_entry_add_signal (binding_set, GDK_Left,
1282                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1283                                 "expand_collapse_cursor_row", 3,
1284                                 G_TYPE_BOOLEAN, FALSE,
1285                                 G_TYPE_BOOLEAN, FALSE,
1286                                 G_TYPE_BOOLEAN, TRUE);
1287   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
1288                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1289                                 "expand_collapse_cursor_row", 3,
1290                                 G_TYPE_BOOLEAN, FALSE,
1291                                 G_TYPE_BOOLEAN, FALSE,
1292                                 G_TYPE_BOOLEAN, TRUE);
1293
1294   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
1295   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select_cursor_parent", 0);
1296
1297   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start_interactive_search", 0);
1298
1299   gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start_interactive_search", 0);
1300
1301   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1302 }
1303
1304 static void
1305 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1306 {
1307   iface->add_child = gtk_tree_view_buildable_add_child;
1308 }
1309
1310 static void
1311 gtk_tree_view_init (GtkTreeView *tree_view)
1312 {
1313   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1314
1315   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
1316
1317   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1318
1319   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1320                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1321                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1322
1323   /* We need some padding */
1324   tree_view->priv->dy = 0;
1325   tree_view->priv->cursor_offset = 0;
1326   tree_view->priv->n_columns = 0;
1327   tree_view->priv->header_height = 1;
1328   tree_view->priv->x_drag = 0;
1329   tree_view->priv->drag_pos = -1;
1330   tree_view->priv->header_has_focus = FALSE;
1331   tree_view->priv->pressed_button = -1;
1332   tree_view->priv->press_start_x = -1;
1333   tree_view->priv->press_start_y = -1;
1334   tree_view->priv->reorderable = FALSE;
1335   tree_view->priv->presize_handler_timer = 0;
1336   tree_view->priv->scroll_sync_timer = 0;
1337   tree_view->priv->fixed_height = -1;
1338   tree_view->priv->fixed_height_mode = FALSE;
1339   tree_view->priv->fixed_height_check = 0;
1340   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1341   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1342   tree_view->priv->enable_search = TRUE;
1343   tree_view->priv->search_column = -1;
1344   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1345   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1346   tree_view->priv->search_custom_entry_set = FALSE;
1347   tree_view->priv->typeselect_flush_timeout = 0;
1348   tree_view->priv->init_hadjust_value = TRUE;    
1349   tree_view->priv->width = 0;
1350           
1351   tree_view->priv->hover_selection = FALSE;
1352   tree_view->priv->hover_expand = FALSE;
1353
1354   tree_view->priv->level_indentation = 0;
1355
1356   tree_view->priv->rubber_banding_enable = FALSE;
1357
1358   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1359   tree_view->priv->tree_lines_enabled = FALSE;
1360
1361   tree_view->priv->tooltip_column = -1;
1362 }
1363
1364 \f
1365
1366 /* GObject Methods
1367  */
1368
1369 static void
1370 gtk_tree_view_set_property (GObject         *object,
1371                             guint            prop_id,
1372                             const GValue    *value,
1373                             GParamSpec      *pspec)
1374 {
1375   GtkTreeView *tree_view;
1376
1377   tree_view = GTK_TREE_VIEW (object);
1378
1379   switch (prop_id)
1380     {
1381     case PROP_MODEL:
1382       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1383       break;
1384     case PROP_HADJUSTMENT:
1385       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1386       break;
1387     case PROP_VADJUSTMENT:
1388       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1389       break;
1390     case PROP_HEADERS_VISIBLE:
1391       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1392       break;
1393     case PROP_HEADERS_CLICKABLE:
1394       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1395       break;
1396     case PROP_EXPANDER_COLUMN:
1397       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1398       break;
1399     case PROP_REORDERABLE:
1400       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1401       break;
1402     case PROP_RULES_HINT:
1403       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1404       break;
1405     case PROP_ENABLE_SEARCH:
1406       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1407       break;
1408     case PROP_SEARCH_COLUMN:
1409       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1410       break;
1411     case PROP_FIXED_HEIGHT_MODE:
1412       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1413       break;
1414     case PROP_HOVER_SELECTION:
1415       tree_view->priv->hover_selection = g_value_get_boolean (value);
1416       break;
1417     case PROP_HOVER_EXPAND:
1418       tree_view->priv->hover_expand = g_value_get_boolean (value);
1419       break;
1420     case PROP_SHOW_EXPANDERS:
1421       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1422       break;
1423     case PROP_LEVEL_INDENTATION:
1424       tree_view->priv->level_indentation = g_value_get_int (value);
1425       break;
1426     case PROP_RUBBER_BANDING:
1427       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1428       break;
1429     case PROP_ENABLE_GRID_LINES:
1430       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1431       break;
1432     case PROP_ENABLE_TREE_LINES:
1433       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1434       break;
1435     case PROP_TOOLTIP_COLUMN:
1436       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1437       break;
1438     default:
1439       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1440       break;
1441     }
1442 }
1443
1444 static void
1445 gtk_tree_view_get_property (GObject    *object,
1446                             guint       prop_id,
1447                             GValue     *value,
1448                             GParamSpec *pspec)
1449 {
1450   GtkTreeView *tree_view;
1451
1452   tree_view = GTK_TREE_VIEW (object);
1453
1454   switch (prop_id)
1455     {
1456     case PROP_MODEL:
1457       g_value_set_object (value, tree_view->priv->model);
1458       break;
1459     case PROP_HADJUSTMENT:
1460       g_value_set_object (value, tree_view->priv->hadjustment);
1461       break;
1462     case PROP_VADJUSTMENT:
1463       g_value_set_object (value, tree_view->priv->vadjustment);
1464       break;
1465     case PROP_HEADERS_VISIBLE:
1466       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1467       break;
1468     case PROP_HEADERS_CLICKABLE:
1469       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1470       break;
1471     case PROP_EXPANDER_COLUMN:
1472       g_value_set_object (value, tree_view->priv->expander_column);
1473       break;
1474     case PROP_REORDERABLE:
1475       g_value_set_boolean (value, tree_view->priv->reorderable);
1476       break;
1477     case PROP_RULES_HINT:
1478       g_value_set_boolean (value, tree_view->priv->has_rules);
1479       break;
1480     case PROP_ENABLE_SEARCH:
1481       g_value_set_boolean (value, tree_view->priv->enable_search);
1482       break;
1483     case PROP_SEARCH_COLUMN:
1484       g_value_set_int (value, tree_view->priv->search_column);
1485       break;
1486     case PROP_FIXED_HEIGHT_MODE:
1487       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1488       break;
1489     case PROP_HOVER_SELECTION:
1490       g_value_set_boolean (value, tree_view->priv->hover_selection);
1491       break;
1492     case PROP_HOVER_EXPAND:
1493       g_value_set_boolean (value, tree_view->priv->hover_expand);
1494       break;
1495     case PROP_SHOW_EXPANDERS:
1496       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1497       break;
1498     case PROP_LEVEL_INDENTATION:
1499       g_value_set_int (value, tree_view->priv->level_indentation);
1500       break;
1501     case PROP_RUBBER_BANDING:
1502       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1503       break;
1504     case PROP_ENABLE_GRID_LINES:
1505       g_value_set_enum (value, tree_view->priv->grid_lines);
1506       break;
1507     case PROP_ENABLE_TREE_LINES:
1508       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1509       break;
1510     case PROP_TOOLTIP_COLUMN:
1511       g_value_set_int (value, tree_view->priv->tooltip_column);
1512       break;
1513     default:
1514       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1515       break;
1516     }
1517 }
1518
1519 static void
1520 gtk_tree_view_finalize (GObject *object)
1521 {
1522   (* G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize) (object);
1523 }
1524
1525 \f
1526
1527 static void
1528 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1529                                    GtkBuilder  *builder,
1530                                    GObject     *child,
1531                                    const gchar *type)
1532 {
1533   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1534 }
1535
1536 /* GtkObject Methods
1537  */
1538
1539 static void
1540 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1541 {
1542   _gtk_rbtree_free (tree_view->priv->tree);
1543   
1544   tree_view->priv->tree = NULL;
1545   tree_view->priv->button_pressed_node = NULL;
1546   tree_view->priv->button_pressed_tree = NULL;
1547   tree_view->priv->prelight_tree = NULL;
1548   tree_view->priv->prelight_node = NULL;
1549   tree_view->priv->expanded_collapsed_node = NULL;
1550   tree_view->priv->expanded_collapsed_tree = NULL;
1551 }
1552
1553 static void
1554 gtk_tree_view_destroy (GtkObject *object)
1555 {
1556   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1557   GList *list;
1558
1559   gtk_tree_view_stop_editing (tree_view, TRUE);
1560
1561   if (tree_view->priv->columns != NULL)
1562     {
1563       list = tree_view->priv->columns;
1564       while (list)
1565         {
1566           GtkTreeViewColumn *column;
1567           column = GTK_TREE_VIEW_COLUMN (list->data);
1568           list = list->next;
1569           gtk_tree_view_remove_column (tree_view, column);
1570         }
1571       tree_view->priv->columns = NULL;
1572     }
1573
1574   if (tree_view->priv->tree != NULL)
1575     {
1576       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1577
1578       gtk_tree_view_free_rbtree (tree_view);
1579     }
1580
1581   if (tree_view->priv->selection != NULL)
1582     {
1583       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1584       g_object_unref (tree_view->priv->selection);
1585       tree_view->priv->selection = NULL;
1586     }
1587
1588   if (tree_view->priv->scroll_to_path != NULL)
1589     {
1590       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1591       tree_view->priv->scroll_to_path = NULL;
1592     }
1593
1594   if (tree_view->priv->drag_dest_row != NULL)
1595     {
1596       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1597       tree_view->priv->drag_dest_row = NULL;
1598     }
1599
1600   if (tree_view->priv->last_button_press != NULL)
1601     {
1602       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
1603       tree_view->priv->last_button_press = NULL;
1604     }
1605
1606   if (tree_view->priv->last_button_press_2 != NULL)
1607     {
1608       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
1609       tree_view->priv->last_button_press_2 = NULL;
1610     }
1611
1612   if (tree_view->priv->top_row != NULL)
1613     {
1614       gtk_tree_row_reference_free (tree_view->priv->top_row);
1615       tree_view->priv->top_row = NULL;
1616     }
1617
1618   if (tree_view->priv->column_drop_func_data &&
1619       tree_view->priv->column_drop_func_data_destroy)
1620     {
1621       (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
1622       tree_view->priv->column_drop_func_data = NULL;
1623     }
1624
1625   if (tree_view->priv->destroy_count_destroy &&
1626       tree_view->priv->destroy_count_data)
1627     {
1628       (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
1629       tree_view->priv->destroy_count_data = NULL;
1630     }
1631
1632   gtk_tree_row_reference_free (tree_view->priv->cursor);
1633   tree_view->priv->cursor = NULL;
1634
1635   gtk_tree_row_reference_free (tree_view->priv->anchor);
1636   tree_view->priv->anchor = NULL;
1637
1638   /* destroy interactive search dialog */
1639   if (tree_view->priv->search_window)
1640     {
1641       gtk_widget_destroy (tree_view->priv->search_window);
1642       tree_view->priv->search_window = NULL;
1643       tree_view->priv->search_entry = NULL;
1644       if (tree_view->priv->typeselect_flush_timeout)
1645         {
1646           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1647           tree_view->priv->typeselect_flush_timeout = 0;
1648         }
1649     }
1650
1651   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1652     {
1653       (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
1654       tree_view->priv->search_user_data = NULL;
1655     }
1656
1657   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1658     {
1659       (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
1660       tree_view->priv->search_position_user_data = NULL;
1661     }
1662
1663   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1664     {
1665       (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data);
1666       tree_view->priv->row_separator_data = NULL;
1667     }
1668   
1669   gtk_tree_view_set_model (tree_view, NULL);
1670
1671   if (tree_view->priv->hadjustment)
1672     {
1673       g_object_unref (tree_view->priv->hadjustment);
1674       tree_view->priv->hadjustment = NULL;
1675     }
1676   if (tree_view->priv->vadjustment)
1677     {
1678       g_object_unref (tree_view->priv->vadjustment);
1679       tree_view->priv->vadjustment = NULL;
1680     }
1681
1682   if (GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy)
1683     (* GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy) (object);
1684 }
1685
1686 \f
1687
1688 /* GtkWidget Methods
1689  */
1690
1691 /* GtkWidget::map helper */
1692 static void
1693 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1694 {
1695   GList *list;
1696
1697   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1698
1699   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1700     {
1701       GtkTreeViewColumn *column;
1702
1703       for (list = tree_view->priv->columns; list; list = list->next)
1704         {
1705           column = list->data;
1706           if (GTK_WIDGET_VISIBLE (column->button) &&
1707               !GTK_WIDGET_MAPPED (column->button))
1708             gtk_widget_map (column->button);
1709         }
1710       for (list = tree_view->priv->columns; list; list = list->next)
1711         {
1712           column = list->data;
1713           if (column->visible == FALSE)
1714             continue;
1715           if (column->resizable)
1716             {
1717               gdk_window_raise (column->window);
1718               gdk_window_show (column->window);
1719             }
1720           else
1721             gdk_window_hide (column->window);
1722         }
1723       gdk_window_show (tree_view->priv->header_window);
1724     }
1725 }
1726
1727 static void
1728 gtk_tree_view_map (GtkWidget *widget)
1729 {
1730   GList *tmp_list;
1731   GtkTreeView *tree_view;
1732
1733   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1734
1735   tree_view = GTK_TREE_VIEW (widget);
1736
1737   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1738
1739   tmp_list = tree_view->priv->children;
1740   while (tmp_list)
1741     {
1742       GtkTreeViewChild *child = tmp_list->data;
1743       tmp_list = tmp_list->next;
1744
1745       if (GTK_WIDGET_VISIBLE (child->widget))
1746         {
1747           if (!GTK_WIDGET_MAPPED (child->widget))
1748             gtk_widget_map (child->widget);
1749         }
1750     }
1751   gdk_window_show (tree_view->priv->bin_window);
1752
1753   gtk_tree_view_map_buttons (tree_view);
1754
1755   gdk_window_show (widget->window);
1756 }
1757
1758 static void
1759 gtk_tree_view_realize (GtkWidget *widget)
1760 {
1761   GList *tmp_list;
1762   GtkTreeView *tree_view;
1763   GdkWindowAttr attributes;
1764   gint attributes_mask;
1765
1766   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1767
1768   tree_view = GTK_TREE_VIEW (widget);
1769
1770   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1771
1772   /* Make the main, clipping window */
1773   attributes.window_type = GDK_WINDOW_CHILD;
1774   attributes.x = widget->allocation.x;
1775   attributes.y = widget->allocation.y;
1776   attributes.width = widget->allocation.width;
1777   attributes.height = widget->allocation.height;
1778   attributes.wclass = GDK_INPUT_OUTPUT;
1779   attributes.visual = gtk_widget_get_visual (widget);
1780   attributes.colormap = gtk_widget_get_colormap (widget);
1781   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1782
1783   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1784
1785   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1786                                    &attributes, attributes_mask);
1787   gdk_window_set_user_data (widget->window, widget);
1788
1789   /* Make the window for the tree */
1790   attributes.x = 0;
1791   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1792   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1793   attributes.height = widget->allocation.height;
1794   attributes.event_mask = GDK_EXPOSURE_MASK |
1795     GDK_SCROLL_MASK |
1796     GDK_POINTER_MOTION_MASK |
1797     GDK_ENTER_NOTIFY_MASK |
1798     GDK_LEAVE_NOTIFY_MASK |
1799     GDK_BUTTON_PRESS_MASK |
1800     GDK_BUTTON_RELEASE_MASK |
1801     gtk_widget_get_events (widget);
1802
1803   tree_view->priv->bin_window = gdk_window_new (widget->window,
1804                                                 &attributes, attributes_mask);
1805   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1806
1807   /* Make the column header window */
1808   attributes.x = 0;
1809   attributes.y = 0;
1810   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1811   attributes.height = tree_view->priv->header_height;
1812   attributes.event_mask = (GDK_EXPOSURE_MASK |
1813                            GDK_SCROLL_MASK |
1814                            GDK_BUTTON_PRESS_MASK |
1815                            GDK_BUTTON_RELEASE_MASK |
1816                            GDK_KEY_PRESS_MASK |
1817                            GDK_KEY_RELEASE_MASK) |
1818     gtk_widget_get_events (widget);
1819
1820   tree_view->priv->header_window = gdk_window_new (widget->window,
1821                                                    &attributes, attributes_mask);
1822   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1823
1824   /* Add them all up. */
1825   widget->style = gtk_style_attach (widget->style, widget->window);
1826   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1827   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1828   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1829
1830   tmp_list = tree_view->priv->children;
1831   while (tmp_list)
1832     {
1833       GtkTreeViewChild *child = tmp_list->data;
1834       tmp_list = tmp_list->next;
1835
1836       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1837     }
1838
1839   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1840     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1841
1842   /* Need to call those here, since they create GCs */
1843   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1844   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1845
1846   install_presize_handler (tree_view); 
1847 }
1848
1849 static void
1850 gtk_tree_view_unrealize (GtkWidget *widget)
1851 {
1852   GtkTreeView *tree_view;
1853   GtkTreeViewPrivate *priv;
1854   GList *list;
1855
1856   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1857
1858   tree_view = GTK_TREE_VIEW (widget);
1859   priv = tree_view->priv;
1860
1861   if (priv->scroll_timeout != 0)
1862     {
1863       g_source_remove (priv->scroll_timeout);
1864       priv->scroll_timeout = 0;
1865     }
1866
1867   if (priv->auto_expand_timeout != 0)
1868     {
1869       g_source_remove (priv->auto_expand_timeout);
1870       priv->auto_expand_timeout = 0;
1871     }
1872
1873   if (priv->open_dest_timeout != 0)
1874     {
1875       g_source_remove (priv->open_dest_timeout);
1876       priv->open_dest_timeout = 0;
1877     }
1878
1879   if (priv->expand_collapse_timeout != 0)
1880     {
1881       g_source_remove (priv->expand_collapse_timeout);
1882       priv->expand_collapse_timeout = 0;
1883     }
1884   
1885   if (priv->presize_handler_timer != 0)
1886     {
1887       g_source_remove (priv->presize_handler_timer);
1888       priv->presize_handler_timer = 0;
1889     }
1890
1891   if (priv->validate_rows_timer != 0)
1892     {
1893       g_source_remove (priv->validate_rows_timer);
1894       priv->validate_rows_timer = 0;
1895     }
1896
1897   if (priv->scroll_sync_timer != 0)
1898     {
1899       g_source_remove (priv->scroll_sync_timer);
1900       priv->scroll_sync_timer = 0;
1901     }
1902
1903   if (priv->typeselect_flush_timeout)
1904     {
1905       g_source_remove (priv->typeselect_flush_timeout);
1906       priv->typeselect_flush_timeout = 0;
1907     }
1908   
1909   for (list = priv->columns; list; list = list->next)
1910     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1911
1912   gdk_window_set_user_data (priv->bin_window, NULL);
1913   gdk_window_destroy (priv->bin_window);
1914   priv->bin_window = NULL;
1915
1916   gdk_window_set_user_data (priv->header_window, NULL);
1917   gdk_window_destroy (priv->header_window);
1918   priv->header_window = NULL;
1919
1920   if (priv->drag_window)
1921     {
1922       gdk_window_set_user_data (priv->drag_window, NULL);
1923       gdk_window_destroy (priv->drag_window);
1924       priv->drag_window = NULL;
1925     }
1926
1927   if (priv->drag_highlight_window)
1928     {
1929       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1930       gdk_window_destroy (priv->drag_highlight_window);
1931       priv->drag_highlight_window = NULL;
1932     }
1933
1934   if (priv->tree_line_gc)
1935     {
1936       g_object_unref (priv->tree_line_gc);
1937       priv->tree_line_gc = NULL;
1938     }
1939
1940   if (priv->grid_line_gc)
1941     {
1942       g_object_unref (priv->grid_line_gc);
1943       priv->grid_line_gc = NULL;
1944     }
1945
1946   /* GtkWidget::unrealize destroys children and widget->window */
1947   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize)
1948     (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize) (widget);
1949 }
1950
1951 /* GtkWidget::size_request helper */
1952 static void
1953 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1954 {
1955   GList *list;
1956
1957   tree_view->priv->header_height = 0;
1958
1959   if (tree_view->priv->model)
1960     {
1961       for (list = tree_view->priv->columns; list; list = list->next)
1962         {
1963           GtkRequisition requisition;
1964           GtkTreeViewColumn *column = list->data;
1965
1966           if (column->button == NULL)
1967             continue;
1968
1969           column = list->data;
1970           
1971           gtk_widget_size_request (column->button, &requisition);
1972           column->button_request = requisition.width;
1973           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1974         }
1975     }
1976 }
1977
1978
1979 /* Called only by ::size_request */
1980 static void
1981 gtk_tree_view_update_size (GtkTreeView *tree_view)
1982 {
1983   GList *list;
1984   GtkTreeViewColumn *column;
1985   gint i;
1986
1987   if (tree_view->priv->model == NULL)
1988     {
1989       tree_view->priv->width = 0;
1990       tree_view->priv->prev_width = 0;                   
1991       tree_view->priv->height = 0;
1992       return;
1993     }
1994
1995   tree_view->priv->prev_width = tree_view->priv->width;  
1996   tree_view->priv->width = 0;
1997   /* keep this in sync with size_allocate below */
1998   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1999     {
2000       gint real_requested_width = 0;
2001       column = list->data;
2002       if (!column->visible)
2003         continue;
2004
2005       if (column->use_resized_width)
2006         {
2007           real_requested_width = column->resized_width;
2008         }
2009       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2010         {
2011           real_requested_width = column->fixed_width;
2012         }
2013       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2014         {
2015           real_requested_width = MAX (column->requested_width, column->button_request);
2016         }
2017       else
2018         {
2019           real_requested_width = column->requested_width;
2020         }
2021
2022       if (column->min_width != -1)
2023         real_requested_width = MAX (real_requested_width, column->min_width);
2024       if (column->max_width != -1)
2025         real_requested_width = MIN (real_requested_width, column->max_width);
2026
2027       tree_view->priv->width += real_requested_width;
2028     }
2029
2030   if (tree_view->priv->tree == NULL)
2031     tree_view->priv->height = 0;
2032   else
2033     tree_view->priv->height = tree_view->priv->tree->root->offset;
2034 }
2035
2036 static void
2037 gtk_tree_view_size_request (GtkWidget      *widget,
2038                             GtkRequisition *requisition)
2039 {
2040   GtkTreeView *tree_view;
2041   GList *tmp_list;
2042
2043   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
2044
2045   tree_view = GTK_TREE_VIEW (widget);
2046
2047   /* we validate GTK_TREE_VIEW_NUM_ROWS_PER_IDLE rows initially just to make
2048    * sure we have some size. In practice, with a lot of static lists, this
2049    * should get a good width.
2050    */
2051   do_validate_rows (tree_view, FALSE);
2052   gtk_tree_view_size_request_columns (tree_view);
2053   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2054
2055   requisition->width = tree_view->priv->width;
2056   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2057
2058   tmp_list = tree_view->priv->children;
2059
2060   while (tmp_list)
2061     {
2062       GtkTreeViewChild *child = tmp_list->data;
2063       GtkRequisition child_requisition;
2064
2065       tmp_list = tmp_list->next;
2066
2067       if (GTK_WIDGET_VISIBLE (child->widget))
2068         gtk_widget_size_request (child->widget, &child_requisition);
2069     }
2070 }
2071
2072
2073 static void
2074 invalidate_column (GtkTreeView       *tree_view,
2075                    GtkTreeViewColumn *column)
2076 {
2077   gint column_offset = 0;
2078   GList *list;
2079   GtkWidget *widget = GTK_WIDGET (tree_view);
2080   gboolean rtl;
2081
2082   if (!GTK_WIDGET_REALIZED (widget))
2083     return;
2084
2085   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2086   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2087        list;
2088        list = (rtl ? list->prev : list->next))
2089     {
2090       GtkTreeViewColumn *tmpcolumn = list->data;
2091       if (tmpcolumn == column)
2092         {
2093           GdkRectangle invalid_rect;
2094           
2095           invalid_rect.x = column_offset;
2096           invalid_rect.y = 0;
2097           invalid_rect.width = column->width;
2098           invalid_rect.height = widget->allocation.height;
2099           
2100           gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
2101           break;
2102         }
2103       
2104       column_offset += tmpcolumn->width;
2105     }
2106 }
2107
2108 static void
2109 invalidate_last_column (GtkTreeView *tree_view)
2110 {
2111   GList *last_column;
2112   gboolean rtl;
2113
2114   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2115
2116   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2117        last_column;
2118        last_column = (rtl ? last_column->next : last_column->prev))
2119     {
2120       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2121         {
2122           invalidate_column (tree_view, last_column->data);
2123           return;
2124         }
2125     }
2126 }
2127
2128 static gint
2129 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2130                                                     GtkTreeViewColumn *column)
2131 {
2132   gint real_requested_width;
2133
2134   if (column->use_resized_width)
2135     {
2136       real_requested_width = column->resized_width;
2137     }
2138   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2139     {
2140       real_requested_width = column->fixed_width;
2141     }
2142   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2143     {
2144       real_requested_width = MAX (column->requested_width, column->button_request);
2145     }
2146   else
2147     {
2148       real_requested_width = column->requested_width;
2149       if (real_requested_width < 0)
2150         real_requested_width = 0;
2151     }
2152
2153   if (column->min_width != -1)
2154     real_requested_width = MAX (real_requested_width, column->min_width);
2155   if (column->max_width != -1)
2156     real_requested_width = MIN (real_requested_width, column->max_width);
2157
2158   return real_requested_width;
2159 }
2160
2161 /* GtkWidget::size_allocate helper */
2162 static void
2163 gtk_tree_view_size_allocate_columns (GtkWidget *widget)
2164 {
2165   GtkTreeView *tree_view;
2166   GList *list, *first_column, *last_column;
2167   GtkTreeViewColumn *column;
2168   GtkAllocation allocation;
2169   gint width = 0;
2170   gint extra, extra_per_column;
2171   gint full_requested_width = 0;
2172   gint number_of_expand_columns = 0;
2173   gboolean column_changed = FALSE;
2174   gboolean rtl;
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   extra = MAX (widget->allocation.width - full_requested_width, 0);
2210   if (number_of_expand_columns > 0)
2211     extra_per_column = extra/number_of_expand_columns;
2212   else
2213     extra_per_column = 0;
2214
2215   for (list = (rtl ? last_column : first_column); 
2216        list != (rtl ? first_column->prev : last_column->next);
2217        list = (rtl ? list->prev : list->next)) 
2218     {
2219       gint real_requested_width = 0;
2220       gint old_width;
2221
2222       column = list->data;
2223       old_width = column->width;
2224
2225       if (!column->visible)
2226         continue;
2227
2228       /* We need to handle the dragged button specially.
2229        */
2230       if (column == tree_view->priv->drag_column)
2231         {
2232           GtkAllocation drag_allocation;
2233           gdk_drawable_get_size (tree_view->priv->drag_window,
2234                                  &(drag_allocation.width),
2235                                  &(drag_allocation.height));
2236           drag_allocation.x = 0;
2237           drag_allocation.y = 0;
2238           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2239                                     &drag_allocation);
2240           width += drag_allocation.width;
2241           continue;
2242         }
2243
2244       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2245
2246       allocation.x = width;
2247       column->width = real_requested_width;
2248
2249       if (column->expand)
2250         {
2251           if (number_of_expand_columns == 1)
2252             {
2253               /* We add the remander to the last column as
2254                * */
2255               column->width += extra;
2256             }
2257           else
2258             {
2259               column->width += extra_per_column;
2260               extra -= extra_per_column;
2261               number_of_expand_columns --;
2262             }
2263         }
2264       else if (number_of_expand_columns == 0 &&
2265                list == last_column)
2266         {
2267           column->width += extra;
2268         }
2269
2270       g_object_notify (G_OBJECT (column), "width");
2271
2272       allocation.width = column->width;
2273       width += column->width;
2274
2275       if (column->width > old_width)
2276         column_changed = TRUE;
2277
2278       gtk_widget_size_allocate (column->button, &allocation);
2279
2280       if (column->window)
2281         gdk_window_move_resize (column->window,
2282                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2283                                 allocation.y,
2284                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2285     }
2286
2287   if (column_changed)
2288     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2289 }
2290
2291
2292 static void
2293 gtk_tree_view_size_allocate (GtkWidget     *widget,
2294                              GtkAllocation *allocation)
2295 {
2296   GList *tmp_list;
2297   GtkTreeView *tree_view;
2298   gboolean width_changed = FALSE;
2299   gint old_width = widget->allocation.width;           
2300
2301   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
2302
2303   if (allocation->width != widget->allocation.width)
2304     width_changed = TRUE;
2305   
2306   widget->allocation = *allocation;
2307
2308   tree_view = GTK_TREE_VIEW (widget);
2309
2310   tmp_list = tree_view->priv->children;
2311
2312   while (tmp_list)
2313     {
2314       GtkAllocation allocation;
2315
2316       GtkTreeViewChild *child = tmp_list->data;
2317       tmp_list = tmp_list->next;
2318
2319       /* totally ignore our child's requisition */
2320       allocation.x = child->x;
2321       allocation.y = child->y;
2322       allocation.width = child->width;
2323       allocation.height = child->height;
2324       gtk_widget_size_allocate (child->widget, &allocation);
2325     }
2326
2327
2328   tree_view->priv->hadjustment->page_size = allocation->width;
2329   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2330   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2331   tree_view->priv->hadjustment->lower = 0;
2332   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2333
2334   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2335      {
2336       if (allocation->width < tree_view->priv->width)
2337          {
2338          if (tree_view->priv->init_hadjust_value)
2339            {
2340            tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2341            tree_view->priv->init_hadjust_value = FALSE;
2342            }
2343          else if(allocation->width != old_width)
2344            tree_view->priv->hadjustment->value = CLAMP(tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2345          else
2346            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);
2347          }
2348       else
2349          {
2350          tree_view->priv->hadjustment->value = 0;
2351          tree_view->priv->init_hadjust_value = TRUE;
2352          }
2353      }
2354   else
2355      if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2356         tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2357
2358   gtk_adjustment_changed (tree_view->priv->hadjustment);
2359
2360   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2361   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2362   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2363   tree_view->priv->vadjustment->lower = 0;
2364   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2365
2366   gtk_adjustment_changed (tree_view->priv->vadjustment);
2367
2368   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2369   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2370     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2371   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2372     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2373                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2374   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2375     gtk_tree_view_top_row_to_dy (tree_view);
2376   else
2377     gtk_tree_view_dy_to_top_row (tree_view);
2378   
2379   if (GTK_WIDGET_REALIZED (widget))
2380     {
2381       gdk_window_move_resize (widget->window,
2382                               allocation->x, allocation->y,
2383                               allocation->width, allocation->height);
2384       gdk_window_move_resize (tree_view->priv->header_window,
2385                               - (gint) tree_view->priv->hadjustment->value,
2386                               0,
2387                               MAX (tree_view->priv->width, allocation->width),
2388                               tree_view->priv->header_height);
2389       gdk_window_move_resize (tree_view->priv->bin_window,
2390                               - (gint) tree_view->priv->hadjustment->value,
2391                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2392                               MAX (tree_view->priv->width, allocation->width),
2393                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2394     }
2395
2396   gtk_tree_view_size_allocate_columns (widget);
2397
2398   if (tree_view->priv->tree == NULL)
2399     invalidate_empty_focus (tree_view);
2400
2401   if (GTK_WIDGET_REALIZED (widget))
2402     {
2403       gboolean has_expand_column = FALSE;
2404       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2405         {
2406           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2407             {
2408               has_expand_column = TRUE;
2409               break;
2410             }
2411         }
2412
2413       /* This little hack only works if we have an LTR locale, and no column has the  */
2414       if (width_changed)
2415         {
2416           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2417               ! has_expand_column)
2418             invalidate_last_column (tree_view);
2419           else
2420             gtk_widget_queue_draw (widget);
2421         }
2422     }
2423 }
2424
2425 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2426 static void
2427 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2428 {
2429   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
2430     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2431   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2432 }
2433
2434 static inline gboolean
2435 row_is_separator (GtkTreeView *tree_view,
2436                   GtkTreeIter *iter,
2437                   GtkTreePath *path)
2438 {
2439   gboolean is_separator = FALSE;
2440
2441   if (tree_view->priv->row_separator_func)
2442     {
2443       GtkTreeIter tmpiter;
2444
2445       if (iter)
2446         tmpiter = *iter;
2447       else
2448         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2449
2450       is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
2451                                                               &tmpiter,
2452                                                               tree_view->priv->row_separator_data);
2453     }
2454
2455   return is_separator;
2456 }
2457
2458 static gboolean
2459 gtk_tree_view_button_press (GtkWidget      *widget,
2460                             GdkEventButton *event)
2461 {
2462   GtkTreeView *tree_view;
2463   GList *list;
2464   GtkTreeViewColumn *column = NULL;
2465   gint i;
2466   GdkRectangle background_area;
2467   GdkRectangle cell_area;
2468   gint vertical_separator;
2469   gint horizontal_separator;
2470   gboolean path_is_selectable;
2471   gboolean rtl;
2472
2473   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2474   g_return_val_if_fail (event != NULL, FALSE);
2475
2476   tree_view = GTK_TREE_VIEW (widget);
2477   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2478   gtk_tree_view_stop_editing (tree_view, FALSE);
2479   gtk_widget_style_get (widget,
2480                         "vertical-separator", &vertical_separator,
2481                         "horizontal-separator", &horizontal_separator,
2482                         NULL);
2483
2484
2485   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2486    * we're done handling the button press.
2487    */
2488
2489   if (event->window == tree_view->priv->bin_window)
2490     {
2491       GtkRBNode *node;
2492       GtkRBTree *tree;
2493       GtkTreePath *path;
2494       gchar *path_string;
2495       gint depth;
2496       gint new_y;
2497       gint y_offset;
2498       gint dval;
2499       gint pre_val, aft_val;
2500       GtkTreeViewColumn *column = NULL;
2501       GtkCellRenderer *focus_cell = NULL;
2502       gint column_handled_click = FALSE;
2503       gboolean row_double_click = FALSE;
2504       gboolean rtl;
2505       gboolean node_selected;
2506
2507       /* Empty tree? */
2508       if (tree_view->priv->tree == NULL)
2509         {
2510           grab_focus_and_unset_draw_keyfocus (tree_view);
2511           return TRUE;
2512         }
2513
2514       /* are we in an arrow? */
2515       if (tree_view->priv->prelight_node &&
2516           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2517           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2518         {
2519           if (event->button == 1)
2520             {
2521               gtk_grab_add (widget);
2522               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2523               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2524               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2525                                         tree_view->priv->prelight_tree,
2526                                         tree_view->priv->prelight_node,
2527                                         event->x,
2528                                         event->y);
2529             }
2530
2531           grab_focus_and_unset_draw_keyfocus (tree_view);
2532           return TRUE;
2533         }
2534
2535       /* find the node that was clicked */
2536       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2537       if (new_y < 0)
2538         new_y = 0;
2539       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2540
2541       if (node == NULL)
2542         {
2543           /* We clicked in dead space */
2544           grab_focus_and_unset_draw_keyfocus (tree_view);
2545           return TRUE;
2546         }
2547
2548       /* Get the path and the node */
2549       path = _gtk_tree_view_find_path (tree_view, tree, node);
2550       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2551
2552       if (!path_is_selectable)
2553         {
2554           gtk_tree_path_free (path);
2555           grab_focus_and_unset_draw_keyfocus (tree_view);
2556           return TRUE;
2557         }
2558
2559       depth = gtk_tree_path_get_depth (path);
2560       background_area.y = y_offset + event->y;
2561       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2562       background_area.x = 0;
2563
2564
2565       /* Let the column have a chance at selecting it. */
2566       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2567       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2568            list; list = (rtl ? list->prev : list->next))
2569         {
2570           GtkTreeViewColumn *candidate = list->data;
2571
2572           if (!candidate->visible)
2573             continue;
2574
2575           background_area.width = candidate->width;
2576           if ((background_area.x > (gint) event->x) ||
2577               (background_area.x + background_area.width <= (gint) event->x))
2578             {
2579               background_area.x += background_area.width;
2580               continue;
2581             }
2582
2583           /* we found the focus column */
2584           column = candidate;
2585           cell_area = background_area;
2586           cell_area.width -= horizontal_separator;
2587           cell_area.height -= vertical_separator;
2588           cell_area.x += horizontal_separator/2;
2589           cell_area.y += vertical_separator/2;
2590           if (gtk_tree_view_is_expander_column (tree_view, column))
2591             {
2592               if (!rtl)
2593                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2594               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2595
2596               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2597                 {
2598                   if (!rtl)
2599                     cell_area.x += depth * tree_view->priv->expander_size;
2600                   cell_area.width -= depth * tree_view->priv->expander_size;
2601                 }
2602             }
2603           break;
2604         }
2605
2606       if (column == NULL)
2607         {
2608           gtk_tree_path_free (path);
2609           grab_focus_and_unset_draw_keyfocus (tree_view);
2610           return FALSE;
2611         }
2612
2613       tree_view->priv->focus_column = column;
2614
2615       /* decide if we edit */
2616       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2617           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2618         {
2619           GtkTreePath *anchor;
2620           GtkTreeIter iter;
2621
2622           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2623           gtk_tree_view_column_cell_set_cell_data (column,
2624                                                    tree_view->priv->model,
2625                                                    &iter,
2626                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2627                                                    node->children?TRUE:FALSE);
2628
2629           if (tree_view->priv->anchor)
2630             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2631           else
2632             anchor = NULL;
2633
2634           if ((anchor && !gtk_tree_path_compare (anchor, path))
2635               || !_gtk_tree_view_column_has_editable_cell (column))
2636             {
2637               GtkCellEditable *cell_editable = NULL;
2638
2639               /* FIXME: get the right flags */
2640               guint flags = 0;
2641
2642               path_string = gtk_tree_path_to_string (path);
2643
2644               if (_gtk_tree_view_column_cell_event (column,
2645                                                     &cell_editable,
2646                                                     (GdkEvent *)event,
2647                                                     path_string,
2648                                                     &background_area,
2649                                                     &cell_area, flags))
2650                 {
2651                   if (cell_editable != NULL)
2652                     {
2653                       gint left, right;
2654                       GdkRectangle area;
2655
2656                       area = cell_area;
2657                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2658
2659                       area.x += left;
2660                       area.width -= right + left;
2661
2662                       gtk_tree_view_real_start_editing (tree_view,
2663                                                         column,
2664                                                         path,
2665                                                         cell_editable,
2666                                                         &area,
2667                                                         (GdkEvent *)event,
2668                                                         flags);
2669                       g_free (path_string);
2670                       gtk_tree_path_free (path);
2671                       gtk_tree_path_free (anchor);
2672                       return TRUE;
2673                     }
2674                   column_handled_click = TRUE;
2675                 }
2676               g_free (path_string);
2677             }
2678           if (anchor)
2679             gtk_tree_path_free (anchor);
2680         }
2681
2682       /* select */
2683       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2684       pre_val = tree_view->priv->vadjustment->value;
2685
2686       /* we only handle selection modifications on the first button press
2687        */
2688       if (event->type == GDK_BUTTON_PRESS)
2689         {
2690           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2691             tree_view->priv->ctrl_pressed = TRUE;
2692           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2693             tree_view->priv->shift_pressed = TRUE;
2694
2695           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2696           if (focus_cell)
2697             gtk_tree_view_column_focus_cell (column, focus_cell);
2698
2699           if (event->state & GDK_CONTROL_MASK)
2700             {
2701               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2702               gtk_tree_view_real_toggle_cursor_row (tree_view);
2703             }
2704           else if (event->state & GDK_SHIFT_MASK)
2705             {
2706               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2707               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2708             }
2709           else
2710             {
2711               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2712             }
2713
2714           tree_view->priv->ctrl_pressed = FALSE;
2715           tree_view->priv->shift_pressed = FALSE;
2716         }
2717
2718       /* the treeview may have been scrolled because of _set_cursor,
2719        * correct here
2720        */
2721
2722       aft_val = tree_view->priv->vadjustment->value;
2723       dval = pre_val - aft_val;
2724
2725       cell_area.y += dval;
2726       background_area.y += dval;
2727
2728       /* Save press to possibly begin a drag
2729        */
2730       if (!column_handled_click &&
2731           !tree_view->priv->in_grab &&
2732           tree_view->priv->pressed_button < 0)
2733         {
2734           tree_view->priv->pressed_button = event->button;
2735           tree_view->priv->press_start_x = event->x;
2736           tree_view->priv->press_start_y = event->y;
2737
2738           if (tree_view->priv->rubber_banding_enable
2739               && !node_selected
2740               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2741             {
2742               tree_view->priv->press_start_y += tree_view->priv->dy;
2743               tree_view->priv->rubber_band_x = event->x;
2744               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2745               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2746
2747               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2748                 tree_view->priv->rubber_band_ctrl = TRUE;
2749               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2750                 tree_view->priv->rubber_band_shift = TRUE;
2751             }
2752         }
2753
2754       /* Test if a double click happened on the same row. */
2755       if (event->button == 1)
2756         {
2757           /* We also handle triple clicks here, because a user could have done
2758            * a first click and a second double click on different rows.
2759            */
2760           if ((event->type == GDK_2BUTTON_PRESS
2761                || event->type == GDK_3BUTTON_PRESS)
2762               && tree_view->priv->last_button_press)
2763             {
2764               GtkTreePath *lsc;
2765
2766               lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
2767
2768               if (lsc)
2769                 {
2770                   row_double_click = !gtk_tree_path_compare (lsc, path);
2771                   gtk_tree_path_free (lsc);
2772                 }
2773             }
2774
2775           if (row_double_click)
2776             {
2777               if (tree_view->priv->last_button_press)
2778                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2779               if (tree_view->priv->last_button_press_2)
2780                 gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
2781               tree_view->priv->last_button_press = NULL;
2782               tree_view->priv->last_button_press_2 = NULL;
2783             }
2784           else
2785             {
2786               if (tree_view->priv->last_button_press)
2787                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2788               tree_view->priv->last_button_press = tree_view->priv->last_button_press_2;
2789               tree_view->priv->last_button_press_2 = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
2790             }
2791         }
2792
2793       if (row_double_click)
2794         {
2795           gtk_grab_remove (widget);
2796           gtk_tree_view_row_activated (tree_view, path, column);
2797
2798           if (tree_view->priv->pressed_button == event->button)
2799             tree_view->priv->pressed_button = -1;
2800         }
2801
2802       gtk_tree_path_free (path);
2803
2804       /* If we activated the row through a double click we don't want to grab
2805        * focus back, as moving focus to another widget is pretty common.
2806        */
2807       if (!row_double_click)
2808         grab_focus_and_unset_draw_keyfocus (tree_view);
2809
2810       return TRUE;
2811     }
2812
2813   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2814    */
2815   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2816     {
2817       column = list->data;
2818       if (event->window == column->window &&
2819           column->resizable &&
2820           column->window)
2821         {
2822           gpointer drag_data;
2823
2824           if (event->type == GDK_2BUTTON_PRESS &&
2825               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2826             {
2827               column->use_resized_width = FALSE;
2828               _gtk_tree_view_column_autosize (tree_view, column);
2829               return TRUE;
2830             }
2831
2832           if (gdk_pointer_grab (column->window, FALSE,
2833                                 GDK_POINTER_MOTION_HINT_MASK |
2834                                 GDK_BUTTON1_MOTION_MASK |
2835                                 GDK_BUTTON_RELEASE_MASK,
2836                                 NULL, NULL, event->time))
2837             return FALSE;
2838
2839           gtk_grab_add (widget);
2840           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2841           column->resized_width = column->width;
2842
2843           /* block attached dnd signal handler */
2844           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2845           if (drag_data)
2846             g_signal_handlers_block_matched (widget,
2847                                              G_SIGNAL_MATCH_DATA,
2848                                              0, 0, NULL, NULL,
2849                                              drag_data);
2850
2851           tree_view->priv->drag_pos = i;
2852           tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
2853
2854           if (!GTK_WIDGET_HAS_FOCUS (widget))
2855             gtk_widget_grab_focus (widget);
2856
2857           return TRUE;
2858         }
2859     }
2860   return FALSE;
2861 }
2862
2863 /* GtkWidget::button_release_event helper */
2864 static gboolean
2865 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2866                                           GdkEventButton *event)
2867 {
2868   GtkTreeView *tree_view;
2869   gboolean rtl;
2870
2871   tree_view = GTK_TREE_VIEW (widget);
2872
2873   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2874   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2875   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2876
2877   /* Move the button back */
2878   g_object_ref (tree_view->priv->drag_column->button);
2879   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2880   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2881   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2882   g_object_unref (tree_view->priv->drag_column->button);
2883   gtk_widget_queue_resize (widget);
2884   if (tree_view->priv->drag_column->resizable)
2885     {
2886       gdk_window_raise (tree_view->priv->drag_column->window);
2887       gdk_window_show (tree_view->priv->drag_column->window);
2888     }
2889   else
2890     gdk_window_hide (tree_view->priv->drag_column->window);
2891
2892   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2893
2894   if (rtl)
2895     {
2896       if (tree_view->priv->cur_reorder &&
2897           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2898         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2899                                          tree_view->priv->cur_reorder->right_column);
2900     }
2901   else
2902     {
2903       if (tree_view->priv->cur_reorder &&
2904           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2905         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2906                                          tree_view->priv->cur_reorder->left_column);
2907     }
2908   tree_view->priv->drag_column = NULL;
2909   gdk_window_hide (tree_view->priv->drag_window);
2910
2911   g_list_foreach (tree_view->priv->column_drag_info, (GFunc) g_free, NULL);
2912   g_list_free (tree_view->priv->column_drag_info);
2913   tree_view->priv->column_drag_info = NULL;
2914   tree_view->priv->cur_reorder = NULL;
2915
2916   if (tree_view->priv->drag_highlight_window)
2917     gdk_window_hide (tree_view->priv->drag_highlight_window);
2918
2919   /* Reset our flags */
2920   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
2921   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
2922
2923   return TRUE;
2924 }
2925
2926 /* GtkWidget::button_release_event helper */
2927 static gboolean
2928 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
2929                                             GdkEventButton *event)
2930 {
2931   GtkTreeView *tree_view;
2932   gpointer drag_data;
2933
2934   tree_view = GTK_TREE_VIEW (widget);
2935
2936   tree_view->priv->drag_pos = -1;
2937
2938   /* unblock attached dnd signal handler */
2939   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2940   if (drag_data)
2941     g_signal_handlers_unblock_matched (widget,
2942                                        G_SIGNAL_MATCH_DATA,
2943                                        0, 0, NULL, NULL,
2944                                        drag_data);
2945
2946   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2947   gtk_grab_remove (widget);
2948   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
2949                               event->time);
2950   return TRUE;
2951 }
2952
2953 static gboolean
2954 gtk_tree_view_button_release (GtkWidget      *widget,
2955                               GdkEventButton *event)
2956 {
2957   GtkTreeView *tree_view;
2958
2959   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2960   g_return_val_if_fail (event != NULL, FALSE);
2961
2962   tree_view = GTK_TREE_VIEW (widget);
2963
2964   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2965     return gtk_tree_view_button_release_drag_column (widget, event);
2966
2967   if (tree_view->priv->rubber_band_status)
2968     gtk_tree_view_stop_rubber_band (tree_view);
2969
2970   if (tree_view->priv->pressed_button == event->button)
2971     tree_view->priv->pressed_button = -1;
2972
2973   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
2974     return gtk_tree_view_button_release_column_resize (widget, event);
2975
2976   if (tree_view->priv->button_pressed_node == NULL)
2977     return FALSE;
2978
2979   if (event->button == 1)
2980     {
2981       gtk_grab_remove (widget);
2982       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
2983           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
2984         {
2985           GtkTreePath *path = NULL;
2986
2987           path = _gtk_tree_view_find_path (tree_view,
2988                                            tree_view->priv->button_pressed_tree,
2989                                            tree_view->priv->button_pressed_node);
2990           /* Actually activate the node */
2991           if (tree_view->priv->button_pressed_node->children == NULL)
2992             gtk_tree_view_real_expand_row (tree_view, path,
2993                                            tree_view->priv->button_pressed_tree,
2994                                            tree_view->priv->button_pressed_node,
2995                                            FALSE, TRUE);
2996           else
2997             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
2998                                              tree_view->priv->button_pressed_tree,
2999                                              tree_view->priv->button_pressed_node, TRUE);
3000           gtk_tree_path_free (path);
3001         }
3002
3003       tree_view->priv->button_pressed_tree = NULL;
3004       tree_view->priv->button_pressed_node = NULL;
3005     }
3006
3007   return TRUE;
3008 }
3009
3010 static gboolean
3011 gtk_tree_view_grab_broken (GtkWidget          *widget,
3012                            GdkEventGrabBroken *event)
3013 {
3014   GtkTreeView *tree_view;
3015
3016   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3017   g_return_val_if_fail (event != NULL, FALSE);
3018
3019   tree_view = GTK_TREE_VIEW (widget);
3020
3021   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3022     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3023
3024   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3025     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3026
3027   return TRUE;
3028 }
3029
3030 #if 0
3031 static gboolean
3032 gtk_tree_view_configure (GtkWidget *widget,
3033                          GdkEventConfigure *event)
3034 {
3035   GtkTreeView *tree_view;
3036
3037   tree_view = GTK_TREE_VIEW (widget);
3038   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3039
3040   return FALSE;
3041 }
3042 #endif
3043
3044 /* GtkWidget::motion_event function set.
3045  */
3046
3047 static gboolean
3048 coords_are_over_arrow (GtkTreeView *tree_view,
3049                        GtkRBTree   *tree,
3050                        GtkRBNode   *node,
3051                        /* these are in bin window coords */
3052                        gint         x,
3053                        gint         y)
3054 {
3055   GdkRectangle arrow;
3056   gint x2;
3057
3058   if (!GTK_WIDGET_REALIZED (tree_view))
3059     return FALSE;
3060
3061   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3062     return FALSE;
3063
3064   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3065
3066   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3067
3068   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3069
3070   arrow.width = x2 - arrow.x;
3071
3072   return (x >= arrow.x &&
3073           x < (arrow.x + arrow.width) &&
3074           y >= arrow.y &&
3075           y < (arrow.y + arrow.height));
3076 }
3077
3078 static gboolean
3079 auto_expand_timeout (gpointer data)
3080 {
3081   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3082   GtkTreePath *path;
3083
3084   if (tree_view->priv->prelight_node)
3085     {
3086       path = _gtk_tree_view_find_path (tree_view,
3087                                        tree_view->priv->prelight_tree,
3088                                        tree_view->priv->prelight_node);   
3089
3090       if (tree_view->priv->prelight_node->children)
3091         gtk_tree_view_collapse_row (tree_view, path);
3092       else
3093         gtk_tree_view_expand_row (tree_view, path, FALSE);
3094
3095       gtk_tree_path_free (path);
3096     }
3097
3098   tree_view->priv->auto_expand_timeout = 0;
3099
3100   return FALSE;
3101 }
3102
3103 static void
3104 remove_auto_expand_timeout (GtkTreeView *tree_view)
3105 {
3106   if (tree_view->priv->auto_expand_timeout != 0)
3107     {
3108       g_source_remove (tree_view->priv->auto_expand_timeout);
3109       tree_view->priv->auto_expand_timeout = 0;
3110     }
3111 }
3112
3113 static void
3114 do_prelight (GtkTreeView *tree_view,
3115              GtkRBTree   *tree,
3116              GtkRBNode   *node,
3117              /* these are in bin_window coords */
3118              gint         x,
3119              gint         y)
3120 {
3121   if (tree_view->priv->prelight_tree == tree &&
3122       tree_view->priv->prelight_node == node)
3123     {
3124       /*  We are still on the same node,
3125           but we might need to take care of the arrow  */
3126
3127       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3128         {
3129           gboolean over_arrow;
3130           gboolean flag_set;
3131
3132           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3133           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3134                                              GTK_TREE_VIEW_ARROW_PRELIT);
3135
3136           if (over_arrow != flag_set)
3137             {
3138               if (over_arrow)
3139                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3140                                         GTK_TREE_VIEW_ARROW_PRELIT);
3141               else
3142                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3143                                           GTK_TREE_VIEW_ARROW_PRELIT);
3144
3145               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3146             }
3147         }
3148
3149       return;
3150     }
3151
3152   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3153     {
3154       /*  Unprelight the old node and arrow  */
3155
3156       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3157                              GTK_RBNODE_IS_PRELIT);
3158
3159       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3160           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3161         {
3162           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3163           
3164           gtk_tree_view_draw_arrow (tree_view,
3165                                     tree_view->priv->prelight_tree,
3166                                     tree_view->priv->prelight_node,
3167                                     x,
3168                                     y);
3169         }
3170
3171       _gtk_tree_view_queue_draw_node (tree_view,
3172                                       tree_view->priv->prelight_tree,
3173                                       tree_view->priv->prelight_node,
3174                                       NULL);
3175     }
3176
3177
3178   if (tree_view->priv->hover_expand)
3179     remove_auto_expand_timeout (tree_view);
3180
3181   /*  Set the new prelight values  */
3182   tree_view->priv->prelight_node = node;
3183   tree_view->priv->prelight_tree = tree;
3184
3185   if (!node || !tree)
3186     return;
3187
3188   /*  Prelight the new node and arrow  */
3189
3190   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3191       && coords_are_over_arrow (tree_view, tree, node, x, y))
3192     {
3193       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3194
3195       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3196     }
3197
3198   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3199
3200   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3201
3202   if (tree_view->priv->hover_expand)
3203     {
3204       tree_view->priv->auto_expand_timeout = 
3205         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3206     }
3207 }
3208
3209 static void
3210 prelight_or_select (GtkTreeView *tree_view,
3211                     GtkRBTree   *tree,
3212                     GtkRBNode   *node,
3213                     /* these are in bin_window coords */
3214                     gint         x,
3215                     gint         y)
3216 {
3217   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3218   
3219   if (tree_view->priv->hover_selection &&
3220       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3221       !(tree_view->priv->edited_column &&
3222         tree_view->priv->edited_column->editable_widget))
3223     {
3224       if (node)
3225         {
3226           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3227             {
3228               GtkTreePath *path;
3229               
3230               path = _gtk_tree_view_find_path (tree_view, tree, node);
3231               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3232               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3233                 {
3234                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3235                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3236                 }
3237               gtk_tree_path_free (path);
3238             }
3239         }
3240
3241       else if (mode == GTK_SELECTION_SINGLE)
3242         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3243     }
3244
3245     do_prelight (tree_view, tree, node, x, y);
3246 }
3247
3248 static void
3249 ensure_unprelighted (GtkTreeView *tree_view)
3250 {
3251   do_prelight (tree_view,
3252                NULL, NULL,
3253                -1000, -1000); /* coords not possibly over an arrow */
3254
3255   g_assert (tree_view->priv->prelight_node == NULL);
3256 }
3257
3258
3259
3260
3261 /* Our motion arrow is either a box (in the case of the original spot)
3262  * or an arrow.  It is expander_size wide.
3263  */
3264 /*
3265  * 11111111111111
3266  * 01111111111110
3267  * 00111111111100
3268  * 00011111111000
3269  * 00001111110000
3270  * 00000111100000
3271  * 00000111100000
3272  * 00000111100000
3273  * ~ ~ ~ ~ ~ ~ ~
3274  * 00000111100000
3275  * 00000111100000
3276  * 00000111100000
3277  * 00001111110000
3278  * 00011111111000
3279  * 00111111111100
3280  * 01111111111110
3281  * 11111111111111
3282  */
3283
3284 static void
3285 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3286 {
3287   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3288   GtkWidget *widget = GTK_WIDGET (tree_view);
3289   GdkBitmap *mask = NULL;
3290   gint x;
3291   gint y;
3292   gint width;
3293   gint height;
3294   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3295   GdkWindowAttr attributes;
3296   guint attributes_mask;
3297
3298   if (!reorder ||
3299       reorder->left_column == tree_view->priv->drag_column ||
3300       reorder->right_column == tree_view->priv->drag_column)
3301     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3302   else if (reorder->left_column || reorder->right_column)
3303     {
3304       GdkRectangle visible_rect;
3305       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3306       if (reorder->left_column)
3307         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
3308       else
3309         x = reorder->right_column->button->allocation.x;
3310
3311       if (x < visible_rect.x)
3312         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3313       else if (x > visible_rect.x + visible_rect.width)
3314         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3315       else
3316         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3317     }
3318
3319   /* We want to draw the rectangle over the initial location. */
3320   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3321     {
3322       GdkGC *gc;
3323       GdkColor col;
3324
3325       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3326         {
3327           if (tree_view->priv->drag_highlight_window)
3328             {
3329               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3330                                         NULL);
3331               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3332             }
3333
3334           attributes.window_type = GDK_WINDOW_CHILD;
3335           attributes.wclass = GDK_INPUT_OUTPUT;
3336           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3337           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3338           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3339           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3340           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3341           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3342
3343           width = tree_view->priv->drag_column->button->allocation.width;
3344           height = tree_view->priv->drag_column->button->allocation.height;
3345           gdk_window_move_resize (tree_view->priv->drag_highlight_window,
3346                                   tree_view->priv->drag_column_x, 0, width, height);
3347
3348           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3349           gc = gdk_gc_new (mask);
3350           col.pixel = 1;
3351           gdk_gc_set_foreground (gc, &col);
3352           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3353           col.pixel = 0;
3354           gdk_gc_set_foreground(gc, &col);
3355           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
3356           g_object_unref (gc);
3357
3358           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3359                                          mask, 0, 0);
3360           if (mask) g_object_unref (mask);
3361           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3362         }
3363     }
3364   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3365     {
3366       gint i, j = 1;
3367       GdkGC *gc;
3368       GdkColor col;
3369
3370       width = tree_view->priv->expander_size;
3371
3372       /* Get x, y, width, height of arrow */
3373       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3374       if (reorder->left_column)
3375         {
3376           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
3377           height = reorder->left_column->button->allocation.height;
3378         }
3379       else
3380         {
3381           x += reorder->right_column->button->allocation.x - width/2;
3382           height = reorder->right_column->button->allocation.height;
3383         }
3384       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3385       height += tree_view->priv->expander_size;
3386
3387       /* Create the new window */
3388       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3389         {
3390           if (tree_view->priv->drag_highlight_window)
3391             {
3392               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3393                                         NULL);
3394               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3395             }
3396
3397           attributes.window_type = GDK_WINDOW_TEMP;
3398           attributes.wclass = GDK_INPUT_OUTPUT;
3399           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3400           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3401           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3402           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3403           attributes.width = width;
3404           attributes.height = height;
3405           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3406                                                                    &attributes, attributes_mask);
3407           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3408
3409           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3410           gc = gdk_gc_new (mask);
3411           col.pixel = 1;
3412           gdk_gc_set_foreground (gc, &col);
3413           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3414
3415           /* Draw the 2 arrows as per above */
3416           col.pixel = 0;
3417           gdk_gc_set_foreground (gc, &col);
3418           for (i = 0; i < width; i ++)
3419             {
3420               if (i == (width/2 - 1))
3421                 continue;
3422               gdk_draw_line (mask, gc, i, j, i, height - j);
3423               if (i < (width/2 - 1))
3424                 j++;
3425               else
3426                 j--;
3427             }
3428           g_object_unref (gc);
3429           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3430                                          mask, 0, 0);
3431           if (mask) g_object_unref (mask);
3432         }
3433
3434       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3435       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3436     }
3437   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3438            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3439     {
3440       gint i, j = 1;
3441       GdkGC *gc;
3442       GdkColor col;
3443
3444       width = tree_view->priv->expander_size;
3445
3446       /* Get x, y, width, height of arrow */
3447       width = width/2; /* remember, the arrow only takes half the available width */
3448       gdk_window_get_origin (widget->window, &x, &y);
3449       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3450         x += widget->allocation.width - width;
3451
3452       if (reorder->left_column)
3453         height = reorder->left_column->button->allocation.height;
3454       else
3455         height = reorder->right_column->button->allocation.height;
3456
3457       y -= tree_view->priv->expander_size;
3458       height += 2*tree_view->priv->expander_size;
3459
3460       /* Create the new window */
3461       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3462           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3463         {
3464           if (tree_view->priv->drag_highlight_window)
3465             {
3466               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3467                                         NULL);
3468               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3469             }
3470
3471           attributes.window_type = GDK_WINDOW_TEMP;
3472           attributes.wclass = GDK_INPUT_OUTPUT;
3473           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3474           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3475           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3476           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3477           attributes.width = width;
3478           attributes.height = height;
3479           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3480           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3481
3482           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3483           gc = gdk_gc_new (mask);
3484           col.pixel = 1;
3485           gdk_gc_set_foreground (gc, &col);
3486           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3487
3488           /* Draw the 2 arrows as per above */
3489           col.pixel = 0;
3490           gdk_gc_set_foreground (gc, &col);
3491           j = tree_view->priv->expander_size;
3492           for (i = 0; i < width; i ++)
3493             {
3494               gint k;
3495               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3496                 k = width - i - 1;
3497               else
3498                 k = i;
3499               gdk_draw_line (mask, gc, k, j, k, height - j);
3500               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
3501               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
3502               j--;
3503             }
3504           g_object_unref (gc);
3505           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3506                                          mask, 0, 0);
3507           if (mask) g_object_unref (mask);
3508         }
3509
3510       tree_view->priv->drag_column_window_state = arrow_type;
3511       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3512    }
3513   else
3514     {
3515       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3516       gdk_window_hide (tree_view->priv->drag_highlight_window);
3517       return;
3518     }
3519
3520   gdk_window_show (tree_view->priv->drag_highlight_window);
3521   gdk_window_raise (tree_view->priv->drag_highlight_window);
3522 }
3523
3524 static gboolean
3525 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3526                                     GdkEventMotion *event)
3527 {
3528   gint x;
3529   gint new_width;
3530   GtkTreeViewColumn *column;
3531   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3532
3533   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3534
3535   if (event->is_hint || event->window != widget->window)
3536     gtk_widget_get_pointer (widget, &x, NULL);
3537   else
3538     x = event->x;
3539
3540   if (tree_view->priv->hadjustment)
3541     x += tree_view->priv->hadjustment->value;
3542
3543   new_width = gtk_tree_view_new_column_width (tree_view,
3544                                               tree_view->priv->drag_pos, &x);
3545   if (x != tree_view->priv->x_drag &&
3546       (new_width != column->fixed_width))
3547     {
3548       column->use_resized_width = TRUE;
3549       column->resized_width = new_width;
3550       gtk_widget_queue_resize (widget);
3551     }
3552
3553   return FALSE;
3554 }
3555
3556
3557 static void
3558 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3559 {
3560   GtkTreeViewColumnReorder *reorder = NULL;
3561   GList *list;
3562   gint mouse_x;
3563
3564   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3565   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3566     {
3567       reorder = (GtkTreeViewColumnReorder *) list->data;
3568       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3569         break;
3570       reorder = NULL;
3571     }
3572
3573   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3574       return;*/
3575
3576   tree_view->priv->cur_reorder = reorder;
3577   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3578 }
3579
3580 static void
3581 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3582 {
3583   GdkRectangle visible_rect;
3584   gint y;
3585   gint offset;
3586   gfloat value;
3587
3588   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3589   y += tree_view->priv->dy;
3590
3591   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3592
3593   /* see if we are near the edge. */
3594   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3595   if (offset > 0)
3596     {
3597       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3598       if (offset < 0)
3599         return;
3600     }
3601
3602   value = CLAMP (tree_view->priv->vadjustment->value + offset, 0.0,
3603                  tree_view->priv->vadjustment->upper - tree_view->priv->vadjustment->page_size);
3604   gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
3605 }
3606
3607 static gboolean
3608 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3609 {
3610   GdkRectangle visible_rect;
3611   gint x;
3612   gint offset;
3613   gfloat value;
3614
3615   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3616
3617   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3618
3619   /* See if we are near the edge. */
3620   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3621   if (offset > 0)
3622     {
3623       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3624       if (offset < 0)
3625         return TRUE;
3626     }
3627   offset = offset/3;
3628
3629   value = CLAMP (tree_view->priv->hadjustment->value + offset,
3630                  0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
3631   gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
3632
3633   return TRUE;
3634
3635 }
3636
3637 static gboolean
3638 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3639                                   GdkEventMotion *event)
3640 {
3641   GtkTreeView *tree_view = (GtkTreeView *) widget;
3642   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3643   gint x, y;
3644
3645   /* Sanity Check */
3646   if ((column == NULL) ||
3647       (event->window != tree_view->priv->drag_window))
3648     return FALSE;
3649
3650   /* Handle moving the header */
3651   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3652   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3653              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
3654   gdk_window_move (tree_view->priv->drag_window, x, y);
3655   
3656   /* autoscroll, if needed */
3657   gtk_tree_view_horizontal_autoscroll (tree_view);
3658   /* Update the current reorder position and arrow; */
3659   gtk_tree_view_update_current_reorder (tree_view);
3660
3661   return TRUE;
3662 }
3663
3664 static void
3665 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3666 {
3667   remove_scroll_timeout (tree_view);
3668   gtk_grab_remove (GTK_WIDGET (tree_view));
3669
3670   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3671
3672   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3673     {
3674       GtkTreePath *tmp_path;
3675
3676       /* The anchor path should be set to the start path */
3677       tmp_path = _gtk_tree_view_find_path (tree_view,
3678                                            tree_view->priv->rubber_band_start_tree,
3679                                            tree_view->priv->rubber_band_start_node);
3680
3681       if (tree_view->priv->anchor)
3682         gtk_tree_row_reference_free (tree_view->priv->anchor);
3683
3684       tree_view->priv->anchor =
3685         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3686                                           tree_view->priv->model,
3687                                           tmp_path);
3688
3689       gtk_tree_path_free (tmp_path);
3690
3691       /* ... and the cursor to the end path */
3692       tmp_path = _gtk_tree_view_find_path (tree_view,
3693                                            tree_view->priv->rubber_band_end_tree,
3694                                            tree_view->priv->rubber_band_end_node);
3695       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3696       gtk_tree_path_free (tmp_path);
3697
3698       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3699     }
3700
3701   /* Clear status variables */
3702   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3703   tree_view->priv->rubber_band_shift = 0;
3704   tree_view->priv->rubber_band_ctrl = 0;
3705
3706   tree_view->priv->rubber_band_start_node = NULL;
3707   tree_view->priv->rubber_band_start_tree = NULL;
3708   tree_view->priv->rubber_band_end_node = NULL;
3709   tree_view->priv->rubber_band_end_tree = NULL;
3710 }
3711
3712 static void
3713 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3714                                                  GtkRBTree   *start_tree,
3715                                                  GtkRBNode   *start_node,
3716                                                  GtkRBTree   *end_tree,
3717                                                  GtkRBNode   *end_node,
3718                                                  gboolean     select,
3719                                                  gboolean     skip_start,
3720                                                  gboolean     skip_end)
3721 {
3722   if (start_node == end_node)
3723     return;
3724
3725   /* We skip the first node and jump inside the loop */
3726   if (skip_start)
3727     goto skip_first;
3728
3729   do
3730     {
3731       /* Small optimization by assuming insensitive nodes are never
3732        * selected.
3733        */
3734       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3735         {
3736           GtkTreePath *path;
3737           gboolean selectable;
3738
3739           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3740           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3741           gtk_tree_path_free (path);
3742
3743           if (!selectable)
3744             goto node_not_selectable;
3745         }
3746
3747       if (select)
3748         {
3749           if (tree_view->priv->rubber_band_shift)
3750             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3751           else if (tree_view->priv->rubber_band_ctrl)
3752             {
3753               /* Toggle the selection state */
3754               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3755                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3756               else
3757                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3758             }
3759           else
3760             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3761         }
3762       else
3763         {
3764           /* Mirror the above */
3765           if (tree_view->priv->rubber_band_shift)
3766             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3767           else if (tree_view->priv->rubber_band_ctrl)
3768             {
3769               /* Toggle the selection state */
3770               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3771                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3772               else
3773                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3774             }
3775           else
3776             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3777         }
3778
3779       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3780
3781 node_not_selectable:
3782       if (start_node == end_node)
3783         break;
3784
3785 skip_first:
3786
3787       if (start_node->children)
3788         {
3789           start_tree = start_node->children;
3790           start_node = start_tree->root;
3791           while (start_node->left != start_tree->nil)
3792             start_node = start_node->left;
3793         }
3794       else
3795         {
3796           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3797
3798           if (!start_tree)
3799             /* Ran out of tree */
3800             break;
3801         }
3802
3803       if (skip_end && start_node == end_node)
3804         break;
3805     }
3806   while (TRUE);
3807 }
3808
3809 static void
3810 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3811 {
3812   GtkRBTree *start_tree, *end_tree;
3813   GtkRBNode *start_node, *end_node;
3814
3815   _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);
3816   _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);
3817
3818   /* Handle the start area first */
3819   if (!tree_view->priv->rubber_band_start_node)
3820     {
3821       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3822                                                        start_tree,
3823                                                        start_node,
3824                                                        end_tree,
3825                                                        end_node,
3826                                                        TRUE,
3827                                                        FALSE,
3828                                                        FALSE);
3829     }
3830   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3831            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3832     {
3833       /* New node is above the old one; selection became bigger */
3834       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3835                                                        start_tree,
3836                                                        start_node,
3837                                                        tree_view->priv->rubber_band_start_tree,
3838                                                        tree_view->priv->rubber_band_start_node,
3839                                                        TRUE,
3840                                                        FALSE,
3841                                                        TRUE);
3842     }
3843   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3844            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3845     {
3846       /* New node is below the old one; selection became smaller */
3847       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3848                                                        tree_view->priv->rubber_band_start_tree,
3849                                                        tree_view->priv->rubber_band_start_node,
3850                                                        start_tree,
3851                                                        start_node,
3852                                                        FALSE,
3853                                                        FALSE,
3854                                                        TRUE);
3855     }
3856
3857   tree_view->priv->rubber_band_start_tree = start_tree;
3858   tree_view->priv->rubber_band_start_node = start_node;
3859
3860   /* Next, handle the end area */
3861   if (!tree_view->priv->rubber_band_end_node)
3862     {
3863       /* In the event this happens, start_node was also NULL; this case is
3864        * handled above.
3865        */
3866     }
3867   else if (!end_node)
3868     {
3869       /* Find the last node in the tree */
3870       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3871                                &end_tree, &end_node);
3872
3873       /* Selection reached end of the tree */
3874       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3875                                                        tree_view->priv->rubber_band_end_tree,
3876                                                        tree_view->priv->rubber_band_end_node,
3877                                                        end_tree,
3878                                                        end_node,
3879                                                        TRUE,
3880                                                        TRUE,
3881                                                        FALSE);
3882     }
3883   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3884            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3885     {
3886       /* New node is below the old one; selection became bigger */
3887       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3888                                                        tree_view->priv->rubber_band_end_tree,
3889                                                        tree_view->priv->rubber_band_end_node,
3890                                                        end_tree,
3891                                                        end_node,
3892                                                        TRUE,
3893                                                        TRUE,
3894                                                        FALSE);
3895     }
3896   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
3897            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3898     {
3899       /* New node is above the old one; selection became smaller */
3900       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3901                                                        end_tree,
3902                                                        end_node,
3903                                                        tree_view->priv->rubber_band_end_tree,
3904                                                        tree_view->priv->rubber_band_end_node,
3905                                                        FALSE,
3906                                                        TRUE,
3907                                                        FALSE);
3908     }
3909
3910   tree_view->priv->rubber_band_end_tree = end_tree;
3911   tree_view->priv->rubber_band_end_node = end_node;
3912 }
3913
3914 static void
3915 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
3916 {
3917   gint x, y;
3918   GdkRectangle old_area;
3919   GdkRectangle new_area;
3920   GdkRectangle common;
3921   GdkRegion *invalid_region;
3922
3923   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
3924   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
3925   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
3926   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
3927
3928   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
3929
3930   x = MAX (x, 0);
3931   y = MAX (y, 0) + tree_view->priv->dy;
3932
3933   new_area.x = MIN (tree_view->priv->press_start_x, x);
3934   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
3935   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
3936   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
3937
3938   invalid_region = gdk_region_rectangle (&old_area);
3939   gdk_region_union_with_rect (invalid_region, &new_area);
3940
3941   gdk_rectangle_intersect (&old_area, &new_area, &common);
3942   if (common.width > 2 && common.height > 2)
3943     {
3944       GdkRegion *common_region;
3945
3946       /* make sure the border is invalidated */
3947       common.x += 1;
3948       common.y += 1;
3949       common.width -= 2;
3950       common.height -= 2;
3951
3952       common_region = gdk_region_rectangle (&common);
3953
3954       gdk_region_subtract (invalid_region, common_region);
3955       gdk_region_destroy (common_region);
3956     }
3957
3958   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
3959
3960   gdk_region_destroy (invalid_region);
3961
3962   tree_view->priv->rubber_band_x = x;
3963   tree_view->priv->rubber_band_y = y;
3964
3965   gtk_tree_view_update_rubber_band_selection (tree_view);
3966 }
3967
3968 static void
3969 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
3970                                 GdkRectangle *area)
3971 {
3972   cairo_t *cr;
3973   GdkRectangle rect;
3974   GdkRectangle rubber_rect;
3975
3976   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
3977   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
3978   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
3979   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
3980
3981   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
3982     return;
3983
3984   cr = gdk_cairo_create (tree_view->priv->bin_window);
3985   cairo_set_line_width (cr, 1.0);
3986
3987   cairo_set_source_rgba (cr,
3988                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
3989                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
3990                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
3991                          .25);
3992
3993   gdk_cairo_rectangle (cr, &rect);
3994   cairo_clip (cr);
3995   cairo_paint (cr);
3996
3997   cairo_set_source_rgb (cr,
3998                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
3999                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4000                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
4001
4002   cairo_rectangle (cr,
4003                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4004                    rubber_rect.width - 1, rubber_rect.height - 1);
4005   cairo_stroke (cr);
4006
4007   cairo_destroy (cr);
4008 }
4009
4010 static gboolean
4011 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4012                                  GdkEventMotion *event)
4013 {
4014   GtkTreeView *tree_view;
4015   GtkRBTree *tree;
4016   GtkRBNode *node;
4017   gint new_y;
4018
4019   tree_view = (GtkTreeView *) widget;
4020
4021   if (tree_view->priv->tree == NULL)
4022     return FALSE;
4023
4024   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4025     {
4026       gtk_grab_add (GTK_WIDGET (tree_view));
4027       gtk_tree_view_update_rubber_band (tree_view);
4028
4029       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4030     }
4031   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4032     {
4033       gtk_tree_view_update_rubber_band (tree_view);
4034
4035       add_scroll_timeout (tree_view);
4036     }
4037
4038   /* only check for an initiated drag when a button is pressed */
4039   if (tree_view->priv->pressed_button >= 0
4040       && !tree_view->priv->rubber_band_status)
4041     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4042
4043   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4044   if (new_y < 0)
4045     new_y = 0;
4046
4047   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4048
4049   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4050   if ((tree_view->priv->button_pressed_node != NULL) &&
4051       (tree_view->priv->button_pressed_node != node))
4052     node = NULL;
4053
4054   prelight_or_select (tree_view, tree, node, event->x, event->y);
4055
4056   return TRUE;
4057 }
4058
4059 static gboolean
4060 gtk_tree_view_motion (GtkWidget      *widget,
4061                       GdkEventMotion *event)
4062 {
4063   GtkTreeView *tree_view;
4064
4065   tree_view = (GtkTreeView *) widget;
4066
4067   /* Resizing a column */
4068   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4069     return gtk_tree_view_motion_resize_column (widget, event);
4070
4071   /* Drag column */
4072   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4073     return gtk_tree_view_motion_drag_column (widget, event);
4074
4075   /* Sanity check it */
4076   if (event->window == tree_view->priv->bin_window)
4077     return gtk_tree_view_motion_bin_window (widget, event);
4078
4079   return FALSE;
4080 }
4081
4082 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4083  * the tree is empty.
4084  */
4085 static void
4086 invalidate_empty_focus (GtkTreeView *tree_view)
4087 {
4088   GdkRectangle area;
4089
4090   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4091     return;
4092
4093   area.x = 0;
4094   area.y = 0;
4095   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4096   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4097 }
4098
4099 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4100  * is empty.
4101  */
4102 static void
4103 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4104 {
4105   gint w, h;
4106
4107   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4108     return;
4109
4110   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4111
4112   w -= 2;
4113   h -= 2;
4114
4115   if (w > 0 && h > 0)
4116     gtk_paint_focus (GTK_WIDGET (tree_view)->style,
4117                      tree_view->priv->bin_window,
4118                      GTK_WIDGET_STATE (tree_view),
4119                      clip_area,
4120                      GTK_WIDGET (tree_view),
4121                      NULL,
4122                      1, 1, w, h);
4123 }
4124
4125 static void
4126 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4127                                GdkEventExpose *event,
4128                                gint            n_visible_columns)
4129 {
4130   GList *list = tree_view->priv->columns;
4131   gint i = 0;
4132   gint current_x = 0;
4133
4134   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4135       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4136     return;
4137
4138   /* Only draw the lines for visible rows and columns */
4139   for (list = tree_view->priv->columns; list; list = list->next, i++)
4140     {
4141       GtkTreeViewColumn *column = list->data;
4142
4143       /* We don't want a line for the last column */
4144       if (i == n_visible_columns - 1)
4145         break;
4146
4147       if (! column->visible)
4148         continue;
4149
4150       current_x += column->width;
4151
4152       gdk_draw_line (event->window,
4153                      tree_view->priv->grid_line_gc,
4154                      current_x - 1, 0,
4155                      current_x - 1, tree_view->priv->height);
4156     }
4157 }
4158
4159 /* Warning: Very scary function.
4160  * Modify at your own risk
4161  *
4162  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4163  * FIXME: It's not...
4164  */
4165 static gboolean
4166 gtk_tree_view_bin_expose (GtkWidget      *widget,
4167                           GdkEventExpose *event)
4168 {
4169   GtkTreeView *tree_view;
4170   GtkTreePath *path;
4171   GtkRBTree *tree;
4172   GList *list;
4173   GtkRBNode *node;
4174   GtkRBNode *cursor = NULL;
4175   GtkRBTree *cursor_tree = NULL;
4176   GtkRBNode *drag_highlight = NULL;
4177   GtkRBTree *drag_highlight_tree = NULL;
4178   GtkTreeIter iter;
4179   gint new_y;
4180   gint y_offset, cell_offset;
4181   gint max_height;
4182   gint depth;
4183   GdkRectangle background_area;
4184   GdkRectangle cell_area;
4185   guint flags;
4186   gint highlight_x;
4187   gint expander_cell_width;
4188   gint bin_window_width;
4189   gint bin_window_height;
4190   GtkTreePath *cursor_path;
4191   GtkTreePath *drag_dest_path;
4192   GList *first_column, *last_column;
4193   gint vertical_separator;
4194   gint horizontal_separator;
4195   gint focus_line_width;
4196   gboolean allow_rules;
4197   gboolean has_special_cell;
4198   gboolean rtl;
4199   gint n_visible_columns;
4200   gint pointer_x, pointer_y;
4201   gint grid_line_width;
4202   gboolean got_pointer = FALSE;
4203   gboolean row_ending_details;
4204   gboolean draw_vgrid_lines, draw_hgrid_lines;
4205
4206   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
4207
4208   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4209
4210   tree_view = GTK_TREE_VIEW (widget);
4211
4212   gtk_widget_style_get (widget,
4213                         "horizontal-separator", &horizontal_separator,
4214                         "vertical-separator", &vertical_separator,
4215                         "allow-rules", &allow_rules,
4216                         "focus-line-width", &focus_line_width,
4217                         "row-ending-details", &row_ending_details,
4218                         NULL);
4219
4220   if (tree_view->priv->tree == NULL)
4221     {
4222       draw_empty_focus (tree_view, &event->area);
4223       return TRUE;
4224     }
4225
4226   /* clip event->area to the visible area */
4227   if (event->area.height < 0)
4228     return TRUE;
4229
4230   validate_visible_area (tree_view);
4231
4232   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4233
4234   if (new_y < 0)
4235     new_y = 0;
4236   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4237   gdk_drawable_get_size (tree_view->priv->bin_window,
4238                          &bin_window_width, &bin_window_height);
4239
4240   if (tree_view->priv->height < bin_window_height)
4241     {
4242       gtk_paint_flat_box (widget->style,
4243                           event->window,
4244                           widget->state,
4245                           GTK_SHADOW_NONE,
4246                           &event->area,
4247                           widget,
4248                           "cell_even",
4249                           0, tree_view->priv->height,
4250                           bin_window_width,
4251                           bin_window_height - tree_view->priv->height);
4252     }
4253
4254   if (node == NULL)
4255     return TRUE;
4256
4257   /* find the path for the node */
4258   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4259                                    tree,
4260                                    node);
4261   gtk_tree_model_get_iter (tree_view->priv->model,
4262                            &iter,
4263                            path);
4264   depth = gtk_tree_path_get_depth (path);
4265   gtk_tree_path_free (path);
4266   
4267   cursor_path = NULL;
4268   drag_dest_path = NULL;
4269
4270   if (tree_view->priv->cursor)
4271     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4272
4273   if (cursor_path)
4274     _gtk_tree_view_find_node (tree_view, cursor_path,
4275                               &cursor_tree, &cursor);
4276
4277   if (tree_view->priv->drag_dest_row)
4278     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4279
4280   if (drag_dest_path)
4281     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4282                               &drag_highlight_tree, &drag_highlight);
4283
4284   draw_vgrid_lines =
4285     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4286     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4287   draw_hgrid_lines =
4288     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4289     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4290
4291   if (draw_vgrid_lines || draw_hgrid_lines)
4292     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4293   
4294   n_visible_columns = 0;
4295   for (list = tree_view->priv->columns; list; list = list->next)
4296     {
4297       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4298         continue;
4299       n_visible_columns ++;
4300     }
4301
4302   /* Find the last column */
4303   for (last_column = g_list_last (tree_view->priv->columns);
4304        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4305        last_column = last_column->prev)
4306     ;
4307
4308   /* and the first */
4309   for (first_column = g_list_first (tree_view->priv->columns);
4310        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4311        first_column = first_column->next)
4312     ;
4313
4314   /* Actually process the expose event.  To do this, we want to
4315    * start at the first node of the event, and walk the tree in
4316    * order, drawing each successive node.
4317    */
4318
4319   do
4320     {
4321       gboolean parity;
4322       gboolean is_separator = FALSE;
4323       gboolean is_first = FALSE;
4324       gboolean is_last = FALSE;
4325       
4326       is_separator = row_is_separator (tree_view, &iter, NULL);
4327
4328       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4329
4330       cell_offset = 0;
4331       highlight_x = 0; /* should match x coord of first cell */
4332       expander_cell_width = 0;
4333
4334       background_area.y = y_offset + event->area.y;
4335       background_area.height = max_height;
4336
4337       flags = 0;
4338
4339       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4340         flags |= GTK_CELL_RENDERER_PRELIT;
4341
4342       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4343         flags |= GTK_CELL_RENDERER_SELECTED;
4344
4345       parity = _gtk_rbtree_node_find_parity (tree, node);
4346
4347       /* we *need* to set cell data on all cells before the call
4348        * to _has_special_cell, else _has_special_cell() does not
4349        * return a correct value.
4350        */
4351       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4352            list;
4353            list = (rtl ? list->prev : list->next))
4354         {
4355           GtkTreeViewColumn *column = list->data;
4356           gtk_tree_view_column_cell_set_cell_data (column,
4357                                                    tree_view->priv->model,
4358                                                    &iter,
4359                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4360                                                    node->children?TRUE:FALSE);
4361         }
4362
4363       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4364
4365       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4366            list;
4367            list = (rtl ? list->prev : list->next))
4368         {
4369           GtkTreeViewColumn *column = list->data;
4370           const gchar *detail = NULL;
4371           GtkStateType state;
4372
4373           if (!column->visible)
4374             continue;
4375
4376           if (cell_offset > event->area.x + event->area.width ||
4377               cell_offset + column->width < event->area.x)
4378             {
4379               cell_offset += column->width;
4380               continue;
4381             }
4382
4383           if (column->show_sort_indicator)
4384             flags |= GTK_CELL_RENDERER_SORTED;
4385           else
4386             flags &= ~GTK_CELL_RENDERER_SORTED;
4387
4388           if (cursor == node)
4389             flags |= GTK_CELL_RENDERER_FOCUSED;
4390           else
4391             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4392
4393           background_area.x = cell_offset;
4394           background_area.width = column->width;
4395
4396           cell_area = background_area;
4397           cell_area.y += vertical_separator / 2;
4398           cell_area.x += horizontal_separator / 2;
4399           cell_area.height -= vertical_separator;
4400           cell_area.width -= horizontal_separator;
4401
4402           if (draw_vgrid_lines)
4403             {
4404               if (list == first_column)
4405                 {
4406                   cell_area.width -= grid_line_width / 2;
4407                 }
4408               else if (list == last_column)
4409                 {
4410                   cell_area.x += grid_line_width / 2;
4411                   cell_area.width -= grid_line_width / 2;
4412                 }
4413               else
4414                 {
4415                   cell_area.x += grid_line_width / 2;
4416                   cell_area.width -= grid_line_width;
4417                 }
4418             }
4419
4420           if (draw_hgrid_lines)
4421             {
4422               cell_area.y += grid_line_width / 2;
4423               cell_area.height -= grid_line_width;
4424             }
4425
4426           if (gdk_region_rect_in (event->region, &background_area) == GDK_OVERLAP_RECTANGLE_OUT)
4427             {
4428               cell_offset += column->width;
4429               continue;
4430             }
4431
4432           gtk_tree_view_column_cell_set_cell_data (column,
4433                                                    tree_view->priv->model,
4434                                                    &iter,
4435                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4436                                                    node->children?TRUE:FALSE);
4437
4438           /* Select the detail for drawing the cell.  relevant
4439            * factors are parity, sortedness, and whether to
4440            * display rules.
4441            */
4442           if (allow_rules && tree_view->priv->has_rules)
4443             {
4444               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4445                   n_visible_columns >= 3)
4446                 {
4447                   if (parity)
4448                     detail = "cell_odd_ruled_sorted";
4449                   else
4450                     detail = "cell_even_ruled_sorted";
4451                 }
4452               else
4453                 {
4454                   if (parity)
4455                     detail = "cell_odd_ruled";
4456                   else
4457                     detail = "cell_even_ruled";
4458                 }
4459             }
4460           else
4461             {
4462               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4463                   n_visible_columns >= 3)
4464                 {
4465                   if (parity)
4466                     detail = "cell_odd_sorted";
4467                   else
4468                     detail = "cell_even_sorted";
4469                 }
4470               else
4471                 {
4472                   if (parity)
4473                     detail = "cell_odd";
4474                   else
4475                     detail = "cell_even";
4476                 }
4477             }
4478
4479           g_assert (detail);
4480
4481           if (widget->state == GTK_STATE_INSENSITIVE)
4482             state = GTK_STATE_INSENSITIVE;          
4483           else if (flags & GTK_CELL_RENDERER_SELECTED)
4484             state = GTK_STATE_SELECTED;
4485           else
4486             state = GTK_STATE_NORMAL;
4487
4488           /* Draw background */
4489           if (row_ending_details)
4490             {
4491               char new_detail[128];
4492
4493               is_first = (rtl ? !list->next : !list->prev);
4494               is_last = (rtl ? !list->prev : !list->next);
4495
4496               /* (I don't like the snprintfs either, but couldn't find a
4497                * less messy way).
4498                */
4499               if (is_first && is_last)
4500                 g_snprintf (new_detail, 127, "%s", detail);
4501               else if (is_first)
4502                 g_snprintf (new_detail, 127, "%s_start", detail);
4503               else if (is_last)
4504                 g_snprintf (new_detail, 127, "%s_end", detail);
4505               else
4506                 g_snprintf (new_detail, 128, "%s_middle", detail);
4507
4508               gtk_paint_flat_box (widget->style,
4509                                   event->window,
4510                                   state,
4511                                   GTK_SHADOW_NONE,
4512                                   &event->area,
4513                                   widget,
4514                                   new_detail,
4515                                   background_area.x,
4516                                   background_area.y,
4517                                   background_area.width,
4518                                   background_area.height);
4519             }
4520           else
4521             {
4522               gtk_paint_flat_box (widget->style,
4523                                   event->window,
4524                                   state,
4525                                   GTK_SHADOW_NONE,
4526                                   &event->area,
4527                                   widget,
4528                                   detail,
4529                                   background_area.x,
4530                                   background_area.y,
4531                                   background_area.width,
4532                                   background_area.height);
4533             }
4534
4535           if (draw_hgrid_lines)
4536             {
4537               if (background_area.y > 0)
4538                 gdk_draw_line (event->window,
4539                                tree_view->priv->grid_line_gc,
4540                                background_area.x, background_area.y,
4541                                background_area.x + background_area.width,
4542                                background_area.y);
4543
4544               if (y_offset + max_height >= event->area.height)
4545                 gdk_draw_line (event->window,
4546                                tree_view->priv->grid_line_gc,
4547                                background_area.x, background_area.y + max_height,
4548                                background_area.x + background_area.width,
4549                                background_area.y + max_height);
4550             }
4551
4552           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4553               tree_view->priv->tree_lines_enabled)
4554             {
4555               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4556                   && depth > 1)
4557                 {
4558                   gdk_draw_line (event->window,
4559                                  tree_view->priv->tree_line_gc,
4560                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4561                                  background_area.y + background_area.height / 2,
4562                                  background_area.x + tree_view->priv->expander_size * (depth - 1.1),
4563                                  background_area.y + background_area.height / 2);
4564                 }
4565               else if (depth > 1)
4566                 {
4567                   gdk_draw_line (event->window,
4568                                  tree_view->priv->tree_line_gc,
4569                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4570                                  background_area.y + background_area.height / 2,
4571                                  background_area.x + tree_view->priv->expander_size * (depth - 0.5),
4572                                  background_area.y + background_area.height / 2);
4573                 }
4574
4575               if (depth > 1)
4576                 {
4577                   gint i;
4578                   GtkRBNode *tmp_node;
4579                   GtkRBTree *tmp_tree;
4580
4581                   if (!_gtk_rbtree_next (tree, node))
4582                     gdk_draw_line (event->window,
4583                                    tree_view->priv->tree_line_gc,
4584                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4585                                    background_area.y,
4586                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4587                                    background_area.y + background_area.height / 2);
4588                   else
4589                     gdk_draw_line (event->window,
4590                                    tree_view->priv->tree_line_gc,
4591                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4592                                    background_area.y,
4593                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4594                                    background_area.y + background_area.height);
4595
4596                   tmp_node = tree->parent_node;
4597                   tmp_tree = tree->parent_tree;
4598
4599                   for (i = depth - 2; i > 0; i--)
4600                     {
4601                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4602                         gdk_draw_line (event->window,
4603                                        tree_view->priv->tree_line_gc,
4604                                        background_area.x + tree_view->priv->expander_size * (i - 0.5),
4605                                        background_area.y,
4606                                        background_area.x + tree_view->priv->expander_size * (i - 0.5),
4607                                        background_area.y + background_area.height);
4608
4609                       tmp_node = tmp_tree->parent_node;
4610                       tmp_tree = tmp_tree->parent_tree;
4611                     }
4612                 }
4613             }
4614
4615           if (gtk_tree_view_is_expander_column (tree_view, column))
4616             {
4617               if (!rtl)
4618                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4619               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4620
4621               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4622                 {
4623                   if (!rtl)
4624                     cell_area.x += depth * tree_view->priv->expander_size;
4625                   cell_area.width -= depth * tree_view->priv->expander_size;
4626                 }
4627
4628               /* If we have an expander column, the highlight underline
4629                * starts with that column, so that it indicates which
4630                * level of the tree we're dropping at.
4631                */
4632               highlight_x = cell_area.x;
4633               expander_cell_width = cell_area.width;
4634
4635               if (is_separator)
4636                 gtk_paint_hline (widget->style,
4637                                  event->window,
4638                                  state,
4639                                  &cell_area,
4640                                  widget,
4641                                  NULL,
4642                                  cell_area.x,
4643                                  cell_area.x + cell_area.width,
4644                                  cell_area.y + cell_area.height / 2);
4645               else
4646                 _gtk_tree_view_column_cell_render (column,
4647                                                    event->window,
4648                                                    &background_area,
4649                                                    &cell_area,
4650                                                    &event->area,
4651                                                    flags);
4652               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4653                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4654                 {
4655                   if (!got_pointer)
4656                     {
4657                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4658                                               &pointer_x, &pointer_y, NULL);
4659                       got_pointer = TRUE;
4660                     }
4661
4662                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4663                                             tree,
4664                                             node,
4665                                             pointer_x, pointer_y);
4666                 }
4667             }
4668           else
4669             {
4670               if (is_separator)
4671                 gtk_paint_hline (widget->style,
4672                                  event->window,
4673                                  state,
4674                                  &cell_area,
4675                                  widget,
4676                                  NULL,
4677                                  cell_area.x,
4678                                  cell_area.x + cell_area.width,
4679                                  cell_area.y + cell_area.height / 2);
4680               else
4681                 _gtk_tree_view_column_cell_render (column,
4682                                                    event->window,
4683                                                    &background_area,
4684                                                    &cell_area,
4685                                                    &event->area,
4686                                                    flags);
4687             }
4688           if (node == cursor && has_special_cell &&
4689               ((column == tree_view->priv->focus_column &&
4690                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4691                 GTK_WIDGET_HAS_FOCUS (widget)) ||
4692                (column == tree_view->priv->edited_column)))
4693             {
4694               _gtk_tree_view_column_cell_draw_focus (column,
4695                                                      event->window,
4696                                                      &background_area,
4697                                                      &cell_area,
4698                                                      &event->area,
4699                                                      flags);
4700             }
4701           cell_offset += column->width;
4702         }
4703
4704       if (node == drag_highlight)
4705         {
4706           /* Draw indicator for the drop
4707            */
4708           gint highlight_y = -1;
4709           GtkRBTree *tree = NULL;
4710           GtkRBNode *node = NULL;
4711           gint width;
4712
4713           switch (tree_view->priv->drag_dest_pos)
4714             {
4715             case GTK_TREE_VIEW_DROP_BEFORE:
4716               highlight_y = background_area.y - 1;
4717               if (highlight_y < 0)
4718                       highlight_y = 0;
4719               break;
4720
4721             case GTK_TREE_VIEW_DROP_AFTER:
4722               highlight_y = background_area.y + background_area.height - 1;
4723               break;
4724
4725             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4726             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4727               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4728
4729               if (tree == NULL)
4730                 break;
4731               gdk_drawable_get_size (tree_view->priv->bin_window,
4732                                      &width, NULL);
4733
4734               if (row_ending_details)
4735                 gtk_paint_focus (widget->style,
4736                                  tree_view->priv->bin_window,
4737                                  GTK_WIDGET_STATE (widget),
4738                                  &event->area,
4739                                  widget,
4740                                  (is_first
4741                                   ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4742                                   : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4743                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4744                                  - focus_line_width / 2,
4745                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4746                                - focus_line_width + 1);
4747               else
4748                 gtk_paint_focus (widget->style,
4749                                  tree_view->priv->bin_window,
4750                                  GTK_WIDGET_STATE (widget),
4751                                  &event->area,
4752                                  widget,
4753                                  "treeview-drop-indicator",
4754                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4755                                  - focus_line_width / 2,
4756                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4757                                  - focus_line_width + 1);
4758               break;
4759             }
4760
4761           if (highlight_y >= 0)
4762             {
4763               gdk_draw_line (event->window,
4764                              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
4765                              rtl ? highlight_x + expander_cell_width : highlight_x,
4766                              highlight_y,
4767                              rtl ? 0 : bin_window_width,
4768                              highlight_y);
4769             }
4770         }
4771
4772       /* draw the big row-spanning focus rectangle, if needed */
4773       if (!has_special_cell && node == cursor &&
4774           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4775           GTK_WIDGET_HAS_FOCUS (widget))
4776         {
4777           gint tmp_y, tmp_height;
4778           gint width;
4779           GtkStateType focus_rect_state;
4780
4781           focus_rect_state =
4782             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4783             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4784              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4785               GTK_STATE_NORMAL));
4786
4787           gdk_drawable_get_size (tree_view->priv->bin_window,
4788                                  &width, NULL);
4789           
4790           if (draw_hgrid_lines)
4791             {
4792               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4793               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4794             }
4795           else
4796             {
4797               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4798               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4799             }
4800
4801           if (row_ending_details)
4802             gtk_paint_focus (widget->style,
4803                              tree_view->priv->bin_window,
4804                              focus_rect_state,
4805                              &event->area,
4806                              widget,
4807                              (is_first
4808                               ? (is_last ? "treeview" : "treeview-left" )
4809                               : (is_last ? "treeview-right" : "treeview-middle" )),
4810                              0, tmp_y,
4811                              width, tmp_height);
4812           else
4813             gtk_paint_focus (widget->style,
4814                              tree_view->priv->bin_window,
4815                              focus_rect_state,
4816                              &event->area,
4817                              widget,
4818                              "treeview",
4819                              0, tmp_y,
4820                              width, tmp_height);
4821         }
4822
4823       y_offset += max_height;
4824       if (node->children)
4825         {
4826           GtkTreeIter parent = iter;
4827           gboolean has_child;
4828
4829           tree = node->children;
4830           node = tree->root;
4831
4832           g_assert (node != tree->nil);
4833
4834           while (node->left != tree->nil)
4835             node = node->left;
4836           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4837                                                     &iter,
4838                                                     &parent);
4839           depth++;
4840
4841           /* Sanity Check! */
4842           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4843         }
4844       else
4845         {
4846           gboolean done = FALSE;
4847
4848           do
4849             {
4850               node = _gtk_rbtree_next (tree, node);
4851               if (node != NULL)
4852                 {
4853                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4854                   done = TRUE;
4855
4856                   /* Sanity Check! */
4857                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4858                 }
4859               else
4860                 {
4861                   GtkTreeIter parent_iter = iter;
4862                   gboolean has_parent;
4863
4864                   node = tree->parent_node;
4865                   tree = tree->parent_tree;
4866                   if (tree == NULL)
4867                     /* we should go to done to free some memory */
4868                     goto done;
4869                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4870                                                            &iter,
4871                                                            &parent_iter);
4872                   depth--;
4873
4874                   /* Sanity check */
4875                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
4876                 }
4877             }
4878           while (!done);
4879         }
4880     }
4881   while (y_offset < event->area.height);
4882
4883 done:
4884   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
4885
4886  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4887    {
4888      GdkRectangle *rectangles;
4889      gint n_rectangles;
4890
4891      gdk_region_get_rectangles (event->region,
4892                                 &rectangles,
4893                                 &n_rectangles);
4894
4895      while (n_rectangles--)
4896        gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
4897
4898      g_free (rectangles);
4899    }
4900
4901   if (cursor_path)
4902     gtk_tree_path_free (cursor_path);
4903
4904   if (drag_dest_path)
4905     gtk_tree_path_free (drag_dest_path);
4906
4907   return FALSE;
4908 }
4909
4910 static gboolean
4911 gtk_tree_view_expose (GtkWidget      *widget,
4912                       GdkEventExpose *event)
4913 {
4914   GtkTreeView *tree_view;
4915
4916   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
4917
4918   tree_view = GTK_TREE_VIEW (widget);
4919
4920   if (event->window == tree_view->priv->bin_window)
4921     {
4922       gboolean retval;
4923       GList *tmp_list;
4924
4925       retval = gtk_tree_view_bin_expose (widget, event);
4926
4927       /* We can't just chain up to Container::expose as it will try to send the
4928        * event to the headers, so we handle propagating it to our children
4929        * (eg. widgets being edited) ourselves.
4930        */
4931       tmp_list = tree_view->priv->children;
4932       while (tmp_list)
4933         {
4934           GtkTreeViewChild *child = tmp_list->data;
4935           tmp_list = tmp_list->next;
4936
4937           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
4938         }
4939
4940       return retval;
4941     }
4942
4943   else if (event->window == tree_view->priv->header_window)
4944     {
4945       GList *list;
4946       
4947       for (list = tree_view->priv->columns; list != NULL; list = list->next)
4948         {
4949           GtkTreeViewColumn *column = list->data;
4950
4951           if (column == tree_view->priv->drag_column)
4952             continue;
4953
4954           if (column->visible)
4955             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4956                                             column->button,
4957                                             event);
4958         }
4959     }
4960   else if (event->window == tree_view->priv->drag_window)
4961     {
4962       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4963                                       tree_view->priv->drag_column->button,
4964                                       event);
4965     }
4966   return TRUE;
4967 }
4968
4969 enum
4970 {
4971   DROP_HOME,
4972   DROP_RIGHT,
4973   DROP_LEFT,
4974   DROP_END
4975 };
4976
4977 /* returns 0x1 when no column has been found -- yes it's hackish */
4978 static GtkTreeViewColumn *
4979 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
4980                                GtkTreeViewColumn *column,
4981                                gint               drop_position)
4982 {
4983   GtkTreeViewColumn *left_column = NULL;
4984   GtkTreeViewColumn *cur_column = NULL;
4985   GList *tmp_list;
4986
4987   if (!column->reorderable)
4988     return (GtkTreeViewColumn *)0x1;
4989
4990   switch (drop_position)
4991     {
4992       case DROP_HOME:
4993         /* find first column where we can drop */
4994         tmp_list = tree_view->priv->columns;
4995         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
4996           return (GtkTreeViewColumn *)0x1;
4997
4998         while (tmp_list)
4999           {
5000             g_assert (tmp_list);
5001
5002             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5003             tmp_list = tmp_list->next;
5004
5005             if (left_column && left_column->visible == FALSE)
5006               continue;
5007
5008             if (!tree_view->priv->column_drop_func)
5009               return left_column;
5010
5011             if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5012               {
5013                 left_column = cur_column;
5014                 continue;
5015               }
5016
5017             return left_column;
5018           }
5019
5020         if (!tree_view->priv->column_drop_func)
5021           return left_column;
5022
5023         if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5024           return left_column;
5025         else
5026           return (GtkTreeViewColumn *)0x1;
5027         break;
5028
5029       case DROP_RIGHT:
5030         /* find first column after column where we can drop */
5031         tmp_list = tree_view->priv->columns;
5032
5033         for (; tmp_list; tmp_list = tmp_list->next)
5034           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5035             break;
5036
5037         if (!tmp_list || !tmp_list->next)
5038           return (GtkTreeViewColumn *)0x1;
5039
5040         tmp_list = tmp_list->next;
5041         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5042         tmp_list = tmp_list->next;
5043
5044         while (tmp_list)
5045           {
5046             g_assert (tmp_list);
5047
5048             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5049             tmp_list = tmp_list->next;
5050
5051             if (left_column && left_column->visible == FALSE)
5052               {
5053                 left_column = cur_column;
5054                 if (tmp_list)
5055                   tmp_list = tmp_list->next;
5056                 continue;
5057               }
5058
5059             if (!tree_view->priv->column_drop_func)
5060               return left_column;
5061
5062             if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5063               {
5064                 left_column = cur_column;
5065                 continue;
5066               }
5067
5068             return left_column;
5069           }
5070
5071         if (!tree_view->priv->column_drop_func)
5072           return left_column;
5073
5074         if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5075           return left_column;
5076         else
5077           return (GtkTreeViewColumn *)0x1;
5078         break;
5079
5080       case DROP_LEFT:
5081         /* find first column before column where we can drop */
5082         tmp_list = tree_view->priv->columns;
5083
5084         for (; tmp_list; tmp_list = tmp_list->next)
5085           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5086             break;
5087
5088         if (!tmp_list || !tmp_list->prev)
5089           return (GtkTreeViewColumn *)0x1;
5090
5091         tmp_list = tmp_list->prev;
5092         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5093         tmp_list = tmp_list->prev;
5094
5095         while (tmp_list)
5096           {
5097             g_assert (tmp_list);
5098
5099             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5100
5101             if (left_column && !left_column->visible)
5102               {
5103                 /*if (!tmp_list->prev)
5104                   return (GtkTreeViewColumn *)0x1;
5105                   */
5106 /*
5107                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5108                 tmp_list = tmp_list->prev->prev;
5109                 continue;*/
5110
5111                 cur_column = left_column;
5112                 if (tmp_list)
5113                   tmp_list = tmp_list->prev;
5114                 continue;
5115               }
5116
5117             if (!tree_view->priv->column_drop_func)
5118               return left_column;
5119
5120             if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5121               return left_column;
5122
5123             cur_column = left_column;
5124             tmp_list = tmp_list->prev;
5125           }
5126
5127         if (!tree_view->priv->column_drop_func)
5128           return NULL;
5129
5130         if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5131           return NULL;
5132         else
5133           return (GtkTreeViewColumn *)0x1;
5134         break;
5135
5136       case DROP_END:
5137         /* same as DROP_HOME case, but doing it backwards */
5138         tmp_list = g_list_last (tree_view->priv->columns);
5139         cur_column = NULL;
5140
5141         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5142           return (GtkTreeViewColumn *)0x1;
5143
5144         while (tmp_list)
5145           {
5146             g_assert (tmp_list);
5147
5148             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5149
5150             if (left_column && !left_column->visible)
5151               {
5152                 cur_column = left_column;
5153                 tmp_list = tmp_list->prev;
5154               }
5155
5156             if (!tree_view->priv->column_drop_func)
5157               return left_column;
5158
5159             if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5160               return left_column;
5161
5162             cur_column = left_column;
5163             tmp_list = tmp_list->prev;
5164           }
5165
5166         if (!tree_view->priv->column_drop_func)
5167           return NULL;
5168
5169         if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5170           return NULL;
5171         else
5172           return (GtkTreeViewColumn *)0x1;
5173         break;
5174     }
5175
5176   return (GtkTreeViewColumn *)0x1;
5177 }
5178
5179 static gboolean
5180 gtk_tree_view_key_press (GtkWidget   *widget,
5181                          GdkEventKey *event)
5182 {
5183   GtkTreeView *tree_view = (GtkTreeView *) widget;
5184
5185   if (tree_view->priv->rubber_band_status)
5186     {
5187       if (event->keyval == GDK_Escape)
5188         gtk_tree_view_stop_rubber_band (tree_view);
5189
5190       return TRUE;
5191     }
5192
5193   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5194     {
5195       if (event->keyval == GDK_Escape)
5196         {
5197           tree_view->priv->cur_reorder = NULL;
5198           gtk_tree_view_button_release_drag_column (widget, NULL);
5199         }
5200       return TRUE;
5201     }
5202
5203   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5204     {
5205       GList *focus_column;
5206       gboolean rtl;
5207
5208       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5209
5210       for (focus_column = tree_view->priv->columns;
5211            focus_column;
5212            focus_column = focus_column->next)
5213         {
5214           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5215
5216           if (GTK_WIDGET_HAS_FOCUS (column->button))
5217             break;
5218         }
5219
5220       if (focus_column &&
5221           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5222           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5223            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
5224         {
5225           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5226
5227           if (!column->resizable)
5228             {
5229               gtk_widget_error_bell (widget);
5230               return TRUE;
5231             }
5232
5233           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5234               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5235             {
5236               gint old_width = column->resized_width;
5237
5238               column->resized_width = MAX (column->resized_width,
5239                                            column->width);
5240               column->resized_width -= 2;
5241               if (column->resized_width < 0)
5242                 column->resized_width = 0;
5243
5244               if (column->min_width == -1)
5245                 column->resized_width = MAX (column->button->requisition.width,
5246                                              column->resized_width);
5247               else
5248                 column->resized_width = MAX (column->min_width,
5249                                              column->resized_width);
5250
5251               if (column->max_width != -1)
5252                 column->resized_width = MIN (column->resized_width,
5253                                              column->max_width);
5254
5255               column->use_resized_width = TRUE;
5256
5257               if (column->resized_width != old_width)
5258                 gtk_widget_queue_resize (widget);
5259               else
5260                 gtk_widget_error_bell (widget);
5261             }
5262           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5263                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5264             {
5265               gint old_width = column->resized_width;
5266
5267               column->resized_width = MAX (column->resized_width,
5268                                            column->width);
5269               column->resized_width += 2;
5270
5271               if (column->max_width != -1)
5272                 column->resized_width = MIN (column->resized_width,
5273                                              column->max_width);
5274
5275               column->use_resized_width = TRUE;
5276
5277               if (column->resized_width != old_width)
5278                 gtk_widget_queue_resize (widget);
5279               else
5280                 gtk_widget_error_bell (widget);
5281             }
5282
5283           return TRUE;
5284         }
5285
5286       if (focus_column &&
5287           (event->state & GDK_MOD1_MASK) &&
5288           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5289            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
5290            || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
5291            || event->keyval == GDK_End || event->keyval == GDK_KP_End))
5292         {
5293           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5294
5295           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5296               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5297             {
5298               GtkTreeViewColumn *col;
5299               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5300               if (col != (GtkTreeViewColumn *)0x1)
5301                 gtk_tree_view_move_column_after (tree_view, column, col);
5302               else
5303                 gtk_widget_error_bell (widget);
5304             }
5305           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5306                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5307             {
5308               GtkTreeViewColumn *col;
5309               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5310               if (col != (GtkTreeViewColumn *)0x1)
5311                 gtk_tree_view_move_column_after (tree_view, column, col);
5312               else
5313                 gtk_widget_error_bell (widget);
5314             }
5315           else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
5316             {
5317               GtkTreeViewColumn *col;
5318               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5319               if (col != (GtkTreeViewColumn *)0x1)
5320                 gtk_tree_view_move_column_after (tree_view, column, col);
5321               else
5322                 gtk_widget_error_bell (widget);
5323             }
5324           else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
5325             {
5326               GtkTreeViewColumn *col;
5327               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5328               if (col != (GtkTreeViewColumn *)0x1)
5329                 gtk_tree_view_move_column_after (tree_view, column, col);
5330               else
5331                 gtk_widget_error_bell (widget);
5332             }
5333
5334           return TRUE;
5335         }
5336     }
5337
5338   /* Chain up to the parent class.  It handles the keybindings. */
5339   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5340     return TRUE;
5341
5342   /* We pass the event to the search_entry.  If its text changes, then we start
5343    * the typeahead find capabilities. */
5344   if (GTK_WIDGET_HAS_FOCUS (tree_view)
5345       && tree_view->priv->enable_search
5346       && !tree_view->priv->search_custom_entry_set)
5347     {
5348       GdkEvent *new_event;
5349       char *old_text;
5350       const char *new_text;
5351       gboolean retval;
5352       GdkScreen *screen;
5353       gboolean text_modified;
5354       gulong popup_menu_id;
5355
5356       gtk_tree_view_ensure_interactive_directory (tree_view);
5357
5358       /* Make a copy of the current text */
5359       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5360       new_event = gdk_event_copy ((GdkEvent *) event);
5361       g_object_unref (((GdkEventKey *) new_event)->window);
5362       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5363       gtk_widget_realize (tree_view->priv->search_window);
5364
5365       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5366                                         "popup_menu", G_CALLBACK (gtk_true), NULL);
5367
5368       /* Move the entry off screen */
5369       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5370       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5371                        gdk_screen_get_width (screen) + 1,
5372                        gdk_screen_get_height (screen) + 1);
5373       gtk_widget_show (tree_view->priv->search_window);
5374
5375       /* Send the event to the window.  If the preedit_changed signal is emitted
5376        * during this event, we will set priv->imcontext_changed  */
5377       tree_view->priv->imcontext_changed = FALSE;
5378       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5379       gdk_event_free (new_event);
5380       gtk_widget_hide (tree_view->priv->search_window);
5381
5382       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5383                                    popup_menu_id);
5384
5385       /* We check to make sure that the entry tried to handle the text, and that
5386        * the text has changed.
5387        */
5388       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5389       text_modified = strcmp (old_text, new_text) != 0;
5390       g_free (old_text);
5391       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5392           (retval && text_modified))               /* ...or the text was modified */
5393         {
5394           if (gtk_tree_view_real_start_interactive_search (tree_view, FALSE))
5395             {
5396               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5397               return TRUE;
5398             }
5399           else
5400             {
5401               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5402               return FALSE;
5403             }
5404         }
5405     }
5406
5407   return FALSE;
5408 }
5409
5410 static gboolean
5411 gtk_tree_view_key_release (GtkWidget   *widget,
5412                            GdkEventKey *event)
5413 {
5414   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5415
5416   if (tree_view->priv->rubber_band_status)
5417     return TRUE;
5418
5419   return (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event) (widget, event);
5420 }
5421
5422 /* FIXME Is this function necessary? Can I get an enter_notify event
5423  * w/o either an expose event or a mouse motion event?
5424  */
5425 static gboolean
5426 gtk_tree_view_enter_notify (GtkWidget        *widget,
5427                             GdkEventCrossing *event)
5428 {
5429   GtkTreeView *tree_view;
5430   GtkRBTree *tree;
5431   GtkRBNode *node;
5432   gint new_y;
5433
5434   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
5435
5436   tree_view = GTK_TREE_VIEW (widget);
5437
5438   /* Sanity check it */
5439   if (event->window != tree_view->priv->bin_window)
5440     return FALSE;
5441
5442   if (tree_view->priv->tree == NULL)
5443     return FALSE;
5444
5445   /* find the node internally */
5446   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5447   if (new_y < 0)
5448     new_y = 0;
5449   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5450
5451   if ((tree_view->priv->button_pressed_node == NULL) ||
5452       (tree_view->priv->button_pressed_node == node))
5453     prelight_or_select (tree_view, tree, node, event->x, event->y);
5454
5455   return TRUE;
5456 }
5457
5458 static gboolean
5459 gtk_tree_view_leave_notify (GtkWidget        *widget,
5460                             GdkEventCrossing *event)
5461 {
5462   GtkTreeView *tree_view;
5463
5464   if (event->mode == GDK_CROSSING_GRAB)
5465     return TRUE;
5466
5467   tree_view = GTK_TREE_VIEW (widget);
5468
5469   if (tree_view->priv->prelight_node)
5470     _gtk_tree_view_queue_draw_node (tree_view,
5471                                    tree_view->priv->prelight_tree,
5472                                    tree_view->priv->prelight_node,
5473                                    NULL);
5474
5475   prelight_or_select (tree_view,
5476                       NULL, NULL,
5477                       -1000, -1000); /* coords not possibly over an arrow */
5478
5479   return TRUE;
5480 }
5481
5482
5483 static gint
5484 gtk_tree_view_focus_out (GtkWidget     *widget,
5485                          GdkEventFocus *event)
5486 {
5487   GtkTreeView *tree_view;
5488
5489   tree_view = GTK_TREE_VIEW (widget);
5490
5491   gtk_widget_queue_draw (widget);
5492
5493   /* destroy interactive search dialog */
5494   if (tree_view->priv->search_window)
5495     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
5496
5497   return FALSE;
5498 }
5499
5500
5501 /* Incremental Reflow
5502  */
5503
5504 static void
5505 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5506                                  GtkRBTree   *tree,
5507                                  GtkRBNode   *node)
5508 {
5509   gint y;
5510
5511   y = _gtk_rbtree_node_find_offset (tree, node)
5512     - tree_view->priv->vadjustment->value
5513     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5514
5515   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5516                               0, y,
5517                               GTK_WIDGET (tree_view)->allocation.width,
5518                               GTK_RBNODE_GET_HEIGHT (node));
5519 }
5520
5521 static gboolean
5522 node_is_visible (GtkTreeView *tree_view,
5523                  GtkRBTree   *tree,
5524                  GtkRBNode   *node)
5525 {
5526   int y;
5527   int height;
5528
5529   y = _gtk_rbtree_node_find_offset (tree, node);
5530   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5531
5532   if (y >= tree_view->priv->vadjustment->value &&
5533       y + height <= (tree_view->priv->vadjustment->value
5534                      + tree_view->priv->vadjustment->page_size))
5535     return TRUE;
5536
5537   return FALSE;
5538 }
5539
5540 /* Returns TRUE if it updated the size
5541  */
5542 static gboolean
5543 validate_row (GtkTreeView *tree_view,
5544               GtkRBTree   *tree,
5545               GtkRBNode   *node,
5546               GtkTreeIter *iter,
5547               GtkTreePath *path)
5548 {
5549   GtkTreeViewColumn *column;
5550   GList *list, *first_column, *last_column;
5551   gint height = 0;
5552   gint horizontal_separator;
5553   gint vertical_separator;
5554   gint focus_line_width;
5555   gint depth = gtk_tree_path_get_depth (path);
5556   gboolean retval = FALSE;
5557   gboolean is_separator = FALSE;
5558   gboolean draw_vgrid_lines, draw_hgrid_lines;
5559   gint focus_pad;
5560   gint grid_line_width;
5561
5562   /* double check the row needs validating */
5563   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5564       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5565     return FALSE;
5566
5567   is_separator = row_is_separator (tree_view, iter, NULL);
5568
5569   gtk_widget_style_get (GTK_WIDGET (tree_view),
5570                         "focus-padding", &focus_pad,
5571                         "focus-line-width", &focus_line_width,
5572                         "horizontal-separator", &horizontal_separator,
5573                         "vertical-separator", &vertical_separator,
5574                         "grid-line-width", &grid_line_width,
5575                         NULL);
5576   
5577   draw_vgrid_lines =
5578     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5579     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5580   draw_hgrid_lines =
5581     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5582     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5583
5584   for (last_column = g_list_last (tree_view->priv->columns);
5585        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5586        last_column = last_column->prev)
5587     ;
5588
5589   for (first_column = g_list_first (tree_view->priv->columns);
5590        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5591        first_column = first_column->next)
5592     ;
5593
5594   for (list = tree_view->priv->columns; list; list = list->next)
5595     {
5596       gint tmp_width;
5597       gint tmp_height;
5598
5599       column = list->data;
5600
5601       if (! column->visible)
5602         continue;
5603
5604       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5605         continue;
5606
5607       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5608                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5609                                                node->children?TRUE:FALSE);
5610       gtk_tree_view_column_cell_get_size (column,
5611                                           NULL, NULL, NULL,
5612                                           &tmp_width, &tmp_height);
5613
5614       if (!is_separator)
5615         {
5616           tmp_height += vertical_separator;
5617           height = MAX (height, tmp_height);
5618           height = MAX (height, tree_view->priv->expander_size);
5619         }
5620       else
5621         height = 2 + 2 * focus_pad;
5622
5623       if (gtk_tree_view_is_expander_column (tree_view, column))
5624         {
5625           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5626
5627           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5628             tmp_width += depth * tree_view->priv->expander_size;
5629         }
5630       else
5631         tmp_width = tmp_width + horizontal_separator;
5632
5633       if (draw_vgrid_lines)
5634         {
5635           if (list->data == first_column || list->data == last_column)
5636             tmp_width += grid_line_width / 2.0;
5637           else
5638             tmp_width += grid_line_width;
5639         }
5640
5641       if (tmp_width > column->requested_width)
5642         {
5643           retval = TRUE;
5644           column->requested_width = tmp_width;
5645         }
5646     }
5647
5648   if (draw_hgrid_lines)
5649     height += grid_line_width;
5650
5651   if (height != GTK_RBNODE_GET_HEIGHT (node))
5652     {
5653       retval = TRUE;
5654       _gtk_rbtree_node_set_height (tree, node, height);
5655     }
5656   _gtk_rbtree_node_mark_valid (tree, node);
5657
5658   return retval;
5659 }
5660
5661
5662 static void
5663 validate_visible_area (GtkTreeView *tree_view)
5664 {
5665   GtkTreePath *path = NULL;
5666   GtkTreePath *above_path = NULL;
5667   GtkTreeIter iter;
5668   GtkRBTree *tree = NULL;
5669   GtkRBNode *node = NULL;
5670   gboolean need_redraw = FALSE;
5671   gboolean size_changed = FALSE;
5672   gint total_height;
5673   gint area_above = 0;
5674   gint area_below = 0;
5675
5676   if (tree_view->priv->tree == NULL)
5677     return;
5678
5679   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5680       tree_view->priv->scroll_to_path == NULL)
5681     return;
5682
5683   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5684
5685   if (total_height == 0)
5686     return;
5687
5688   /* First, we check to see if we need to scroll anywhere
5689    */
5690   if (tree_view->priv->scroll_to_path)
5691     {
5692       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5693       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5694         {
5695           /* we are going to scroll, and will update dy */
5696           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5697           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5698               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5699             {
5700               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5701               if (validate_row (tree_view, tree, node, &iter, path))
5702                 size_changed = TRUE;
5703             }
5704
5705           if (tree_view->priv->scroll_to_use_align)
5706             {
5707               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5708               area_above = (total_height - height) *
5709                 tree_view->priv->scroll_to_row_align;
5710               area_below = total_height - area_above - height;
5711               area_above = MAX (area_above, 0);
5712               area_below = MAX (area_below, 0);
5713             }
5714           else
5715             {
5716               /* two cases:
5717                * 1) row not visible
5718                * 2) row visible
5719                */
5720               gint dy;
5721               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5722
5723               dy = _gtk_rbtree_node_find_offset (tree, node);
5724
5725               if (dy >= tree_view->priv->vadjustment->value &&
5726                   dy + height <= (tree_view->priv->vadjustment->value
5727                                   + tree_view->priv->vadjustment->page_size))
5728                 {
5729                   /* row visible: keep the row at the same position */
5730                   area_above = dy - tree_view->priv->vadjustment->value;
5731                   area_below = (tree_view->priv->vadjustment->value +
5732                                 tree_view->priv->vadjustment->page_size)
5733                                - dy - height;
5734                 }
5735               else
5736                 {
5737                   /* row not visible */
5738                   if (dy >= 0
5739                       && dy + height <= tree_view->priv->vadjustment->page_size)
5740                     {
5741                       /* row at the beginning -- fixed */
5742                       area_above = dy;
5743                       area_below = tree_view->priv->vadjustment->page_size
5744                                    - area_above - height;
5745                     }
5746                   else if (dy >= (tree_view->priv->vadjustment->upper -
5747                                   tree_view->priv->vadjustment->page_size))
5748                     {
5749                       /* row at the end -- fixed */
5750                       area_above = dy - (tree_view->priv->vadjustment->upper -
5751                                    tree_view->priv->vadjustment->page_size);
5752                       area_below = tree_view->priv->vadjustment->page_size -
5753                                    area_above - height;
5754
5755                       if (area_below < 0)
5756                         {
5757                           area_above = tree_view->priv->vadjustment->page_size - height;
5758                           area_below = 0;
5759                         }
5760                     }
5761                   else
5762                     {
5763                       /* row somewhere in the middle, bring it to the top
5764                        * of the view
5765                        */
5766                       area_above = 0;
5767                       area_below = total_height - height;
5768                     }
5769                 }
5770             }
5771         }
5772       else
5773         /* the scroll to isn't valid; ignore it.
5774          */
5775         {
5776           if (tree_view->priv->scroll_to_path && !path)
5777             {
5778               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5779               tree_view->priv->scroll_to_path = NULL;
5780             }
5781           if (path)
5782             gtk_tree_path_free (path);
5783           path = NULL;
5784         }      
5785     }
5786
5787   /* We didn't have a scroll_to set, so we just handle things normally
5788    */
5789   if (path == NULL)
5790     {
5791       gint offset;
5792
5793       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5794                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5795                                         &tree, &node);
5796       if (node == NULL)
5797         {
5798           /* In this case, nothing has been validated */
5799           path = gtk_tree_path_new_first ();
5800           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5801         }
5802       else
5803         {
5804           path = _gtk_tree_view_find_path (tree_view, tree, node);
5805           total_height += offset;
5806         }
5807
5808       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5809
5810       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5811           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5812         {
5813           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5814           if (validate_row (tree_view, tree, node, &iter, path))
5815             size_changed = TRUE;
5816         }
5817       area_above = 0;
5818       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5819     }
5820
5821   above_path = gtk_tree_path_copy (path);
5822
5823   /* if we do not validate any row above the new top_row, we will make sure
5824    * that the row immediately above top_row has been validated. (if we do not
5825    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5826    * when invalidated that row's height will be zero. and this will mess up
5827    * scrolling).
5828    */
5829   if (area_above == 0)
5830     {
5831       GtkRBTree *tmptree;
5832       GtkRBNode *tmpnode;
5833
5834       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5835       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5836
5837       if (tmpnode)
5838         {
5839           GtkTreePath *tmppath;
5840           GtkTreeIter tmpiter;
5841
5842           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5843           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5844
5845           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
5846               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
5847             {
5848               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
5849               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
5850                 size_changed = TRUE;
5851             }
5852
5853           gtk_tree_path_free (tmppath);
5854         }
5855     }
5856
5857   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
5858    * backwards is much slower then forward, as there is no iter_prev function.
5859    * We go forwards first in case we run out of tree.  Then we go backwards to
5860    * fill out the top.
5861    */
5862   while (node && area_below > 0)
5863     {
5864       if (node->children)
5865         {
5866           GtkTreeIter parent = iter;
5867           gboolean has_child;
5868
5869           tree = node->children;
5870           node = tree->root;
5871
5872           g_assert (node != tree->nil);
5873
5874           while (node->left != tree->nil)
5875             node = node->left;
5876           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5877                                                     &iter,
5878                                                     &parent);
5879           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
5880           gtk_tree_path_down (path);
5881         }
5882       else
5883         {
5884           gboolean done = FALSE;
5885           do
5886             {
5887               node = _gtk_rbtree_next (tree, node);
5888               if (node != NULL)
5889                 {
5890                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5891                   done = TRUE;
5892                   gtk_tree_path_next (path);
5893
5894                   /* Sanity Check! */
5895                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
5896                 }
5897               else
5898                 {
5899                   GtkTreeIter parent_iter = iter;
5900                   gboolean has_parent;
5901
5902                   node = tree->parent_node;
5903                   tree = tree->parent_tree;
5904                   if (tree == NULL)
5905                     break;
5906                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5907                                                            &iter,
5908                                                            &parent_iter);
5909                   gtk_tree_path_up (path);
5910
5911                   /* Sanity check */
5912                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
5913                 }
5914             }
5915           while (!done);
5916         }
5917
5918       if (!node)
5919         break;
5920
5921       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5922           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5923         {
5924           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5925           if (validate_row (tree_view, tree, node, &iter, path))
5926               size_changed = TRUE;
5927         }
5928
5929       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5930     }
5931   gtk_tree_path_free (path);
5932
5933   /* If we ran out of tree, and have extra area_below left, we need to add it
5934    * to area_above */
5935   if (area_below > 0)
5936     area_above += area_below;
5937
5938   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
5939
5940   /* We walk backwards */
5941   while (area_above > 0)
5942     {
5943       _gtk_rbtree_prev_full (tree, node, &tree, &node);
5944       if (! gtk_tree_path_prev (above_path) && node != NULL)
5945         {
5946           gtk_tree_path_free (above_path);
5947           above_path = _gtk_tree_view_find_path (tree_view, tree, node);
5948         }
5949       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
5950
5951       if (node == NULL)
5952         break;
5953
5954       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5955           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5956         {
5957           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5958           if (validate_row (tree_view, tree, node, &iter, above_path))
5959             size_changed = TRUE;
5960         }
5961       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5962     }
5963
5964   /* if we scrolled to a path, we need to set the dy here,
5965    * and sync the top row accordingly
5966    */
5967   if (tree_view->priv->scroll_to_path)
5968     {
5969       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
5970       gtk_tree_view_top_row_to_dy (tree_view);
5971
5972       need_redraw = TRUE;
5973     }
5974   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
5975     {
5976       /* when we are not scrolling, we should never set dy to something
5977        * else than zero. we update top_row to be in sync with dy = 0.
5978        */
5979       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
5980       gtk_tree_view_dy_to_top_row (tree_view);
5981     }
5982   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
5983     {
5984       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
5985       gtk_tree_view_dy_to_top_row (tree_view);
5986     }
5987   else
5988     gtk_tree_view_top_row_to_dy (tree_view);
5989
5990   /* update width/height and queue a resize */
5991   if (size_changed)
5992     {
5993       GtkRequisition requisition;
5994
5995       /* We temporarily guess a size, under the assumption that it will be the
5996        * same when we get our next size_allocate.  If we don't do this, we'll be
5997        * in an inconsistent state if we call top_row_to_dy. */
5998
5999       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6000       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6001       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6002       gtk_adjustment_changed (tree_view->priv->hadjustment);
6003       gtk_adjustment_changed (tree_view->priv->vadjustment);
6004       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6005     }
6006
6007   if (tree_view->priv->scroll_to_path)
6008     {
6009       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6010       tree_view->priv->scroll_to_path = NULL;
6011     }
6012
6013   if (above_path)
6014     gtk_tree_path_free (above_path);
6015
6016   if (tree_view->priv->scroll_to_column)
6017     {
6018       tree_view->priv->scroll_to_column = NULL;
6019     }
6020   if (need_redraw)
6021     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6022 }
6023
6024 static void
6025 initialize_fixed_height_mode (GtkTreeView *tree_view)
6026 {
6027   if (!tree_view->priv->tree)
6028     return;
6029
6030   if (tree_view->priv->fixed_height < 0)
6031     {
6032       GtkTreeIter iter;
6033       GtkTreePath *path;
6034
6035       GtkRBTree *tree = NULL;
6036       GtkRBNode *node = NULL;
6037
6038       tree = tree_view->priv->tree;
6039       node = tree->root;
6040
6041       path = _gtk_tree_view_find_path (tree_view, tree, node);
6042       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6043
6044       validate_row (tree_view, tree, node, &iter, path);
6045
6046       gtk_tree_path_free (path);
6047
6048       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6049     }
6050
6051    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6052                                  tree_view->priv->fixed_height, TRUE);
6053 }
6054
6055 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6056  * the left-most uninvalidated node.  We then try walking right, validating
6057  * nodes.  Once we find a valid node, we repeat the previous process of finding
6058  * the first invalid node.
6059  */
6060
6061 static gboolean
6062 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6063 {
6064   GtkRBTree *tree = NULL;
6065   GtkRBNode *node = NULL;
6066   gboolean validated_area = FALSE;
6067   gint retval = TRUE;
6068   GtkTreePath *path = NULL;
6069   GtkTreeIter iter;
6070   gint i = 0;
6071
6072   gint prev_height = -1;
6073   gboolean fixed_height = TRUE;
6074
6075   g_assert (tree_view);
6076
6077   if (tree_view->priv->tree == NULL)
6078       return FALSE;
6079
6080   if (tree_view->priv->fixed_height_mode)
6081     {
6082       if (tree_view->priv->fixed_height < 0)
6083         initialize_fixed_height_mode (tree_view);
6084
6085       return FALSE;
6086     }
6087
6088   do
6089     {
6090       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6091         {
6092           retval = FALSE;
6093           goto done;
6094         }
6095
6096       if (path != NULL)
6097         {
6098           node = _gtk_rbtree_next (tree, node);
6099           if (node != NULL)
6100             {
6101               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6102               gtk_tree_path_next (path);
6103             }
6104           else
6105             {
6106               gtk_tree_path_free (path);
6107               path = NULL;
6108             }
6109         }
6110
6111       if (path == NULL)
6112         {
6113           tree = tree_view->priv->tree;
6114           node = tree_view->priv->tree->root;
6115
6116           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6117
6118           do
6119             {
6120               if (node->left != tree->nil &&
6121                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6122                 {
6123                   node = node->left;
6124                 }
6125               else if (node->right != tree->nil &&
6126                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6127                 {
6128                   node = node->right;
6129                 }
6130               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6131                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6132                 {
6133                   break;
6134                 }
6135               else if (node->children != NULL)
6136                 {
6137                   tree = node->children;
6138                   node = tree->root;
6139                 }
6140               else
6141                 /* RBTree corruption!  All bad */
6142                 g_assert_not_reached ();
6143             }
6144           while (TRUE);
6145           path = _gtk_tree_view_find_path (tree_view, tree, node);
6146           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6147         }
6148
6149       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6150                        validated_area;
6151
6152       if (!tree_view->priv->fixed_height_check)
6153         {
6154           gint height;
6155
6156           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6157           if (prev_height < 0)
6158             prev_height = height;
6159           else if (prev_height != height)
6160             fixed_height = FALSE;
6161         }
6162
6163       i++;
6164     }
6165   while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
6166
6167   if (!tree_view->priv->fixed_height_check)
6168    {
6169      if (fixed_height)
6170        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6171
6172      tree_view->priv->fixed_height_check = 1;
6173    }
6174   
6175  done:
6176   if (validated_area)
6177     {
6178       GtkRequisition requisition;
6179       /* We temporarily guess a size, under the assumption that it will be the
6180        * same when we get our next size_allocate.  If we don't do this, we'll be
6181        * in an inconsistent state when we call top_row_to_dy. */
6182
6183       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6184       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6185       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6186       gtk_adjustment_changed (tree_view->priv->hadjustment);
6187       gtk_adjustment_changed (tree_view->priv->vadjustment);
6188
6189       if (queue_resize)
6190         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6191     }
6192
6193   if (path) gtk_tree_path_free (path);
6194
6195   return retval;
6196 }
6197
6198 static gboolean
6199 validate_rows (GtkTreeView *tree_view)
6200 {
6201   gboolean retval;
6202   
6203   retval = do_validate_rows (tree_view, TRUE);
6204   
6205   if (! retval && tree_view->priv->validate_rows_timer)
6206     {
6207       g_source_remove (tree_view->priv->validate_rows_timer);
6208       tree_view->priv->validate_rows_timer = 0;
6209     }
6210
6211   return retval;
6212 }
6213
6214 static gboolean
6215 validate_rows_handler (GtkTreeView *tree_view)
6216 {
6217   gboolean retval;
6218
6219   retval = do_validate_rows (tree_view, TRUE);
6220   if (! retval && tree_view->priv->validate_rows_timer)
6221     {
6222       g_source_remove (tree_view->priv->validate_rows_timer);
6223       tree_view->priv->validate_rows_timer = 0;
6224     }
6225
6226   return retval;
6227 }
6228
6229 static gboolean
6230 do_presize_handler (GtkTreeView *tree_view)
6231 {
6232   if (tree_view->priv->mark_rows_col_dirty)
6233     {
6234       if (tree_view->priv->tree)
6235         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6236       tree_view->priv->mark_rows_col_dirty = FALSE;
6237     }
6238   validate_visible_area (tree_view);
6239   tree_view->priv->presize_handler_timer = 0;
6240
6241   if (tree_view->priv->fixed_height_mode)
6242     {
6243       GtkRequisition requisition;
6244
6245       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6246
6247       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6248       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6249       gtk_adjustment_changed (tree_view->priv->hadjustment);
6250       gtk_adjustment_changed (tree_view->priv->vadjustment);
6251       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6252     }
6253                    
6254   return FALSE;
6255 }
6256
6257 static gboolean
6258 presize_handler_callback (gpointer data)
6259 {
6260   do_presize_handler (GTK_TREE_VIEW (data));
6261                    
6262   return FALSE;
6263 }
6264
6265 static void
6266 install_presize_handler (GtkTreeView *tree_view)
6267 {
6268   if (! GTK_WIDGET_REALIZED (tree_view))
6269     return;
6270
6271   if (! tree_view->priv->presize_handler_timer)
6272     {
6273       tree_view->priv->presize_handler_timer =
6274         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6275     }
6276   if (! tree_view->priv->validate_rows_timer)
6277     {
6278       tree_view->priv->validate_rows_timer =
6279         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6280     }
6281 }
6282
6283 static gboolean
6284 scroll_sync_handler (GtkTreeView *tree_view)
6285 {
6286   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6287     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6288   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6289     gtk_tree_view_top_row_to_dy (tree_view);
6290   else
6291     gtk_tree_view_dy_to_top_row (tree_view);
6292
6293   tree_view->priv->scroll_sync_timer = 0;
6294
6295   return FALSE;
6296 }
6297
6298 static void
6299 install_scroll_sync_handler (GtkTreeView *tree_view)
6300 {
6301   if (! GTK_WIDGET_REALIZED (tree_view))
6302     return;
6303
6304   if (!tree_view->priv->scroll_sync_timer)
6305     {
6306       tree_view->priv->scroll_sync_timer =
6307         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6308     }
6309 }
6310
6311 static void
6312 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6313                            GtkTreePath *path,
6314                            gint         offset)
6315 {
6316   gtk_tree_row_reference_free (tree_view->priv->top_row);
6317
6318   if (!path)
6319     {
6320       tree_view->priv->top_row = NULL;
6321       tree_view->priv->top_row_dy = 0;
6322     }
6323   else
6324     {
6325       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6326       tree_view->priv->top_row_dy = offset;
6327     }
6328 }
6329
6330 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6331  * it's set to be NULL, and top_row_dy is 0;
6332  */
6333 static void
6334 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6335 {
6336   gint offset;
6337   GtkTreePath *path;
6338   GtkRBTree *tree;
6339   GtkRBNode *node;
6340
6341   if (tree_view->priv->tree == NULL)
6342     {
6343       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6344     }
6345   else
6346     {
6347       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6348                                         tree_view->priv->dy,
6349                                         &tree, &node);
6350
6351       if (tree == NULL)
6352         {
6353           tree_view->priv->top_row = NULL;
6354           tree_view->priv->top_row_dy = 0;
6355         }
6356       else
6357         {
6358           path = _gtk_tree_view_find_path (tree_view, tree, node);
6359           gtk_tree_view_set_top_row (tree_view, path, offset);
6360           gtk_tree_path_free (path);
6361         }
6362     }
6363 }
6364
6365 static void
6366 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6367 {
6368   GtkTreePath *path;
6369   GtkRBTree *tree;
6370   GtkRBNode *node;
6371   int new_dy;
6372
6373   if (tree_view->priv->top_row)
6374     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6375   else
6376     path = NULL;
6377
6378   if (!path)
6379     tree = NULL;
6380   else
6381     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6382
6383   if (path)
6384     gtk_tree_path_free (path);
6385
6386   if (tree == NULL)
6387     {
6388       /* keep dy and set new toprow */
6389       gtk_tree_row_reference_free (tree_view->priv->top_row);
6390       tree_view->priv->top_row = NULL;
6391       tree_view->priv->top_row_dy = 0;
6392       /* DO NOT install the idle handler */
6393       gtk_tree_view_dy_to_top_row (tree_view);
6394       return;
6395     }
6396
6397   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6398       < tree_view->priv->top_row_dy)
6399     {
6400       /* new top row -- do NOT install the idle handler */
6401       gtk_tree_view_dy_to_top_row (tree_view);
6402       return;
6403     }
6404
6405   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6406   new_dy += tree_view->priv->top_row_dy;
6407
6408   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6409     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6410
6411   new_dy = MAX (0, new_dy);
6412
6413   tree_view->priv->in_top_row_to_dy = TRUE;
6414   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6415   tree_view->priv->in_top_row_to_dy = FALSE;
6416 }
6417
6418
6419 void
6420 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6421 {
6422   tree_view->priv->mark_rows_col_dirty = TRUE;
6423
6424   install_presize_handler (tree_view);
6425 }
6426
6427 /*
6428  * This function works synchronously (due to the while (validate_rows...)
6429  * loop).
6430  *
6431  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6432  * here. You now need to check that yourself.
6433  */
6434 void
6435 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6436                                 GtkTreeViewColumn *column)
6437 {
6438   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6439   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6440
6441   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6442
6443   do_presize_handler (tree_view);
6444   while (validate_rows (tree_view));
6445
6446   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6447 }
6448
6449 /* Drag-and-drop */
6450
6451 static void
6452 set_source_row (GdkDragContext *context,
6453                 GtkTreeModel   *model,
6454                 GtkTreePath    *source_row)
6455 {
6456   g_object_set_data_full (G_OBJECT (context),
6457                           I_("gtk-tree-view-source-row"),
6458                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6459                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6460 }
6461
6462 static GtkTreePath*
6463 get_source_row (GdkDragContext *context)
6464 {
6465   GtkTreeRowReference *ref =
6466     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6467
6468   if (ref)
6469     return gtk_tree_row_reference_get_path (ref);
6470   else
6471     return NULL;
6472 }
6473
6474 typedef struct
6475 {
6476   GtkTreeRowReference *dest_row;
6477   gboolean             path_down_mode;
6478   gboolean             empty_view_drop;
6479   gboolean             drop_append_mode;
6480 }
6481 DestRow;
6482
6483 static void
6484 dest_row_free (gpointer data)
6485 {
6486   DestRow *dr = (DestRow *)data;
6487
6488   gtk_tree_row_reference_free (dr->dest_row);
6489   g_free (dr);
6490 }
6491
6492
6493 static void
6494 set_dest_row (GdkDragContext *context,
6495               GtkTreeModel   *model,
6496               GtkTreePath    *dest_row,
6497               gboolean        path_down_mode,
6498               gboolean        empty_view_drop,
6499               gboolean        drop_append_mode)
6500 {
6501   DestRow *dr;
6502
6503   if (!dest_row)
6504     {
6505       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6506                               NULL, NULL);
6507       return;
6508     }
6509
6510   dr = g_new0 (DestRow, 1);
6511
6512   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6513   dr->path_down_mode = path_down_mode;
6514   dr->empty_view_drop = empty_view_drop;
6515   dr->drop_append_mode = drop_append_mode;
6516
6517   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6518                           dr, (GDestroyNotify) dest_row_free);
6519 }
6520
6521 static GtkTreePath*
6522 get_dest_row (GdkDragContext *context,
6523               gboolean       *path_down_mode)
6524 {
6525   DestRow *dr =
6526     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6527
6528   if (dr)
6529     {
6530       GtkTreePath *path = NULL;
6531
6532       if (path_down_mode)
6533         *path_down_mode = dr->path_down_mode;
6534
6535       if (dr->dest_row)
6536         path = gtk_tree_row_reference_get_path (dr->dest_row);
6537       else if (dr->empty_view_drop)
6538         path = gtk_tree_path_new_from_indices (0, -1);
6539       else
6540         path = NULL;
6541
6542       if (path && dr->drop_append_mode)
6543         gtk_tree_path_next (path);
6544
6545       return path;
6546     }
6547   else
6548     return NULL;
6549 }
6550
6551 /* Get/set whether drag_motion requested the drag data and
6552  * drag_data_received should thus not actually insert the data,
6553  * since the data doesn't result from a drop.
6554  */
6555 static void
6556 set_status_pending (GdkDragContext *context,
6557                     GdkDragAction   suggested_action)
6558 {
6559   g_object_set_data (G_OBJECT (context),
6560                      I_("gtk-tree-view-status-pending"),
6561                      GINT_TO_POINTER (suggested_action));
6562 }
6563
6564 static GdkDragAction
6565 get_status_pending (GdkDragContext *context)
6566 {
6567   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6568                                              "gtk-tree-view-status-pending"));
6569 }
6570
6571 static TreeViewDragInfo*
6572 get_info (GtkTreeView *tree_view)
6573 {
6574   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6575 }
6576
6577 static void
6578 clear_source_info (TreeViewDragInfo *di)
6579 {
6580   if (di->source_target_list)
6581     gtk_target_list_unref (di->source_target_list);
6582
6583   di->source_target_list = NULL;
6584 }
6585
6586 static void
6587 clear_dest_info (TreeViewDragInfo *di)
6588 {
6589   if (di->dest_target_list)
6590     gtk_target_list_unref (di->dest_target_list);
6591
6592   di->dest_target_list = NULL;
6593 }
6594
6595 static void
6596 destroy_info (TreeViewDragInfo *di)
6597 {
6598   clear_source_info (di);
6599   clear_dest_info (di);
6600   g_free (di);
6601 }
6602
6603 static TreeViewDragInfo*
6604 ensure_info (GtkTreeView *tree_view)
6605 {
6606   TreeViewDragInfo *di;
6607
6608   di = get_info (tree_view);
6609
6610   if (di == NULL)
6611     {
6612       di = g_new0 (TreeViewDragInfo, 1);
6613
6614       g_object_set_data_full (G_OBJECT (tree_view),
6615                               I_("gtk-tree-view-drag-info"),
6616                               di,
6617                               (GDestroyNotify) destroy_info);
6618     }
6619
6620   return di;
6621 }
6622
6623 static void
6624 remove_info (GtkTreeView *tree_view)
6625 {
6626   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6627 }
6628
6629 #if 0
6630 static gint
6631 drag_scan_timeout (gpointer data)
6632 {
6633   GtkTreeView *tree_view;
6634   gint x, y;
6635   GdkModifierType state;
6636   GtkTreePath *path = NULL;
6637   GtkTreeViewColumn *column = NULL;
6638   GdkRectangle visible_rect;
6639
6640   GDK_THREADS_ENTER ();
6641
6642   tree_view = GTK_TREE_VIEW (data);
6643
6644   gdk_window_get_pointer (tree_view->priv->bin_window,
6645                           &x, &y, &state);
6646
6647   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6648
6649   /* See if we are near the edge. */
6650   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6651       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6652       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6653       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6654     {
6655       gtk_tree_view_get_path_at_pos (tree_view,
6656                                      tree_view->priv->bin_window,
6657                                      x, y,
6658                                      &path,
6659                                      &column,
6660                                      NULL,
6661                                      NULL);
6662
6663       if (path != NULL)
6664         {
6665           gtk_tree_view_scroll_to_cell (tree_view,
6666                                         path,
6667                                         column,
6668                                         TRUE,
6669                                         0.5, 0.5);
6670
6671           gtk_tree_path_free (path);
6672         }
6673     }
6674
6675   GDK_THREADS_LEAVE ();
6676
6677   return TRUE;
6678 }
6679 #endif /* 0 */
6680
6681 static void
6682 add_scroll_timeout (GtkTreeView *tree_view)
6683 {
6684   if (tree_view->priv->scroll_timeout == 0)
6685     {
6686       tree_view->priv->scroll_timeout =
6687         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6688     }
6689 }
6690
6691 static void
6692 remove_scroll_timeout (GtkTreeView *tree_view)
6693 {
6694   if (tree_view->priv->scroll_timeout != 0)
6695     {
6696       g_source_remove (tree_view->priv->scroll_timeout);
6697       tree_view->priv->scroll_timeout = 0;
6698     }
6699 }
6700
6701 static gboolean
6702 check_model_dnd (GtkTreeModel *model,
6703                  GType         required_iface,
6704                  const gchar  *signal)
6705 {
6706   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6707     {
6708       g_warning ("You must override the default '%s' handler "
6709                  "on GtkTreeView when using models that don't support "
6710                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6711                  "is to connect to '%s' and call "
6712                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6713                  "the default handler from running. Look at the source code "
6714                  "for the default handler in gtktreeview.c to get an idea what "
6715                  "your handler should do. (gtktreeview.c is in the GTK source "
6716                  "code.) If you're using GTK from a language other than C, "
6717                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6718                  signal, g_type_name (required_iface), signal);
6719       return FALSE;
6720     }
6721   else
6722     return TRUE;
6723 }
6724
6725 static void
6726 remove_open_timeout (GtkTreeView *tree_view)
6727 {
6728   if (tree_view->priv->open_dest_timeout != 0)
6729     {
6730       g_source_remove (tree_view->priv->open_dest_timeout);
6731       tree_view->priv->open_dest_timeout = 0;
6732     }
6733 }
6734
6735
6736 static gint
6737 open_row_timeout (gpointer data)
6738 {
6739   GtkTreeView *tree_view = data;
6740   GtkTreePath *dest_path = NULL;
6741   GtkTreeViewDropPosition pos;
6742   gboolean result = FALSE;
6743
6744   gtk_tree_view_get_drag_dest_row (tree_view,
6745                                    &dest_path,
6746                                    &pos);
6747
6748   if (dest_path &&
6749       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6750        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6751     {
6752       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6753       tree_view->priv->open_dest_timeout = 0;
6754
6755       gtk_tree_path_free (dest_path);
6756     }
6757   else
6758     {
6759       if (dest_path)
6760         gtk_tree_path_free (dest_path);
6761
6762       result = TRUE;
6763     }
6764
6765   return result;
6766 }
6767
6768 static gboolean
6769 scroll_row_timeout (gpointer data)
6770 {
6771   GtkTreeView *tree_view = data;
6772
6773   gtk_tree_view_vertical_autoscroll (tree_view);
6774
6775   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6776     gtk_tree_view_update_rubber_band (tree_view);
6777
6778   return TRUE;
6779 }
6780
6781 /* Returns TRUE if event should not be propagated to parent widgets */
6782 static gboolean
6783 set_destination_row (GtkTreeView    *tree_view,
6784                      GdkDragContext *context,
6785                      /* coordinates relative to the widget */
6786                      gint            x,
6787                      gint            y,
6788                      GdkDragAction  *suggested_action,
6789                      GdkAtom        *target)
6790 {
6791   GtkTreePath *path = NULL;
6792   GtkTreeViewDropPosition pos;
6793   GtkTreeViewDropPosition old_pos;
6794   TreeViewDragInfo *di;
6795   GtkWidget *widget;
6796   GtkTreePath *old_dest_path = NULL;
6797   gboolean can_drop = FALSE;
6798
6799   *suggested_action = 0;
6800   *target = GDK_NONE;
6801
6802   widget = GTK_WIDGET (tree_view);
6803
6804   di = get_info (tree_view);
6805
6806   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6807     {
6808       /* someone unset us as a drag dest, note that if
6809        * we return FALSE drag_leave isn't called
6810        */
6811
6812       gtk_tree_view_set_drag_dest_row (tree_view,
6813                                        NULL,
6814                                        GTK_TREE_VIEW_DROP_BEFORE);
6815
6816       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6817       remove_open_timeout (GTK_TREE_VIEW (widget));
6818
6819       return FALSE; /* no longer a drop site */
6820     }
6821
6822   *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
6823   if (*target == GDK_NONE)
6824     {
6825       return FALSE;
6826     }
6827
6828   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6829                                           x, y,
6830                                           &path,
6831                                           &pos))
6832     {
6833       gint n_children;
6834       GtkTreeModel *model;
6835
6836       remove_open_timeout (tree_view);
6837
6838       /* the row got dropped on empty space, let's setup a special case
6839        */
6840
6841       if (path)
6842         gtk_tree_path_free (path);
6843
6844       model = gtk_tree_view_get_model (tree_view);
6845
6846       n_children = gtk_tree_model_iter_n_children (model, NULL);
6847       if (n_children)
6848         {
6849           pos = GTK_TREE_VIEW_DROP_AFTER;
6850           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6851         }
6852       else
6853         {
6854           pos = GTK_TREE_VIEW_DROP_BEFORE;
6855           path = gtk_tree_path_new_from_indices (0, -1);
6856         }
6857
6858       can_drop = TRUE;
6859
6860       goto out;
6861     }
6862
6863   g_assert (path);
6864
6865   /* If we left the current row's "open" zone, unset the timeout for
6866    * opening the row
6867    */
6868   gtk_tree_view_get_drag_dest_row (tree_view,
6869                                    &old_dest_path,
6870                                    &old_pos);
6871
6872   if (old_dest_path &&
6873       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
6874        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6875          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
6876     remove_open_timeout (tree_view);
6877
6878   if (old_dest_path)
6879     gtk_tree_path_free (old_dest_path);
6880
6881   if (TRUE /* FIXME if the location droppable predicate */)
6882     {
6883       can_drop = TRUE;
6884     }
6885
6886 out:
6887   if (can_drop)
6888     {
6889       GtkWidget *source_widget;
6890
6891       *suggested_action = context->suggested_action;
6892       source_widget = gtk_drag_get_source_widget (context);
6893
6894       if (source_widget == widget)
6895         {
6896           /* Default to MOVE, unless the user has
6897            * pressed ctrl or shift to affect available actions
6898            */
6899           if ((context->actions & GDK_ACTION_MOVE) != 0)
6900             *suggested_action = GDK_ACTION_MOVE;
6901         }
6902
6903       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6904                                        path, pos);
6905     }
6906   else
6907     {
6908       /* can't drop here */
6909       remove_open_timeout (tree_view);
6910
6911       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6912                                        NULL,
6913                                        GTK_TREE_VIEW_DROP_BEFORE);
6914     }
6915
6916   if (path)
6917     gtk_tree_path_free (path);
6918
6919   return TRUE;
6920 }
6921
6922 static GtkTreePath*
6923 get_logical_dest_row (GtkTreeView *tree_view,
6924                       gboolean    *path_down_mode,
6925                       gboolean    *drop_append_mode)
6926 {
6927   /* adjust path to point to the row the drop goes in front of */
6928   GtkTreePath *path = NULL;
6929   GtkTreeViewDropPosition pos;
6930
6931   g_return_val_if_fail (path_down_mode != NULL, NULL);
6932   g_return_val_if_fail (drop_append_mode != NULL, NULL);
6933
6934   *path_down_mode = FALSE;
6935   *drop_append_mode = 0;
6936
6937   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6938
6939   if (path == NULL)
6940     return NULL;
6941
6942   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
6943     ; /* do nothing */
6944   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
6945            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
6946     *path_down_mode = TRUE;
6947   else
6948     {
6949       GtkTreeIter iter;
6950       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
6951
6952       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
6953
6954       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6955           !gtk_tree_model_iter_next (model, &iter))
6956         *drop_append_mode = 1;
6957       else
6958         {
6959           *drop_append_mode = 0;
6960           gtk_tree_path_next (path);
6961         }
6962     }
6963
6964   return path;
6965 }
6966
6967 static gboolean
6968 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
6969                                         GdkEventMotion   *event)
6970 {
6971   GdkDragContext *context;
6972   TreeViewDragInfo *di;
6973   GtkTreePath *path = NULL;
6974   gint button;
6975   gint cell_x, cell_y;
6976   GtkTreeModel *model;
6977   gboolean retval = FALSE;
6978
6979   di = get_info (tree_view);
6980
6981   if (di == NULL || !di->source_set)
6982     goto out;
6983
6984   if (tree_view->priv->pressed_button < 0)
6985     goto out;
6986
6987   if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
6988                                  tree_view->priv->press_start_x,
6989                                  tree_view->priv->press_start_y,
6990                                  event->x, event->y))
6991     goto out;
6992
6993   model = gtk_tree_view_get_model (tree_view);
6994
6995   if (model == NULL)
6996     goto out;
6997
6998   button = tree_view->priv->pressed_button;
6999   tree_view->priv->pressed_button = -1;
7000
7001   gtk_tree_view_get_path_at_pos (tree_view,
7002                                  tree_view->priv->press_start_x,
7003                                  tree_view->priv->press_start_y,
7004                                  &path,
7005                                  NULL,
7006                                  &cell_x,
7007                                  &cell_y);
7008
7009   if (path == NULL)
7010     goto out;
7011
7012   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7013       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7014                                            path))
7015     goto out;
7016
7017   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7018     goto out;
7019
7020   /* Now we can begin the drag */
7021
7022   retval = TRUE;
7023
7024   context = gtk_drag_begin (GTK_WIDGET (tree_view),
7025                             di->source_target_list,
7026                             di->source_actions,
7027                             button,
7028                             (GdkEvent*)event);
7029
7030   set_source_row (context, model, path);
7031
7032  out:
7033   if (path)
7034     gtk_tree_path_free (path);
7035
7036   return retval;
7037 }
7038
7039
7040 static void
7041 gtk_tree_view_drag_begin (GtkWidget      *widget,
7042                           GdkDragContext *context)
7043 {
7044   GtkTreeView *tree_view;
7045   GtkTreePath *path = NULL;
7046   gint cell_x, cell_y;
7047   GdkPixmap *row_pix;
7048   TreeViewDragInfo *di;
7049
7050   tree_view = GTK_TREE_VIEW (widget);
7051
7052   /* if the user uses a custom DND source impl, we don't set the icon here */
7053   di = get_info (tree_view);
7054
7055   if (di == NULL || !di->source_set)
7056     return;
7057
7058   gtk_tree_view_get_path_at_pos (tree_view,
7059                                  tree_view->priv->press_start_x,
7060                                  tree_view->priv->press_start_y,
7061                                  &path,
7062                                  NULL,
7063                                  &cell_x,
7064                                  &cell_y);
7065
7066   g_return_if_fail (path != NULL);
7067
7068   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7069                                                 path);
7070
7071   gtk_drag_set_icon_pixmap (context,
7072                             gdk_drawable_get_colormap (row_pix),
7073                             row_pix,
7074                             NULL,
7075                             /* the + 1 is for the black border in the icon */
7076                             tree_view->priv->press_start_x + 1,
7077                             cell_y + 1);
7078
7079   g_object_unref (row_pix);
7080   gtk_tree_path_free (path);
7081 }
7082
7083 static void
7084 gtk_tree_view_drag_end (GtkWidget      *widget,
7085                         GdkDragContext *context)
7086 {
7087   /* do nothing */
7088 }
7089
7090 /* Default signal implementations for the drag signals */
7091 static void
7092 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7093                              GdkDragContext   *context,
7094                              GtkSelectionData *selection_data,
7095                              guint             info,
7096                              guint             time)
7097 {
7098   GtkTreeView *tree_view;
7099   GtkTreeModel *model;
7100   TreeViewDragInfo *di;
7101   GtkTreePath *source_row;
7102
7103   tree_view = GTK_TREE_VIEW (widget);
7104
7105   model = gtk_tree_view_get_model (tree_view);
7106
7107   if (model == NULL)
7108     return;
7109
7110   di = get_info (GTK_TREE_VIEW (widget));
7111
7112   if (di == NULL)
7113     return;
7114
7115   source_row = get_source_row (context);
7116
7117   if (source_row == NULL)
7118     return;
7119
7120   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7121    * any model; for DragSource models there are some other targets
7122    * we also support.
7123    */
7124
7125   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7126       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7127                                           source_row,
7128                                           selection_data))
7129     goto done;
7130
7131   /* If drag_data_get does nothing, try providing row data. */
7132   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7133     {
7134       gtk_tree_set_row_drag_data (selection_data,
7135                                   model,
7136                                   source_row);
7137     }
7138
7139  done:
7140   gtk_tree_path_free (source_row);
7141 }
7142
7143
7144 static void
7145 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7146                                 GdkDragContext *context)
7147 {
7148   TreeViewDragInfo *di;
7149   GtkTreeModel *model;
7150   GtkTreeView *tree_view;
7151   GtkTreePath *source_row;
7152
7153   tree_view = GTK_TREE_VIEW (widget);
7154   model = gtk_tree_view_get_model (tree_view);
7155
7156   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7157     return;
7158
7159   di = get_info (tree_view);
7160
7161   if (di == NULL)
7162     return;
7163
7164   source_row = get_source_row (context);
7165
7166   if (source_row == NULL)
7167     return;
7168
7169   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7170                                          source_row);
7171
7172   gtk_tree_path_free (source_row);
7173
7174   set_source_row (context, NULL, NULL);
7175 }
7176
7177 static void
7178 gtk_tree_view_drag_leave (GtkWidget      *widget,
7179                           GdkDragContext *context,
7180                           guint             time)
7181 {
7182   /* unset any highlight row */
7183   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7184                                    NULL,
7185                                    GTK_TREE_VIEW_DROP_BEFORE);
7186
7187   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7188   remove_open_timeout (GTK_TREE_VIEW (widget));
7189 }
7190
7191
7192 static gboolean
7193 gtk_tree_view_drag_motion (GtkWidget        *widget,
7194                            GdkDragContext   *context,
7195                            /* coordinates relative to the widget */
7196                            gint              x,
7197                            gint              y,
7198                            guint             time)
7199 {
7200   gboolean empty;
7201   GtkTreePath *path = NULL;
7202   GtkTreeViewDropPosition pos;
7203   GtkTreeView *tree_view;
7204   GdkDragAction suggested_action = 0;
7205   GdkAtom target;
7206
7207   tree_view = GTK_TREE_VIEW (widget);
7208
7209   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7210     return FALSE;
7211
7212   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7213
7214   /* we only know this *after* set_desination_row */
7215   empty = tree_view->priv->empty_view_drop;
7216
7217   if (path == NULL && !empty)
7218     {
7219       /* Can't drop here. */
7220       gdk_drag_status (context, 0, time);
7221     }
7222   else
7223     {
7224       if (tree_view->priv->open_dest_timeout == 0 &&
7225           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7226            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7227         {
7228           tree_view->priv->open_dest_timeout =
7229             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7230         }
7231       else
7232         {
7233           add_scroll_timeout (tree_view);
7234         }
7235
7236       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7237         {
7238           /* Request data so we can use the source row when
7239            * determining whether to accept the drop
7240            */
7241           set_status_pending (context, suggested_action);
7242           gtk_drag_get_data (widget, context, target, time);
7243         }
7244       else
7245         {
7246           set_status_pending (context, 0);
7247           gdk_drag_status (context, suggested_action, time);
7248         }
7249     }
7250
7251   if (path)
7252     gtk_tree_path_free (path);
7253
7254   return TRUE;
7255 }
7256
7257
7258 static gboolean
7259 gtk_tree_view_drag_drop (GtkWidget        *widget,
7260                          GdkDragContext   *context,
7261                          /* coordinates relative to the widget */
7262                          gint              x,
7263                          gint              y,
7264                          guint             time)
7265 {
7266   GtkTreeView *tree_view;
7267   GtkTreePath *path;
7268   GdkDragAction suggested_action = 0;
7269   GdkAtom target = GDK_NONE;
7270   TreeViewDragInfo *di;
7271   GtkTreeModel *model;
7272   gboolean path_down_mode;
7273   gboolean drop_append_mode;
7274
7275   tree_view = GTK_TREE_VIEW (widget);
7276
7277   model = gtk_tree_view_get_model (tree_view);
7278
7279   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7280   remove_open_timeout (GTK_TREE_VIEW (widget));
7281
7282   di = get_info (tree_view);
7283
7284   if (di == NULL)
7285     return FALSE;
7286
7287   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7288     return FALSE;
7289
7290   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7291     return FALSE;
7292
7293   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7294
7295   if (target != GDK_NONE && path != NULL)
7296     {
7297       /* in case a motion had requested drag data, change things so we
7298        * treat drag data receives as a drop.
7299        */
7300       set_status_pending (context, 0);
7301       set_dest_row (context, model, path,
7302                     path_down_mode, tree_view->priv->empty_view_drop,
7303                     drop_append_mode);
7304     }
7305
7306   if (path)
7307     gtk_tree_path_free (path);
7308
7309   /* Unset this thing */
7310   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7311                                    NULL,
7312                                    GTK_TREE_VIEW_DROP_BEFORE);
7313
7314   if (target != GDK_NONE)
7315     {
7316       gtk_drag_get_data (widget, context, target, time);
7317       return TRUE;
7318     }
7319   else
7320     return FALSE;
7321 }
7322
7323 static void
7324 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7325                                   GdkDragContext   *context,
7326                                   /* coordinates relative to the widget */
7327                                   gint              x,
7328                                   gint              y,
7329                                   GtkSelectionData *selection_data,
7330                                   guint             info,
7331                                   guint             time)
7332 {
7333   GtkTreePath *path;
7334   TreeViewDragInfo *di;
7335   gboolean accepted = FALSE;
7336   GtkTreeModel *model;
7337   GtkTreeView *tree_view;
7338   GtkTreePath *dest_row;
7339   GdkDragAction suggested_action;
7340   gboolean path_down_mode;
7341   gboolean drop_append_mode;
7342
7343   tree_view = GTK_TREE_VIEW (widget);
7344
7345   model = gtk_tree_view_get_model (tree_view);
7346
7347   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7348     return;
7349
7350   di = get_info (tree_view);
7351
7352   if (di == NULL)
7353     return;
7354
7355   suggested_action = get_status_pending (context);
7356
7357   if (suggested_action)
7358     {
7359       /* We are getting this data due to a request in drag_motion,
7360        * rather than due to a request in drag_drop, so we are just
7361        * supposed to call drag_status, not actually paste in the
7362        * data.
7363        */
7364       path = get_logical_dest_row (tree_view, &path_down_mode,
7365                                    &drop_append_mode);
7366
7367       if (path == NULL)
7368         suggested_action = 0;
7369       else if (path_down_mode)
7370         gtk_tree_path_down (path);
7371
7372       if (suggested_action)
7373         {
7374           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7375                                                      path,
7376                                                      selection_data))
7377             {
7378               if (path_down_mode)
7379                 {
7380                   path_down_mode = FALSE;
7381                   gtk_tree_path_up (path);
7382
7383                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7384                                                              path,
7385                                                              selection_data))
7386                     suggested_action = 0;
7387                 }
7388               else
7389                 suggested_action = 0;
7390             }
7391         }
7392
7393       gdk_drag_status (context, suggested_action, time);
7394
7395       if (path)
7396         gtk_tree_path_free (path);
7397
7398       /* If you can't drop, remove user drop indicator until the next motion */
7399       if (suggested_action == 0)
7400         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7401                                          NULL,
7402                                          GTK_TREE_VIEW_DROP_BEFORE);
7403
7404       return;
7405     }
7406
7407   dest_row = get_dest_row (context, &path_down_mode);
7408
7409   if (dest_row == NULL)
7410     return;
7411
7412   if (selection_data->length >= 0)
7413     {
7414       if (path_down_mode)
7415         {
7416           gtk_tree_path_down (dest_row);
7417           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7418                                                      dest_row, selection_data))
7419             gtk_tree_path_up (dest_row);
7420         }
7421     }
7422
7423   if (selection_data->length >= 0)
7424     {
7425       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7426                                                  dest_row,
7427                                                  selection_data))
7428         accepted = TRUE;
7429     }
7430
7431   gtk_drag_finish (context,
7432                    accepted,
7433                    (context->action == GDK_ACTION_MOVE),
7434                    time);
7435
7436   if (gtk_tree_path_get_depth (dest_row) == 1
7437       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7438     {
7439       /* special special case drag to "0", scroll to first item */
7440       if (!tree_view->priv->scroll_to_path)
7441         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7442     }
7443
7444   gtk_tree_path_free (dest_row);
7445
7446   /* drop dest_row */
7447   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7448 }
7449
7450
7451
7452 /* GtkContainer Methods
7453  */
7454
7455
7456 static void
7457 gtk_tree_view_remove (GtkContainer *container,
7458                       GtkWidget    *widget)
7459 {
7460   GtkTreeView *tree_view;
7461   GtkTreeViewChild *child = NULL;
7462   GList *tmp_list;
7463
7464   g_return_if_fail (GTK_IS_TREE_VIEW (container));
7465
7466   tree_view = GTK_TREE_VIEW (container);
7467
7468   tmp_list = tree_view->priv->children;
7469   while (tmp_list)
7470     {
7471       child = tmp_list->data;
7472       if (child->widget == widget)
7473         {
7474           gtk_widget_unparent (widget);
7475
7476           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7477           g_list_free_1 (tmp_list);
7478           g_free (child);
7479           return;
7480         }
7481
7482       tmp_list = tmp_list->next;
7483     }
7484
7485   tmp_list = tree_view->priv->columns;
7486
7487   while (tmp_list)
7488     {
7489       GtkTreeViewColumn *column;
7490       column = tmp_list->data;
7491       if (column->button == widget)
7492         {
7493           gtk_widget_unparent (widget);
7494           return;
7495         }
7496       tmp_list = tmp_list->next;
7497     }
7498 }
7499
7500 static void
7501 gtk_tree_view_forall (GtkContainer *container,
7502                       gboolean      include_internals,
7503                       GtkCallback   callback,
7504                       gpointer      callback_data)
7505 {
7506   GtkTreeView *tree_view;
7507   GtkTreeViewChild *child = NULL;
7508   GtkTreeViewColumn *column;
7509   GList *tmp_list;
7510
7511   g_return_if_fail (GTK_IS_TREE_VIEW (container));
7512   g_return_if_fail (callback != NULL);
7513
7514   tree_view = GTK_TREE_VIEW (container);
7515
7516   tmp_list = tree_view->priv->children;
7517   while (tmp_list)
7518     {
7519       child = tmp_list->data;
7520       tmp_list = tmp_list->next;
7521
7522       (* callback) (child->widget, callback_data);
7523     }
7524   if (include_internals == FALSE)
7525     return;
7526
7527   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7528     {
7529       column = tmp_list->data;
7530
7531       if (column->button)
7532         (* callback) (column->button, callback_data);
7533     }
7534 }
7535
7536 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7537  * cells. If so we draw one big row-spanning focus rectangle.
7538  */
7539 static gboolean
7540 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7541 {
7542   GList *list;
7543
7544   for (list = tree_view->priv->columns; list; list = list->next)
7545     {
7546       if (!((GtkTreeViewColumn *)list->data)->visible)
7547         continue;
7548       if (_gtk_tree_view_column_count_special_cells (list->data))
7549         return TRUE;
7550     }
7551
7552   return FALSE;
7553 }
7554
7555 static void
7556 column_sizing_notify (GObject    *object,
7557                       GParamSpec *pspec,
7558                       gpointer    data)
7559 {
7560   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7561
7562   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7563     /* disable fixed height mode */
7564     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7565 }
7566
7567 /**
7568  * gtk_tree_view_set_fixed_height_mode:
7569  * @tree_view: a #GtkTreeView 
7570  * @enable: %TRUE to enable fixed height mode
7571  * 
7572  * Enables or disables the fixed height mode of @tree_view. 
7573  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7574  * rows have the same height. 
7575  * Only enable this option if all rows are the same height and all
7576  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7577  *
7578  * Since: 2.6 
7579  **/
7580 void
7581 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7582                                      gboolean     enable)
7583 {
7584   GList *l;
7585   
7586   enable = enable != FALSE;
7587
7588   if (enable == tree_view->priv->fixed_height_mode)
7589     return;
7590
7591   if (!enable)
7592     {
7593       tree_view->priv->fixed_height_mode = 0;
7594       tree_view->priv->fixed_height = -1;
7595
7596       /* force a revalidation */
7597       install_presize_handler (tree_view);
7598     }
7599   else 
7600     {
7601       /* make sure all columns are of type FIXED */
7602       for (l = tree_view->priv->columns; l; l = l->next)
7603         {
7604           GtkTreeViewColumn *c = l->data;
7605           
7606           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7607         }
7608       
7609       /* yes, we really have to do this is in a separate loop */
7610       for (l = tree_view->priv->columns; l; l = l->next)
7611         g_signal_connect (l->data, "notify::sizing",
7612                           G_CALLBACK (column_sizing_notify), tree_view);
7613       
7614       tree_view->priv->fixed_height_mode = 1;
7615       tree_view->priv->fixed_height = -1;
7616       
7617       if (tree_view->priv->tree)
7618         initialize_fixed_height_mode (tree_view);
7619     }
7620
7621   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7622 }
7623
7624 /**
7625  * gtk_tree_view_get_fixed_height_mode:
7626  * @tree_view: a #GtkTreeView
7627  * 
7628  * Returns whether fixed height mode is turned on for @tree_view.
7629  * 
7630  * Return value: %TRUE if @tree_view is in fixed height mode
7631  * 
7632  * Since: 2.6
7633  **/
7634 gboolean
7635 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7636 {
7637   return tree_view->priv->fixed_height_mode;
7638 }
7639
7640 /* Returns TRUE if the focus is within the headers, after the focus operation is
7641  * done
7642  */
7643 static gboolean
7644 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7645                             GtkDirectionType  dir,
7646                             gboolean          clamp_column_visible)
7647 {
7648   GtkWidget *focus_child;
7649
7650   GList *last_column, *first_column;
7651   GList *tmp_list;
7652   gboolean rtl;
7653
7654   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7655     return FALSE;
7656
7657   focus_child = GTK_CONTAINER (tree_view)->focus_child;
7658
7659   first_column = tree_view->priv->columns;
7660   while (first_column)
7661     {
7662       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7663           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7664           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7665            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7666         break;
7667       first_column = first_column->next;
7668     }
7669
7670   /* No headers are visible, or are focusable.  We can't focus in or out.
7671    */
7672   if (first_column == NULL)
7673     return FALSE;
7674
7675   last_column = g_list_last (tree_view->priv->columns);
7676   while (last_column)
7677     {
7678       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7679           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7680           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7681            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7682         break;
7683       last_column = last_column->prev;
7684     }
7685
7686
7687   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7688
7689   switch (dir)
7690     {
7691     case GTK_DIR_TAB_BACKWARD:
7692     case GTK_DIR_TAB_FORWARD:
7693     case GTK_DIR_UP:
7694     case GTK_DIR_DOWN:
7695       if (focus_child == NULL)
7696         {
7697           if (tree_view->priv->focus_column != NULL)
7698             focus_child = tree_view->priv->focus_column->button;
7699           else
7700             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7701           gtk_widget_grab_focus (focus_child);
7702           break;
7703         }
7704       return FALSE;
7705
7706     case GTK_DIR_LEFT:
7707     case GTK_DIR_RIGHT:
7708       if (focus_child == NULL)
7709         {
7710           if (tree_view->priv->focus_column != NULL)
7711             focus_child = tree_view->priv->focus_column->button;
7712           else if (dir == GTK_DIR_LEFT)
7713             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7714           else
7715             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7716           gtk_widget_grab_focus (focus_child);
7717           break;
7718         }
7719
7720       if (gtk_widget_child_focus (focus_child, dir))
7721         {
7722           /* The focus moves inside the button. */
7723           /* This is probably a great example of bad UI */
7724           break;
7725         }
7726
7727       /* We need to move the focus among the row of buttons. */
7728       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7729         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7730           break;
7731
7732       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7733           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7734         {
7735           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7736           break;
7737         }
7738
7739       while (tmp_list)
7740         {
7741           GtkTreeViewColumn *column;
7742
7743           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7744             tmp_list = tmp_list->next;
7745           else
7746             tmp_list = tmp_list->prev;
7747
7748           if (tmp_list == NULL)
7749             {
7750               g_warning ("Internal button not found");
7751               break;
7752             }
7753           column = tmp_list->data;
7754           if (column->button &&
7755               column->visible &&
7756               GTK_WIDGET_CAN_FOCUS (column->button))
7757             {
7758               focus_child = column->button;
7759               gtk_widget_grab_focus (column->button);
7760               break;
7761             }
7762         }
7763       break;
7764     default:
7765       g_assert_not_reached ();
7766       break;
7767     }
7768
7769   /* if focus child is non-null, we assume it's been set to the current focus child
7770    */
7771   if (focus_child)
7772     {
7773       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7774         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7775           {
7776             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7777             break;
7778           }
7779
7780       if (clamp_column_visible)
7781         {
7782           gtk_tree_view_clamp_column_visible (tree_view,
7783                                               tree_view->priv->focus_column,
7784                                               FALSE);
7785         }
7786     }
7787
7788   return (focus_child != NULL);
7789 }
7790
7791 /* This function returns in 'path' the first focusable path, if the given path
7792  * is already focusable, it's the returned one.
7793  */
7794 static gboolean
7795 search_first_focusable_path (GtkTreeView  *tree_view,
7796                              GtkTreePath **path,
7797                              gboolean      search_forward,
7798                              GtkRBTree   **new_tree,
7799                              GtkRBNode   **new_node)
7800 {
7801   GtkRBTree *tree = NULL;
7802   GtkRBNode *node = NULL;
7803
7804   if (!path || !*path)
7805     return FALSE;
7806
7807   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7808
7809   if (!tree || !node)
7810     return FALSE;
7811
7812   while (node && row_is_separator (tree_view, NULL, *path))
7813     {
7814       if (search_forward)
7815         _gtk_rbtree_next_full (tree, node, &tree, &node);
7816       else
7817         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7818
7819       if (*path)
7820         gtk_tree_path_free (*path);
7821
7822       if (node)
7823         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7824       else
7825         *path = NULL;
7826     }
7827
7828   if (new_tree)
7829     *new_tree = tree;
7830
7831   if (new_node)
7832     *new_node = node;
7833
7834   return (*path != NULL);
7835 }
7836
7837 static gint
7838 gtk_tree_view_focus (GtkWidget        *widget,
7839                      GtkDirectionType  direction)
7840 {
7841   GtkTreeView *tree_view;
7842   GtkWidget *focus_child;
7843   GtkContainer *container;
7844
7845   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
7846   g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
7847
7848   container = GTK_CONTAINER (widget);
7849   tree_view = GTK_TREE_VIEW (widget);
7850
7851   if (!GTK_WIDGET_IS_SENSITIVE (container))
7852     return FALSE;
7853
7854   focus_child = container->focus_child;
7855
7856   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
7857   /* Case 1.  Headers currently have focus. */
7858   if (focus_child)
7859     {
7860       switch (direction)
7861         {
7862         case GTK_DIR_LEFT:
7863         case GTK_DIR_RIGHT:
7864           gtk_tree_view_header_focus (tree_view, direction, TRUE);
7865           return TRUE;
7866         case GTK_DIR_TAB_BACKWARD:
7867         case GTK_DIR_UP:
7868           return FALSE;
7869         case GTK_DIR_TAB_FORWARD:
7870         case GTK_DIR_DOWN:
7871           gtk_widget_grab_focus (widget);
7872           return TRUE;
7873         default:
7874           g_assert_not_reached ();
7875           return FALSE;
7876         }
7877     }
7878
7879   /* Case 2. We don't have focus at all. */
7880   if (!GTK_WIDGET_HAS_FOCUS (container))
7881     {
7882       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
7883         gtk_widget_grab_focus (widget);
7884       return TRUE;
7885     }
7886
7887   /* Case 3. We have focus already. */
7888   if (direction == GTK_DIR_TAB_BACKWARD)
7889     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
7890   else if (direction == GTK_DIR_TAB_FORWARD)
7891     return FALSE;
7892
7893   /* Other directions caught by the keybindings */
7894   gtk_widget_grab_focus (widget);
7895   return TRUE;
7896 }
7897
7898 static void
7899 gtk_tree_view_grab_focus (GtkWidget *widget)
7900 {
7901   (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus) (widget);
7902
7903   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
7904 }
7905
7906 static void
7907 gtk_tree_view_style_set (GtkWidget *widget,
7908                          GtkStyle *previous_style)
7909 {
7910   GtkTreeView *tree_view;
7911   GList *list;
7912   GtkTreeViewColumn *column;
7913
7914   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
7915
7916   tree_view = GTK_TREE_VIEW (widget);
7917
7918   if (GTK_WIDGET_REALIZED (widget))
7919     {
7920       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
7921       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
7922       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
7923
7924       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
7925       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
7926     }
7927
7928   gtk_widget_style_get (widget,
7929                         "expander-size", &tree_view->priv->expander_size,
7930                         NULL);
7931   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
7932
7933   for (list = tree_view->priv->columns; list; list = list->next)
7934     {
7935       column = list->data;
7936       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
7937     }
7938
7939   tree_view->priv->fixed_height = -1;
7940   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
7941
7942   gtk_widget_queue_resize (widget);
7943 }
7944
7945
7946 static void
7947 gtk_tree_view_set_focus_child (GtkContainer *container,
7948                                GtkWidget    *child)
7949 {
7950   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7951   GList *list;
7952
7953   for (list = tree_view->priv->columns; list; list = list->next)
7954     {
7955       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
7956         {
7957           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
7958           break;
7959         }
7960     }
7961
7962   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
7963 }
7964
7965 static void
7966 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
7967                                GtkAdjustment *hadj,
7968                                GtkAdjustment *vadj)
7969 {
7970   gboolean need_adjust = FALSE;
7971
7972   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7973
7974   if (hadj)
7975     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
7976   else
7977     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7978   if (vadj)
7979     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
7980   else
7981     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7982
7983   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
7984     {
7985       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
7986                                             gtk_tree_view_adjustment_changed,
7987                                             tree_view);
7988       g_object_unref (tree_view->priv->hadjustment);
7989     }
7990
7991   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
7992     {
7993       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
7994                                             gtk_tree_view_adjustment_changed,
7995                                             tree_view);
7996       g_object_unref (tree_view->priv->vadjustment);
7997     }
7998
7999   if (tree_view->priv->hadjustment != hadj)
8000     {
8001       tree_view->priv->hadjustment = hadj;
8002       g_object_ref_sink (tree_view->priv->hadjustment);
8003
8004       g_signal_connect (tree_view->priv->hadjustment, "value_changed",
8005                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8006                         tree_view);
8007       need_adjust = TRUE;
8008     }
8009
8010   if (tree_view->priv->vadjustment != vadj)
8011     {
8012       tree_view->priv->vadjustment = vadj;
8013       g_object_ref_sink (tree_view->priv->vadjustment);
8014
8015       g_signal_connect (tree_view->priv->vadjustment, "value_changed",
8016                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8017                         tree_view);
8018       need_adjust = TRUE;
8019     }
8020
8021   if (need_adjust)
8022     gtk_tree_view_adjustment_changed (NULL, tree_view);
8023 }
8024
8025
8026 static gboolean
8027 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8028                                 GtkMovementStep    step,
8029                                 gint               count)
8030 {
8031   GdkModifierType state;
8032
8033   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8034   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8035                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8036                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8037                         step == GTK_MOVEMENT_PAGES ||
8038                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8039
8040   if (tree_view->priv->tree == NULL)
8041     return FALSE;
8042   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
8043     return FALSE;
8044
8045   gtk_tree_view_stop_editing (tree_view, FALSE);
8046   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8047   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8048
8049   if (gtk_get_current_event_state (&state))
8050     {
8051       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8052         tree_view->priv->ctrl_pressed = TRUE;
8053       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8054         tree_view->priv->shift_pressed = TRUE;
8055     }
8056   /* else we assume not pressed */
8057
8058   switch (step)
8059     {
8060       /* currently we make no distinction.  When we go bi-di, we need to */
8061     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8062     case GTK_MOVEMENT_VISUAL_POSITIONS:
8063       gtk_tree_view_move_cursor_left_right (tree_view, count);
8064       break;
8065     case GTK_MOVEMENT_DISPLAY_LINES:
8066       gtk_tree_view_move_cursor_up_down (tree_view, count);
8067       break;
8068     case GTK_MOVEMENT_PAGES:
8069       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8070       break;
8071     case GTK_MOVEMENT_BUFFER_ENDS:
8072       gtk_tree_view_move_cursor_start_end (tree_view, count);
8073       break;
8074     default:
8075       g_assert_not_reached ();
8076     }
8077
8078   tree_view->priv->ctrl_pressed = FALSE;
8079   tree_view->priv->shift_pressed = FALSE;
8080
8081   return TRUE;
8082 }
8083
8084 static void
8085 gtk_tree_view_put (GtkTreeView *tree_view,
8086                    GtkWidget   *child_widget,
8087                    /* in bin_window coordinates */
8088                    gint         x,
8089                    gint         y,
8090                    gint         width,
8091                    gint         height)
8092 {
8093   GtkTreeViewChild *child;
8094   
8095   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8096   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8097
8098   child = g_new (GtkTreeViewChild, 1);
8099
8100   child->widget = child_widget;
8101   child->x = x;
8102   child->y = y;
8103   child->width = width;
8104   child->height = height;
8105
8106   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8107
8108   if (GTK_WIDGET_REALIZED (tree_view))
8109     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8110   
8111   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8112 }
8113
8114 void
8115 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8116                                   GtkWidget   *widget,
8117                                   /* in tree coordinates */
8118                                   gint         x,
8119                                   gint         y,
8120                                   gint         width,
8121                                   gint         height)
8122 {
8123   GtkTreeViewChild *child = NULL;
8124   GList *list;
8125   GdkRectangle allocation;
8126
8127   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8128   g_return_if_fail (GTK_IS_WIDGET (widget));
8129
8130   for (list = tree_view->priv->children; list; list = list->next)
8131     {
8132       if (((GtkTreeViewChild *)list->data)->widget == widget)
8133         {
8134           child = list->data;
8135           break;
8136         }
8137     }
8138   if (child == NULL)
8139     return;
8140
8141   allocation.x = child->x = x;
8142   allocation.y = child->y = y;
8143   allocation.width = child->width = width;
8144   allocation.height = child->height = height;
8145
8146   if (GTK_WIDGET_REALIZED (widget))
8147     gtk_widget_size_allocate (widget, &allocation);
8148 }
8149
8150
8151 /* TreeModel Callbacks
8152  */
8153
8154 static void
8155 gtk_tree_view_row_changed (GtkTreeModel *model,
8156                            GtkTreePath  *path,
8157                            GtkTreeIter  *iter,
8158                            gpointer      data)
8159 {
8160   GtkTreeView *tree_view = (GtkTreeView *)data;
8161   GtkRBTree *tree;
8162   GtkRBNode *node;
8163   gboolean free_path = FALSE;
8164   GList *list;
8165   GtkTreePath *cursor_path;
8166
8167   g_return_if_fail (path != NULL || iter != NULL);
8168
8169   if (tree_view->priv->cursor != NULL)
8170     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8171   else
8172     cursor_path = NULL;
8173
8174   if (tree_view->priv->edited_column &&
8175       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8176     gtk_tree_view_stop_editing (tree_view, TRUE);
8177
8178   if (cursor_path != NULL)
8179     gtk_tree_path_free (cursor_path);
8180
8181   if (path == NULL)
8182     {
8183       path = gtk_tree_model_get_path (model, iter);
8184       free_path = TRUE;
8185     }
8186   else if (iter == NULL)
8187     gtk_tree_model_get_iter (model, iter, path);
8188
8189   if (_gtk_tree_view_find_node (tree_view,
8190                                 path,
8191                                 &tree,
8192                                 &node))
8193     /* We aren't actually showing the node */
8194     goto done;
8195
8196   if (tree == NULL)
8197     goto done;
8198
8199   if (tree_view->priv->fixed_height_mode
8200       && tree_view->priv->fixed_height >= 0)
8201     {
8202       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8203       if (GTK_WIDGET_REALIZED (tree_view))
8204         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8205     }
8206   else
8207     {
8208       _gtk_rbtree_node_mark_invalid (tree, node);
8209       for (list = tree_view->priv->columns; list; list = list->next)
8210         {
8211           GtkTreeViewColumn *column;
8212
8213           column = list->data;
8214           if (! column->visible)
8215             continue;
8216
8217           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8218             {
8219               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8220             }
8221         }
8222     }
8223
8224  done:
8225   if (GTK_WIDGET_REALIZED (tree_view) && !tree_view->priv->fixed_height_mode)
8226     install_presize_handler (tree_view);
8227   if (free_path)
8228     gtk_tree_path_free (path);
8229 }
8230
8231 static void
8232 gtk_tree_view_row_inserted (GtkTreeModel *model,
8233                             GtkTreePath  *path,
8234                             GtkTreeIter  *iter,
8235                             gpointer      data)
8236 {
8237   GtkTreeView *tree_view = (GtkTreeView *) data;
8238   gint *indices;
8239   GtkRBTree *tmptree, *tree;
8240   GtkRBNode *tmpnode = NULL;
8241   gint depth;
8242   gint i = 0;
8243   gint height;
8244   gboolean free_path = FALSE;
8245   gboolean node_visible = TRUE;
8246
8247   g_return_if_fail (path != NULL || iter != NULL);
8248
8249   if (tree_view->priv->fixed_height_mode
8250       && tree_view->priv->fixed_height >= 0)
8251     height = tree_view->priv->fixed_height;
8252   else
8253     height = 0;
8254
8255   if (path == NULL)
8256     {
8257       path = gtk_tree_model_get_path (model, iter);
8258       free_path = TRUE;
8259     }
8260   else if (iter == NULL)
8261     gtk_tree_model_get_iter (model, iter, path);
8262
8263   if (tree_view->priv->tree == NULL)
8264     tree_view->priv->tree = _gtk_rbtree_new ();
8265
8266   tmptree = tree = tree_view->priv->tree;
8267
8268   /* Update all row-references */
8269   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8270   depth = gtk_tree_path_get_depth (path);
8271   indices = gtk_tree_path_get_indices (path);
8272
8273   /* First, find the parent tree */
8274   while (i < depth - 1)
8275     {
8276       if (tmptree == NULL)
8277         {
8278           /* We aren't showing the node */
8279           node_visible = FALSE;
8280           goto done;
8281         }
8282
8283       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8284       if (tmpnode == NULL)
8285         {
8286           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8287                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8288                      "before the parent was inserted.");
8289           goto done;
8290         }
8291       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8292         {
8293           /* FIXME enforce correct behavior on model, probably */
8294           /* In theory, the model should have emitted has_child_toggled here.  We
8295            * try to catch it anyway, just to be safe, in case the model hasn't.
8296            */
8297           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8298                                                            tree,
8299                                                            tmpnode);
8300           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8301           gtk_tree_path_free (tmppath);
8302           goto done;
8303         }
8304
8305       tmptree = tmpnode->children;
8306       tree = tmptree;
8307       i++;
8308     }
8309
8310   if (tree == NULL)
8311     {
8312       node_visible = FALSE;
8313       goto done;
8314     }
8315
8316   /* ref the node */
8317   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8318   if (indices[depth - 1] == 0)
8319     {
8320       tmpnode = _gtk_rbtree_find_count (tree, 1);
8321       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8322     }
8323   else
8324     {
8325       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8326       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8327     }
8328
8329  done:
8330   if (height > 0)
8331     {
8332       if (tree)
8333         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8334
8335       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8336         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8337       else
8338         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8339     }
8340   else
8341     install_presize_handler (tree_view);
8342   if (free_path)
8343     gtk_tree_path_free (path);
8344 }
8345
8346 static void
8347 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8348                                      GtkTreePath  *path,
8349                                      GtkTreeIter  *iter,
8350                                      gpointer      data)
8351 {
8352   GtkTreeView *tree_view = (GtkTreeView *)data;
8353   GtkTreeIter real_iter;
8354   gboolean has_child;
8355   GtkRBTree *tree;
8356   GtkRBNode *node;
8357   gboolean free_path = FALSE;
8358
8359   g_return_if_fail (path != NULL || iter != NULL);
8360
8361   if (iter)
8362     real_iter = *iter;
8363
8364   if (path == NULL)
8365     {
8366       path = gtk_tree_model_get_path (model, iter);
8367       free_path = TRUE;
8368     }
8369   else if (iter == NULL)
8370     gtk_tree_model_get_iter (model, &real_iter, path);
8371
8372   if (_gtk_tree_view_find_node (tree_view,
8373                                 path,
8374                                 &tree,
8375                                 &node))
8376     /* We aren't actually showing the node */
8377     goto done;
8378
8379   if (tree == NULL)
8380     goto done;
8381
8382   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8383   /* Sanity check.
8384    */
8385   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8386     goto done;
8387
8388   if (has_child)
8389     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8390   else
8391     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8392
8393   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8394     {
8395       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8396       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8397         {
8398           GList *list;
8399
8400           for (list = tree_view->priv->columns; list; list = list->next)
8401             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8402               {
8403                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8404                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8405                 break;
8406               }
8407         }
8408       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8409     }
8410   else
8411     {
8412       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8413     }
8414
8415  done:
8416   if (free_path)
8417     gtk_tree_path_free (path);
8418 }
8419
8420 static void
8421 count_children_helper (GtkRBTree *tree,
8422                        GtkRBNode *node,
8423                        gpointer   data)
8424 {
8425   if (node->children)
8426     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8427   (*((gint *)data))++;
8428 }
8429
8430 static void
8431 check_selection_helper (GtkRBTree *tree,
8432                         GtkRBNode *node,
8433                         gpointer   data)
8434 {
8435   gint *value = (gint *)data;
8436
8437   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8438
8439   if (node->children && !*value)
8440     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8441 }
8442
8443 static void
8444 gtk_tree_view_row_deleted (GtkTreeModel *model,
8445                            GtkTreePath  *path,
8446                            gpointer      data)
8447 {
8448   GtkTreeView *tree_view = (GtkTreeView *)data;
8449   GtkRBTree *tree;
8450   GtkRBNode *node;
8451   GList *list;
8452   gint selection_changed = FALSE;
8453
8454   g_return_if_fail (path != NULL);
8455
8456   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8457
8458   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8459     return;
8460
8461   if (tree == NULL)
8462     return;
8463
8464   /* check if the selection has been changed */
8465   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8466                         check_selection_helper, &selection_changed);
8467
8468   for (list = tree_view->priv->columns; list; list = list->next)
8469     if (((GtkTreeViewColumn *)list->data)->visible &&
8470         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8471       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8472
8473   /* Ensure we don't have a dangling pointer to a dead node */
8474   ensure_unprelighted (tree_view);
8475
8476   /* Cancel editting if we've started */
8477   gtk_tree_view_stop_editing (tree_view, TRUE);
8478
8479   /* If we have a node expanded/collapsed timeout, remove it */
8480   if (tree_view->priv->expand_collapse_timeout != 0)
8481     {
8482       g_source_remove (tree_view->priv->expand_collapse_timeout);
8483       tree_view->priv->expand_collapse_timeout = 0;
8484
8485       /* Reset node */
8486       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8487       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
8488       tree_view->priv->expanded_collapsed_node = NULL;
8489     }
8490
8491   if (tree_view->priv->destroy_count_func)
8492     {
8493       gint child_count = 0;
8494       if (node->children)
8495         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8496       (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8497     }
8498
8499   if (tree->root->count == 1)
8500     {
8501       if (tree_view->priv->tree == tree)
8502         tree_view->priv->tree = NULL;
8503
8504       _gtk_rbtree_remove (tree);
8505     }
8506   else
8507     {
8508       _gtk_rbtree_remove_node (tree, node);
8509     }
8510
8511   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8512     {
8513       gtk_tree_row_reference_free (tree_view->priv->top_row);
8514       tree_view->priv->top_row = NULL;
8515     }
8516
8517   install_scroll_sync_handler (tree_view);
8518
8519   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8520
8521   if (selection_changed)
8522     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8523 }
8524
8525 static void
8526 cancel_arrow_animation (GtkTreeView *tree_view)
8527 {
8528   if (tree_view->priv->expand_collapse_timeout)
8529     {
8530       while (do_expand_collapse (tree_view));
8531
8532       g_source_remove (tree_view->priv->expand_collapse_timeout);
8533       tree_view->priv->expand_collapse_timeout = 0;
8534     }
8535 }
8536
8537 static void
8538 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8539                               GtkTreePath  *parent,
8540                               GtkTreeIter  *iter,
8541                               gint         *new_order,
8542                               gpointer      data)
8543 {
8544   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8545   GtkRBTree *tree;
8546   GtkRBNode *node;
8547   gint len;
8548
8549   len = gtk_tree_model_iter_n_children (model, iter);
8550
8551   if (len < 2)
8552     return;
8553
8554   gtk_tree_row_reference_reordered (G_OBJECT (data),
8555                                     parent,
8556                                     iter,
8557                                     new_order);
8558
8559   if (_gtk_tree_view_find_node (tree_view,
8560                                 parent,
8561                                 &tree,
8562                                 &node))
8563     return;
8564
8565   /* We need to special case the parent path */
8566   if (tree == NULL)
8567     tree = tree_view->priv->tree;
8568   else
8569     tree = node->children;
8570
8571   if (tree == NULL)
8572     return;
8573
8574   if (tree_view->priv->edited_column)
8575     gtk_tree_view_stop_editing (tree_view, TRUE);
8576
8577   /* we need to be unprelighted */
8578   ensure_unprelighted (tree_view);
8579
8580   /* clear the timeout */
8581   cancel_arrow_animation (tree_view);
8582   
8583   _gtk_rbtree_reorder (tree, new_order, len);
8584
8585   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8586
8587   gtk_tree_view_dy_to_top_row (tree_view);
8588 }
8589
8590
8591 /* Internal tree functions
8592  */
8593
8594
8595 static void
8596 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8597                                      GtkRBTree         *tree,
8598                                      GtkTreeViewColumn *column,
8599                                      gint              *x1,
8600                                      gint              *x2)
8601 {
8602   GtkTreeViewColumn *tmp_column = NULL;
8603   gint total_width;
8604   GList *list;
8605   gboolean rtl;
8606
8607   if (x1)
8608     *x1 = 0;
8609
8610   if (x2)
8611     *x2 = 0;
8612
8613   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8614
8615   total_width = 0;
8616   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8617        list;
8618        list = (rtl ? list->prev : list->next))
8619     {
8620       tmp_column = list->data;
8621
8622       if (tmp_column == column)
8623         break;
8624
8625       if (tmp_column->visible)
8626         total_width += tmp_column->width;
8627     }
8628
8629   if (tmp_column != column)
8630     {
8631       g_warning (G_STRLOC": passed-in column isn't in the tree");
8632       return;
8633     }
8634
8635   if (x1)
8636     *x1 = total_width;
8637
8638   if (x2)
8639     {
8640       if (column->visible)
8641         *x2 = total_width + column->width;
8642       else
8643         *x2 = total_width; /* width of 0 */
8644     }
8645 }
8646 static void
8647 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8648                                 GtkRBTree   *tree,
8649                                 gint        *x1,
8650                                 gint        *x2)
8651 {
8652   gint x_offset = 0;
8653   GList *list;
8654   GtkTreeViewColumn *tmp_column = NULL;
8655   gint total_width;
8656   gboolean indent_expanders;
8657   gboolean rtl;
8658
8659   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8660
8661   total_width = 0;
8662   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8663        list;
8664        list = (rtl ? list->prev : list->next))
8665     {
8666       tmp_column = list->data;
8667
8668       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8669         {
8670           if (rtl)
8671             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8672           else
8673             x_offset = total_width;
8674           break;
8675         }
8676
8677       if (tmp_column->visible)
8678         total_width += tmp_column->width;
8679     }
8680
8681   gtk_widget_style_get (GTK_WIDGET (tree_view),
8682                         "indent-expanders", &indent_expanders,
8683                         NULL);
8684
8685   if (indent_expanders)
8686     {
8687       if (rtl)
8688         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8689       else
8690         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8691     }
8692
8693   *x1 = x_offset;
8694   
8695   if (tmp_column && tmp_column->visible)
8696     /* +1 because x2 isn't included in the range. */
8697     *x2 = *x1 + tree_view->priv->expander_size + 1;
8698   else
8699     *x2 = *x1;
8700 }
8701
8702 static void
8703 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8704                           GtkRBTree   *tree,
8705                           GtkTreeIter *iter,
8706                           gint         depth,
8707                           gboolean     recurse)
8708 {
8709   GtkRBNode *temp = NULL;
8710   GtkTreePath *path = NULL;
8711   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8712
8713   do
8714     {
8715       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8716       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8717
8718       if (tree_view->priv->fixed_height > 0)
8719         {
8720           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8721             {
8722               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8723               _gtk_rbtree_node_mark_valid (tree, temp);
8724             }
8725         }
8726
8727       if (is_list)
8728         continue;
8729
8730       if (recurse)
8731         {
8732           GtkTreeIter child;
8733
8734           if (!path)
8735             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8736           else
8737             gtk_tree_path_next (path);
8738
8739           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8740             {
8741               gboolean expand;
8742
8743               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8744
8745               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8746                   && !expand)
8747                 {
8748                   temp->children = _gtk_rbtree_new ();
8749                   temp->children->parent_tree = tree;
8750                   temp->children->parent_node = temp;
8751                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8752                 }
8753             }
8754         }
8755
8756       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8757         {
8758           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8759             temp->flags ^= GTK_RBNODE_IS_PARENT;
8760         }
8761     }
8762   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8763
8764   if (path)
8765     gtk_tree_path_free (path);
8766 }
8767
8768 /* If height is non-NULL, then we set it to be the new height.  if it's all
8769  * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
8770  */
8771 static gboolean
8772 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
8773                                    GtkTreeIter *iter,
8774                                    gint         depth,
8775                                    gint        *height,
8776                                    GtkRBNode   *node)
8777 {
8778   GtkTreeViewColumn *column;
8779   GList *list;
8780   gboolean retval = FALSE;
8781   gint tmpheight;
8782   gint horizontal_separator;
8783
8784   gtk_widget_style_get (GTK_WIDGET (tree_view),
8785                         "horizontal-separator", &horizontal_separator,
8786                         NULL);
8787
8788   if (height)
8789     *height = -1;
8790
8791   for (list = tree_view->priv->columns; list; list = list->next)
8792     {
8793       gint width;
8794       column = list->data;
8795       if (column->dirty == TRUE)
8796         continue;
8797       if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
8798         continue;
8799       if (!column->visible)
8800         continue;
8801
8802       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
8803                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
8804                                                node->children?TRUE:FALSE);
8805
8806       if (height)
8807         {
8808           gtk_tree_view_column_cell_get_size (column,
8809                                               NULL, NULL, NULL,
8810                                               &width, &tmpheight);
8811           *height = MAX (*height, tmpheight);
8812         }
8813       else
8814         {
8815           gtk_tree_view_column_cell_get_size (column,
8816                                               NULL, NULL, NULL,
8817                                               &width, NULL);
8818         }
8819
8820       if (gtk_tree_view_is_expander_column (tree_view, column))
8821         {
8822           int tmp = 0;
8823
8824           tmp = horizontal_separator + width + (depth - 1) * tree_view->priv->level_indentation;
8825           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
8826             tmp += depth * tree_view->priv->expander_size;
8827
8828           if (tmp > column->requested_width)
8829             {
8830               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8831               retval = TRUE;
8832             }
8833         }
8834       else
8835         {
8836           if (horizontal_separator + width > column->requested_width)
8837             {
8838               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8839               retval = TRUE;
8840             }
8841         }
8842     }
8843
8844   return retval;
8845 }
8846
8847 static void
8848 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
8849                               GtkRBTree   *tree,
8850                               GtkTreeIter *iter,
8851                               gint         depth)
8852 {
8853   GtkRBNode *temp = tree->root;
8854   GtkTreeViewColumn *column;
8855   GList *list;
8856   GtkTreeIter child;
8857   gboolean is_all_dirty;
8858
8859   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
8860
8861   while (temp->left != tree->nil)
8862     temp = temp->left;
8863
8864   do
8865     {
8866       TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
8867       is_all_dirty = TRUE;
8868       for (list = tree_view->priv->columns; list; list = list->next)
8869         {
8870           column = list->data;
8871           if (column->dirty == FALSE)
8872             {
8873               is_all_dirty = FALSE;
8874               break;
8875             }
8876         }
8877
8878       if (is_all_dirty)
8879         return;
8880
8881       gtk_tree_view_discover_dirty_iter (tree_view,
8882                                          iter,
8883                                          depth,
8884                                          NULL,
8885                                          temp);
8886       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
8887           temp->children != NULL)
8888         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
8889       temp = _gtk_rbtree_next (tree, temp);
8890     }
8891   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8892 }
8893
8894
8895 /* Make sure the node is visible vertically */
8896 static void
8897 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8898                                   GtkRBTree   *tree,
8899                                   GtkRBNode   *node)
8900 {
8901   gint node_dy, height;
8902   GtkTreePath *path = NULL;
8903
8904   if (!GTK_WIDGET_REALIZED (tree_view))
8905     return;
8906
8907   /* just return if the node is visible, avoiding a costly expose */
8908   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8909   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8910   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8911       && node_dy >= tree_view->priv->vadjustment->value
8912       && node_dy + height <= (tree_view->priv->vadjustment->value
8913                               + tree_view->priv->vadjustment->page_size))
8914     return;
8915
8916   path = _gtk_tree_view_find_path (tree_view, tree, node);
8917   if (path)
8918     {
8919       /* We process updates because we want to clear old selected items when we scroll.
8920        * if this is removed, we get a "selection streak" at the bottom. */
8921       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8922       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8923       gtk_tree_path_free (path);
8924     }
8925 }
8926
8927 static void
8928 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8929                                     GtkTreeViewColumn *column,
8930                                     gboolean           focus_to_cell)
8931 {
8932   gint x, width;
8933
8934   if (column == NULL)
8935     return;
8936
8937   x = column->button->allocation.x;
8938   width = column->button->allocation.width;
8939
8940   if (width > tree_view->priv->hadjustment->page_size)
8941     {
8942       /* The column is larger than the horizontal page size.  If the
8943        * column has cells which can be focussed individually, then we make
8944        * sure the cell which gets focus is fully visible (if even the
8945        * focus cell is bigger than the page size, we make sure the
8946        * left-hand side of the cell is visible).
8947        *
8948        * If the column does not have those so-called special cells, we
8949        * make sure the left-hand side of the column is visible.
8950        */
8951
8952       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8953         {
8954           GtkTreePath *cursor_path;
8955           GdkRectangle background_area, cell_area, focus_area;
8956
8957           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8958
8959           gtk_tree_view_get_cell_area (tree_view,
8960                                        cursor_path, column, &cell_area);
8961           gtk_tree_view_get_background_area (tree_view,
8962                                              cursor_path, column,
8963                                              &background_area);
8964
8965           gtk_tree_path_free (cursor_path);
8966
8967           _gtk_tree_view_column_get_focus_area (column,
8968                                                 &background_area,
8969                                                 &cell_area,
8970                                                 &focus_area);
8971
8972           x = focus_area.x;
8973           width = focus_area.width;
8974
8975           if (width < tree_view->priv->hadjustment->page_size)
8976             {
8977               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8978                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8979                                           x + width - tree_view->priv->hadjustment->page_size);
8980               else if (tree_view->priv->hadjustment->value > x)
8981                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8982             }
8983         }
8984
8985       gtk_adjustment_set_value (tree_view->priv->hadjustment,
8986                                 CLAMP (x,
8987                                        tree_view->priv->hadjustment->lower,
8988                                        tree_view->priv->hadjustment->upper
8989                                        - tree_view->priv->hadjustment->page_size));
8990     }
8991   else
8992     {
8993       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8994           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8995                                     x + width - tree_view->priv->hadjustment->page_size);
8996       else if (tree_view->priv->hadjustment->value > x)
8997         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8998   }
8999 }
9000
9001 /* This function could be more efficient.  I'll optimize it if profiling seems
9002  * to imply that it is important */
9003 GtkTreePath *
9004 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9005                           GtkRBTree   *tree,
9006                           GtkRBNode   *node)
9007 {
9008   GtkTreePath *path;
9009   GtkRBTree *tmp_tree;
9010   GtkRBNode *tmp_node, *last;
9011   gint count;
9012
9013   path = gtk_tree_path_new ();
9014
9015   g_return_val_if_fail (node != NULL, path);
9016   g_return_val_if_fail (node != tree->nil, path);
9017
9018   count = 1 + node->left->count;
9019
9020   last = node;
9021   tmp_node = node->parent;
9022   tmp_tree = tree;
9023   while (tmp_tree)
9024     {
9025       while (tmp_node != tmp_tree->nil)
9026         {
9027           if (tmp_node->right == last)
9028             count += 1 + tmp_node->left->count;
9029           last = tmp_node;
9030           tmp_node = tmp_node->parent;
9031         }
9032       gtk_tree_path_prepend_index (path, count - 1);
9033       last = tmp_tree->parent_node;
9034       tmp_tree = tmp_tree->parent_tree;
9035       if (last)
9036         {
9037           count = 1 + last->left->count;
9038           tmp_node = last->parent;
9039         }
9040     }
9041   return path;
9042 }
9043
9044 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9045  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9046  * both set to NULL.
9047  */
9048 gboolean
9049 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9050                           GtkTreePath  *path,
9051                           GtkRBTree   **tree,
9052                           GtkRBNode   **node)
9053 {
9054   GtkRBNode *tmpnode = NULL;
9055   GtkRBTree *tmptree = tree_view->priv->tree;
9056   gint *indices = gtk_tree_path_get_indices (path);
9057   gint depth = gtk_tree_path_get_depth (path);
9058   gint i = 0;
9059
9060   *node = NULL;
9061   *tree = NULL;
9062
9063   if (depth == 0 || tmptree == NULL)
9064     return FALSE;
9065   do
9066     {
9067       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9068       ++i;
9069       if (tmpnode == NULL)
9070         {
9071           *tree = NULL;
9072           *node = NULL;
9073           return FALSE;
9074         }
9075       if (i >= depth)
9076         {
9077           *tree = tmptree;
9078           *node = tmpnode;
9079           return FALSE;
9080         }
9081       *tree = tmptree;
9082       *node = tmpnode;
9083       tmptree = tmpnode->children;
9084       if (tmptree == NULL)
9085         return TRUE;
9086     }
9087   while (1);
9088 }
9089
9090 static gboolean
9091 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9092                                   GtkTreeViewColumn *column)
9093 {
9094   GList *list;
9095
9096   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9097     return FALSE;
9098
9099   if (tree_view->priv->expander_column != NULL)
9100     {
9101       if (tree_view->priv->expander_column == column)
9102         return TRUE;
9103       return FALSE;
9104     }
9105   else
9106     {
9107       for (list = tree_view->priv->columns;
9108            list;
9109            list = list->next)
9110         if (((GtkTreeViewColumn *)list->data)->visible)
9111           break;
9112       if (list && list->data == column)
9113         return TRUE;
9114     }
9115   return FALSE;
9116 }
9117
9118 static void
9119 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9120                                 guint           keyval,
9121                                 guint           modmask,
9122                                 gboolean        add_shifted_binding,
9123                                 GtkMovementStep step,
9124                                 gint            count)
9125 {
9126   
9127   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9128                                 "move_cursor", 2,
9129                                 G_TYPE_ENUM, step,
9130                                 G_TYPE_INT, count);
9131
9132   if (add_shifted_binding)
9133     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9134                                   "move_cursor", 2,
9135                                   G_TYPE_ENUM, step,
9136                                   G_TYPE_INT, count);
9137
9138   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9139    return;
9140
9141   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9142                                 "move_cursor", 2,
9143                                 G_TYPE_ENUM, step,
9144                                 G_TYPE_INT, count);
9145
9146   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9147                                 "move_cursor", 2,
9148                                 G_TYPE_ENUM, step,
9149                                 G_TYPE_INT, count);
9150 }
9151
9152 static gint
9153 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9154                                  GtkTreeIter  *iter,
9155                                  GtkRBTree    *tree,
9156                                  GtkRBNode    *node)
9157 {
9158   gint retval = FALSE;
9159   do
9160     {
9161       g_return_val_if_fail (node != NULL, FALSE);
9162
9163       if (node->children)
9164         {
9165           GtkTreeIter child;
9166           GtkRBTree *new_tree;
9167           GtkRBNode *new_node;
9168
9169           new_tree = node->children;
9170           new_node = new_tree->root;
9171
9172           while (new_node && new_node->left != new_tree->nil)
9173             new_node = new_node->left;
9174
9175           if (!gtk_tree_model_iter_children (model, &child, iter))
9176             return FALSE;
9177
9178           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9179         }
9180
9181       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9182         retval = TRUE;
9183       gtk_tree_model_unref_node (model, iter);
9184       node = _gtk_rbtree_next (tree, node);
9185     }
9186   while (gtk_tree_model_iter_next (model, iter));
9187
9188   return retval;
9189 }
9190
9191 static gint
9192 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9193                                               GtkRBTree   *tree)
9194 {
9195   GtkTreeIter iter;
9196   GtkTreePath *path;
9197   GtkRBNode *node;
9198   gint retval;
9199
9200   if (!tree)
9201     return FALSE;
9202
9203   node = tree->root;
9204   while (node && node->left != tree->nil)
9205     node = node->left;
9206
9207   g_return_val_if_fail (node != NULL, FALSE);
9208   path = _gtk_tree_view_find_path (tree_view, tree, node);
9209   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9210                            &iter, path);
9211   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9212   gtk_tree_path_free (path);
9213
9214   return retval;
9215 }
9216
9217 static void
9218 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9219                                     GtkTreeViewColumn *column)
9220 {
9221   GtkTreeViewColumn *left_column;
9222   GtkTreeViewColumn *cur_column = NULL;
9223   GtkTreeViewColumnReorder *reorder;
9224   gboolean rtl;
9225   GList *tmp_list;
9226   gint left;
9227
9228   /* We want to precalculate the motion list such that we know what column slots
9229    * are available.
9230    */
9231   left_column = NULL;
9232   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9233
9234   /* First, identify all possible drop spots */
9235   if (rtl)
9236     tmp_list = g_list_last (tree_view->priv->columns);
9237   else
9238     tmp_list = g_list_first (tree_view->priv->columns);
9239
9240   while (tmp_list)
9241     {
9242       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9243       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9244
9245       if (cur_column->visible == FALSE)
9246         continue;
9247
9248       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9249       if (left_column != column && cur_column != column &&
9250           tree_view->priv->column_drop_func &&
9251           ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9252         {
9253           left_column = cur_column;
9254           continue;
9255         }
9256       reorder = g_new (GtkTreeViewColumnReorder, 1);
9257       reorder->left_column = left_column;
9258       left_column = reorder->right_column = cur_column;
9259
9260       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9261     }
9262
9263   /* Add the last one */
9264   if (tree_view->priv->column_drop_func == NULL ||
9265       ((left_column != column) &&
9266        (* tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9267     {
9268       reorder = g_new (GtkTreeViewColumnReorder, 1);
9269       reorder->left_column = left_column;
9270       reorder->right_column = NULL;
9271       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9272     }
9273
9274   /* We quickly check to see if it even makes sense to reorder columns. */
9275   /* If there is nothing that can be moved, then we return */
9276
9277   if (tree_view->priv->column_drag_info == NULL)
9278     return;
9279
9280   /* We know there are always 2 slots possbile, as you can always return column. */
9281   /* If that's all there is, return */
9282   if (tree_view->priv->column_drag_info->next == NULL || 
9283       (tree_view->priv->column_drag_info->next->next == NULL &&
9284        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9285        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9286     {
9287       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9288         g_free (tmp_list->data);
9289       g_list_free (tree_view->priv->column_drag_info);
9290       tree_view->priv->column_drag_info = NULL;
9291       return;
9292     }
9293   /* We fill in the ranges for the columns, now that we've isolated them */
9294   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9295
9296   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9297     {
9298       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9299
9300       reorder->left_align = left;
9301       if (tmp_list->next != NULL)
9302         {
9303           g_assert (tmp_list->next->data);
9304           left = reorder->right_align = (reorder->right_column->button->allocation.x +
9305                                          reorder->right_column->button->allocation.width +
9306                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
9307         }
9308       else
9309         {
9310           gint width;
9311
9312           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9313           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9314         }
9315     }
9316 }
9317
9318 void
9319 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9320                                   GtkTreeViewColumn *column)
9321 {
9322   GdkEvent *send_event;
9323   GtkAllocation allocation;
9324   gint x, y, width, height;
9325   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9326   GdkDisplay *display = gdk_screen_get_display (screen);
9327
9328   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9329   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9330
9331   gtk_tree_view_set_column_drag_info (tree_view, column);
9332
9333   if (tree_view->priv->column_drag_info == NULL)
9334     return;
9335
9336   if (tree_view->priv->drag_window == NULL)
9337     {
9338       GdkWindowAttr attributes;
9339       guint attributes_mask;
9340
9341       attributes.window_type = GDK_WINDOW_CHILD;
9342       attributes.wclass = GDK_INPUT_OUTPUT;
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   gdk_window_move_resize (tree_view->priv->drag_window,
9386                           column->button->allocation.x,
9387                           0,
9388                           column->button->allocation.width,
9389                           column->button->allocation.height);
9390
9391   /* Kids, don't try this at home */
9392   g_object_ref (column->button);
9393   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9394   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9395   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9396   g_object_unref (column->button);
9397
9398   tree_view->priv->drag_column_x = column->button->allocation.x;
9399   allocation = column->button->allocation;
9400   allocation.x = 0;
9401   gtk_widget_size_allocate (column->button, &allocation);
9402   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9403
9404   tree_view->priv->drag_column = column;
9405   gdk_window_show (tree_view->priv->drag_window);
9406
9407   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9408   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9409
9410   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9411   while (gtk_events_pending ())
9412     gtk_main_iteration ();
9413
9414   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9415   gdk_pointer_grab (tree_view->priv->drag_window,
9416                     FALSE,
9417                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9418                     NULL, NULL, GDK_CURRENT_TIME);
9419   gdk_keyboard_grab (tree_view->priv->drag_window,
9420                      FALSE,
9421                      GDK_CURRENT_TIME);
9422 }
9423
9424 static void
9425 gtk_tree_view_queue_draw_arrow (GtkTreeView      *tree_view,
9426                                 GtkRBTree        *tree,
9427                                 GtkRBNode        *node,
9428                                 GdkRectangle     *clip_rect)
9429 {
9430   GdkRectangle rect;
9431
9432   if (!GTK_WIDGET_REALIZED (tree_view))
9433     return;
9434
9435   rect.x = 0;
9436   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
9437
9438   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9439   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9440
9441   if (clip_rect)
9442     {
9443       GdkRectangle new_rect;
9444
9445       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9446
9447       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9448     }
9449   else
9450     {
9451       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9452     }
9453 }
9454
9455 void
9456 _gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
9457                                 GtkRBTree    *tree,
9458                                 GtkRBNode    *node,
9459                                 GdkRectangle *clip_rect)
9460 {
9461   GdkRectangle rect;
9462
9463   if (!GTK_WIDGET_REALIZED (tree_view))
9464     return;
9465
9466   rect.x = 0;
9467   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
9468
9469   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9470   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9471
9472   if (clip_rect)
9473     {
9474       GdkRectangle new_rect;
9475
9476       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9477
9478       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9479     }
9480   else
9481     {
9482       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9483     }
9484 }
9485
9486 static void
9487 gtk_tree_view_queue_draw_path (GtkTreeView      *tree_view,
9488                                GtkTreePath      *path,
9489                                GdkRectangle     *clip_rect)
9490 {
9491   GtkRBTree *tree = NULL;
9492   GtkRBNode *node = NULL;
9493
9494   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9495
9496   if (tree)
9497     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9498 }
9499
9500 /* x and y are the mouse position
9501  */
9502 static void
9503 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9504                           GtkRBTree   *tree,
9505                           GtkRBNode   *node,
9506                           /* in bin_window coordinates */
9507                           gint         x,
9508                           gint         y)
9509 {
9510   GdkRectangle area;
9511   GtkStateType state;
9512   GtkWidget *widget;
9513   gint x_offset = 0;
9514   gint x2;
9515   gint vertical_separator;
9516   gint expander_size;
9517   GtkExpanderStyle expander_style;
9518
9519   gtk_widget_style_get (GTK_WIDGET (tree_view),
9520                         "vertical-separator", &vertical_separator,
9521                         NULL);
9522   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9523
9524   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9525     return;
9526
9527   widget = GTK_WIDGET (tree_view);
9528
9529   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9530
9531   area.x = x_offset;
9532   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9533   area.width = expander_size + 2;
9534   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9535
9536   if (GTK_WIDGET_STATE (tree_view) == GTK_STATE_INSENSITIVE)
9537     {
9538       state = GTK_STATE_INSENSITIVE;
9539     }
9540   else if (node == tree_view->priv->button_pressed_node)
9541     {
9542       if (x >= area.x && x <= (area.x + area.width) &&
9543           y >= area.y && y <= (area.y + area.height))
9544         state = GTK_STATE_ACTIVE;
9545       else
9546         state = GTK_STATE_NORMAL;
9547     }
9548   else
9549     {
9550       if (node == tree_view->priv->prelight_node &&
9551           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9552         state = GTK_STATE_PRELIGHT;
9553       else
9554         state = GTK_STATE_NORMAL;
9555     }
9556
9557   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9558     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9559   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9560     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9561   else if (node->children != NULL)
9562     expander_style = GTK_EXPANDER_EXPANDED;
9563   else
9564     expander_style = GTK_EXPANDER_COLLAPSED;
9565
9566   gtk_paint_expander (widget->style,
9567                       tree_view->priv->bin_window,
9568                       state,
9569                       &area,
9570                       widget,
9571                       "treeview",
9572                       area.x + area.width / 2,
9573                       area.y + area.height / 2,
9574                       expander_style);
9575 }
9576
9577 static void
9578 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9579
9580 {
9581   GtkTreePath *cursor_path;
9582
9583   if ((tree_view->priv->tree == NULL) ||
9584       (! GTK_WIDGET_REALIZED (tree_view)))
9585     return;
9586
9587   cursor_path = NULL;
9588   if (tree_view->priv->cursor)
9589     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9590
9591   if (cursor_path == NULL)
9592     {
9593       /* Consult the selection before defaulting to the
9594        * first focusable element
9595        */
9596       GList *selected_rows;
9597       GtkTreeModel *model;
9598       GtkTreeSelection *selection;
9599
9600       selection = gtk_tree_view_get_selection (tree_view);
9601       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9602
9603       if (selected_rows)
9604         {
9605           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9606           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9607           g_list_free (selected_rows);
9608         }
9609       else
9610         {
9611           cursor_path = gtk_tree_path_new_first ();
9612           search_first_focusable_path (tree_view, &cursor_path,
9613                                        TRUE, NULL, NULL);
9614         }
9615
9616       gtk_tree_row_reference_free (tree_view->priv->cursor);
9617       tree_view->priv->cursor = NULL;
9618
9619       if (cursor_path)
9620         {
9621           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9622             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9623           else
9624             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9625         }
9626     }
9627
9628   if (cursor_path)
9629     {
9630       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9631
9632       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9633       gtk_tree_path_free (cursor_path);
9634
9635       if (tree_view->priv->focus_column == NULL)
9636         {
9637           GList *list;
9638           for (list = tree_view->priv->columns; list; list = list->next)
9639             {
9640               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9641                 {
9642                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9643                   break;
9644                 }
9645             }
9646         }
9647     }
9648 }
9649
9650 static void
9651 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9652                                    gint         count)
9653 {
9654   gint selection_count;
9655   GtkRBTree *cursor_tree = NULL;
9656   GtkRBNode *cursor_node = NULL;
9657   GtkRBTree *new_cursor_tree = NULL;
9658   GtkRBNode *new_cursor_node = NULL;
9659   GtkTreePath *cursor_path = NULL;
9660   gboolean grab_focus = TRUE;
9661   gboolean selectable;
9662
9663   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9664     return;
9665
9666   cursor_path = NULL;
9667   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9668     /* FIXME: we lost the cursor; should we get the first? */
9669     return;
9670
9671   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9672   _gtk_tree_view_find_node (tree_view, cursor_path,
9673                             &cursor_tree, &cursor_node);
9674
9675   if (cursor_tree == NULL)
9676     /* FIXME: we lost the cursor; should we get the first? */
9677     return;
9678
9679   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9680   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9681                                                       cursor_node,
9682                                                       cursor_path);
9683
9684   if (selection_count == 0
9685       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9686       && !tree_view->priv->ctrl_pressed
9687       && selectable)
9688     {
9689       /* Don't move the cursor, but just select the current node */
9690       new_cursor_tree = cursor_tree;
9691       new_cursor_node = cursor_node;
9692     }
9693   else
9694     {
9695       if (count == -1)
9696         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9697                                &new_cursor_tree, &new_cursor_node);
9698       else
9699         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9700                                &new_cursor_tree, &new_cursor_node);
9701     }
9702
9703   gtk_tree_path_free (cursor_path);
9704
9705   if (new_cursor_node)
9706     {
9707       cursor_path = _gtk_tree_view_find_path (tree_view,
9708                                               new_cursor_tree, new_cursor_node);
9709
9710       search_first_focusable_path (tree_view, &cursor_path,
9711                                    (count != -1),
9712                                    &new_cursor_tree,
9713                                    &new_cursor_node);
9714
9715       if (cursor_path)
9716         gtk_tree_path_free (cursor_path);
9717     }
9718
9719   /*
9720    * If the list has only one item and multi-selection is set then select
9721    * the row (if not yet selected).
9722    */
9723   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9724       new_cursor_node == NULL)
9725     {
9726       if (count == -1)
9727         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9728                                &new_cursor_tree, &new_cursor_node);
9729       else
9730         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9731                                &new_cursor_tree, &new_cursor_node);
9732
9733       if (new_cursor_node == NULL
9734           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9735         {
9736           new_cursor_node = cursor_node;
9737           new_cursor_tree = cursor_tree;
9738         }
9739       else
9740         {
9741           new_cursor_node = NULL;
9742         }
9743     }
9744
9745   if (new_cursor_node)
9746     {
9747       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9748       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9749       gtk_tree_path_free (cursor_path);
9750     }
9751   else
9752     {
9753       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9754
9755       if (!tree_view->priv->shift_pressed)
9756         {
9757           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9758                                           count < 0 ?
9759                                           GTK_DIR_UP : GTK_DIR_DOWN))
9760             {
9761               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9762
9763               if (toplevel)
9764                 gtk_widget_child_focus (toplevel,
9765                                         count < 0 ?
9766                                         GTK_DIR_TAB_BACKWARD :
9767                                         GTK_DIR_TAB_FORWARD);
9768
9769               grab_focus = FALSE;
9770             }
9771         }
9772       else
9773         {
9774           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9775         }
9776     }
9777
9778   if (grab_focus)
9779     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9780 }
9781
9782 static void
9783 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9784                                         gint         count)
9785 {
9786   GtkRBTree *cursor_tree = NULL;
9787   GtkRBNode *cursor_node = NULL;
9788   GtkTreePath *old_cursor_path = NULL;
9789   GtkTreePath *cursor_path = NULL;
9790   GtkRBTree *start_cursor_tree = NULL;
9791   GtkRBNode *start_cursor_node = NULL;
9792   gint y;
9793   gint window_y;
9794   gint vertical_separator;
9795
9796   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9797     return;
9798
9799   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9800     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9801   else
9802     /* This is sorta weird.  Focus in should give us a cursor */
9803     return;
9804
9805   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9806   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9807                             &cursor_tree, &cursor_node);
9808
9809   if (cursor_tree == NULL)
9810     {
9811       /* FIXME: we lost the cursor.  Should we try to get one? */
9812       gtk_tree_path_free (old_cursor_path);
9813       return;
9814     }
9815   g_return_if_fail (cursor_node != NULL);
9816
9817   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9818   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9819   y += tree_view->priv->cursor_offset;
9820   y += count * (int)tree_view->priv->vadjustment->page_increment;
9821   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9822
9823   if (y >= tree_view->priv->height)
9824     y = tree_view->priv->height - 1;
9825
9826   tree_view->priv->cursor_offset =
9827     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9828                              &cursor_tree, &cursor_node);
9829
9830   if (tree_view->priv->cursor_offset >= BACKGROUND_HEIGHT (cursor_node))
9831     {
9832       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9833                              &cursor_tree, &cursor_node);
9834       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9835     }
9836
9837   y -= tree_view->priv->cursor_offset;
9838   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9839
9840   start_cursor_tree = cursor_tree;
9841   start_cursor_node = cursor_node;
9842
9843   if (! search_first_focusable_path (tree_view, &cursor_path,
9844                                      (count != -1),
9845                                      &cursor_tree, &cursor_node))
9846     {
9847       /* It looks like we reached the end of the view without finding
9848        * a focusable row.  We will step backwards to find the last
9849        * focusable row.
9850        */
9851       cursor_tree = start_cursor_tree;
9852       cursor_node = start_cursor_node;
9853       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9854
9855       search_first_focusable_path (tree_view, &cursor_path,
9856                                    (count == -1),
9857                                    &cursor_tree, &cursor_node);
9858     }
9859
9860   if (!cursor_path)
9861     goto cleanup;
9862
9863   /* update y */
9864   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9865
9866   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9867
9868   y -= window_y;
9869   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9870   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9871   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9872
9873   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9874     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9875
9876 cleanup:
9877   gtk_tree_path_free (old_cursor_path);
9878   gtk_tree_path_free (cursor_path);
9879 }
9880
9881 static void
9882 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9883                                       gint         count)
9884 {
9885   GtkRBTree *cursor_tree = NULL;
9886   GtkRBNode *cursor_node = NULL;
9887   GtkTreePath *cursor_path = NULL;
9888   GtkTreeViewColumn *column;
9889   GtkTreeIter iter;
9890   GList *list;
9891   gboolean found_column = FALSE;
9892   gboolean rtl;
9893
9894   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9895
9896   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9897     return;
9898
9899   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9900     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9901   else
9902     return;
9903
9904   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9905   if (cursor_tree == NULL)
9906     return;
9907   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9908     {
9909       gtk_tree_path_free (cursor_path);
9910       return;
9911     }
9912   gtk_tree_path_free (cursor_path);
9913
9914   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9915   if (tree_view->priv->focus_column)
9916     {
9917       for (; list; list = (rtl ? list->prev : list->next))
9918         {
9919           if (list->data == tree_view->priv->focus_column)
9920             break;
9921         }
9922     }
9923
9924   while (list)
9925     {
9926       gboolean left, right;
9927
9928       column = list->data;
9929       if (column->visible == FALSE)
9930         goto loop_end;
9931
9932       gtk_tree_view_column_cell_set_cell_data (column,
9933                                                tree_view->priv->model,
9934                                                &iter,
9935                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9936                                                cursor_node->children?TRUE:FALSE);
9937
9938       if (rtl)
9939         {
9940           right = list->prev ? TRUE : FALSE;
9941           left = list->next ? TRUE : FALSE;
9942         }
9943       else
9944         {
9945           left = list->prev ? TRUE : FALSE;
9946           right = list->next ? TRUE : FALSE;
9947         }
9948
9949       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9950         {
9951           tree_view->priv->focus_column = column;
9952           found_column = TRUE;
9953           break;
9954         }
9955     loop_end:
9956       if (count == 1)
9957         list = rtl ? list->prev : list->next;
9958       else
9959         list = rtl ? list->next : list->prev;
9960     }
9961
9962   if (found_column)
9963     {
9964       if (!gtk_tree_view_has_special_cell (tree_view))
9965         _gtk_tree_view_queue_draw_node (tree_view,
9966                                         cursor_tree,
9967                                         cursor_node,
9968                                         NULL);
9969       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9970     }
9971   else
9972     {
9973       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9974     }
9975
9976   gtk_tree_view_clamp_column_visible (tree_view,
9977                                       tree_view->priv->focus_column, TRUE);
9978 }
9979
9980 static void
9981 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9982                                      gint         count)
9983 {
9984   GtkRBTree *cursor_tree;
9985   GtkRBNode *cursor_node;
9986   GtkTreePath *path;
9987   GtkTreePath *old_path;
9988
9989   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9990     return;
9991
9992   g_return_if_fail (tree_view->priv->tree != NULL);
9993
9994   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9995
9996   cursor_tree = tree_view->priv->tree;
9997   cursor_node = cursor_tree->root;
9998
9999   if (count == -1)
10000     {
10001       while (cursor_node && cursor_node->left != cursor_tree->nil)
10002         cursor_node = cursor_node->left;
10003
10004       /* Now go forward to find the first focusable row. */
10005       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10006       search_first_focusable_path (tree_view, &path,
10007                                    TRUE, &cursor_tree, &cursor_node);
10008     }
10009   else
10010     {
10011       do
10012         {
10013           while (cursor_node && cursor_node->right != cursor_tree->nil)
10014             cursor_node = cursor_node->right;
10015           if (cursor_node->children == NULL)
10016             break;
10017
10018           cursor_tree = cursor_node->children;
10019           cursor_node = cursor_tree->root;
10020         }
10021       while (1);
10022
10023       /* Now go backwards to find last focusable row. */
10024       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10025       search_first_focusable_path (tree_view, &path,
10026                                    FALSE, &cursor_tree, &cursor_node);
10027     }
10028
10029   if (!path)
10030     goto cleanup;
10031
10032   if (gtk_tree_path_compare (old_path, path))
10033     {
10034       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10035     }
10036   else
10037     {
10038       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10039     }
10040
10041 cleanup:
10042   gtk_tree_path_free (old_path);
10043   gtk_tree_path_free (path);
10044 }
10045
10046 static gboolean
10047 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10048 {
10049   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10050     return FALSE;
10051
10052   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10053     return FALSE;
10054
10055   gtk_tree_selection_select_all (tree_view->priv->selection);
10056
10057   return TRUE;
10058 }
10059
10060 static gboolean
10061 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10062 {
10063   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10064     return FALSE;
10065
10066   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10067     return FALSE;
10068
10069   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10070
10071   return TRUE;
10072 }
10073
10074 static gboolean
10075 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10076                                       gboolean     start_editing)
10077 {
10078   GtkRBTree *cursor_tree = NULL;
10079   GtkRBNode *cursor_node = NULL;
10080   GtkTreePath *cursor_path = NULL;
10081   GtkTreeSelectMode mode = 0;
10082
10083   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10084     return FALSE;
10085
10086   if (tree_view->priv->cursor)
10087     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10088
10089   if (cursor_path == NULL)
10090     return FALSE;
10091
10092   _gtk_tree_view_find_node (tree_view, cursor_path,
10093                             &cursor_tree, &cursor_node);
10094
10095   if (cursor_tree == NULL)
10096     {
10097       gtk_tree_path_free (cursor_path);
10098       return FALSE;
10099     }
10100
10101   if (!tree_view->priv->shift_pressed && start_editing &&
10102       tree_view->priv->focus_column)
10103     {
10104       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10105         {
10106           gtk_tree_path_free (cursor_path);
10107           return TRUE;
10108         }
10109     }
10110
10111   if (tree_view->priv->ctrl_pressed)
10112     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10113   if (tree_view->priv->shift_pressed)
10114     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10115
10116   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10117                                             cursor_node,
10118                                             cursor_tree,
10119                                             cursor_path,
10120                                             mode,
10121                                             FALSE);
10122
10123   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10124
10125   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10126   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10127
10128   if (!tree_view->priv->shift_pressed)
10129     gtk_tree_view_row_activated (tree_view, cursor_path,
10130                                  tree_view->priv->focus_column);
10131     
10132   gtk_tree_path_free (cursor_path);
10133
10134   return TRUE;
10135 }
10136
10137 static gboolean
10138 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10139 {
10140   GtkRBTree *cursor_tree = NULL;
10141   GtkRBNode *cursor_node = NULL;
10142   GtkTreePath *cursor_path = NULL;
10143
10144   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10145     return FALSE;
10146
10147   cursor_path = NULL;
10148   if (tree_view->priv->cursor)
10149     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10150
10151   if (cursor_path == NULL)
10152     return FALSE;
10153
10154   _gtk_tree_view_find_node (tree_view, cursor_path,
10155                             &cursor_tree, &cursor_node);
10156   if (cursor_tree == NULL)
10157     {
10158       gtk_tree_path_free (cursor_path);
10159       return FALSE;
10160     }
10161
10162   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10163                                             cursor_node,
10164                                             cursor_tree,
10165                                             cursor_path,
10166                                             GTK_TREE_SELECT_MODE_TOGGLE,
10167                                             FALSE);
10168
10169   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10170
10171   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10172   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10173   gtk_tree_path_free (cursor_path);
10174
10175   return TRUE;
10176 }
10177
10178 static gboolean
10179 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10180                                                gboolean     logical,
10181                                                gboolean     expand,
10182                                                gboolean     open_all)
10183 {
10184   GtkTreePath *cursor_path = NULL;
10185   GtkRBTree *tree;
10186   GtkRBNode *node;
10187
10188   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10189     return FALSE;
10190
10191   cursor_path = NULL;
10192   if (tree_view->priv->cursor)
10193     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10194
10195   if (cursor_path == NULL)
10196     return FALSE;
10197
10198   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10199     return FALSE;
10200
10201   /* Don't handle the event if we aren't an expander */
10202   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10203     return FALSE;
10204
10205   if (!logical
10206       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10207     expand = !expand;
10208
10209   if (expand)
10210     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10211   else
10212     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10213
10214   gtk_tree_path_free (cursor_path);
10215
10216   return TRUE;
10217 }
10218
10219 static gboolean
10220 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10221 {
10222   GtkRBTree *cursor_tree = NULL;
10223   GtkRBNode *cursor_node = NULL;
10224   GtkTreePath *cursor_path = NULL;
10225   GdkModifierType state;
10226
10227   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10228     return FALSE;
10229
10230   cursor_path = NULL;
10231   if (tree_view->priv->cursor)
10232     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10233
10234   if (cursor_path == NULL)
10235     return FALSE;
10236
10237   _gtk_tree_view_find_node (tree_view, cursor_path,
10238                             &cursor_tree, &cursor_node);
10239   if (cursor_tree == NULL)
10240     {
10241       gtk_tree_path_free (cursor_path);
10242       return FALSE;
10243     }
10244
10245   if (gtk_get_current_event_state (&state))
10246     {
10247       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10248         tree_view->priv->ctrl_pressed = TRUE;
10249     }
10250
10251   if (cursor_tree->parent_node)
10252     {
10253       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10254       cursor_node = cursor_tree->parent_node;
10255       cursor_tree = cursor_tree->parent_tree;
10256
10257       gtk_tree_path_up (cursor_path);
10258
10259       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10260     }
10261
10262   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10263
10264   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10265   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10266   gtk_tree_path_free (cursor_path);
10267
10268   tree_view->priv->ctrl_pressed = FALSE;
10269
10270   return TRUE;
10271 }
10272 static gboolean
10273 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10274 {
10275   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
10276   tree_view->priv->typeselect_flush_timeout = 0;
10277
10278   return FALSE;
10279 }
10280
10281 /* Cut and paste from gtkwindow.c */
10282 static void
10283 send_focus_change (GtkWidget *widget,
10284                    gboolean   in)
10285 {
10286   GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10287
10288   g_object_ref (widget);
10289    
10290  if (in)
10291     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
10292   else
10293     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
10294
10295   fevent->focus_change.type = GDK_FOCUS_CHANGE;
10296   fevent->focus_change.window = g_object_ref (widget->window);
10297   fevent->focus_change.in = in;
10298   
10299   gtk_widget_event (widget, fevent);
10300   
10301   g_object_notify (G_OBJECT (widget), "has-focus");
10302
10303   g_object_unref (widget);
10304   gdk_event_free (fevent);
10305 }
10306
10307 static void
10308 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10309 {
10310   GtkWidget *frame, *vbox, *toplevel;
10311
10312   if (tree_view->priv->search_custom_entry_set)
10313     return;
10314
10315   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10316
10317    if (tree_view->priv->search_window != NULL)
10318      {
10319        if (GTK_WINDOW (toplevel)->group)
10320          gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10321                                       GTK_WINDOW (tree_view->priv->search_window));
10322        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
10323          gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
10324                                          GTK_WINDOW (tree_view->priv->search_window));
10325        return;
10326      }
10327    
10328   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10329
10330   if (GTK_WINDOW (toplevel)->group)
10331     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10332                                  GTK_WINDOW (tree_view->priv->search_window));
10333
10334   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10335   g_signal_connect (tree_view->priv->search_window, "delete_event",
10336                     G_CALLBACK (gtk_tree_view_search_delete_event),
10337                     tree_view);
10338   g_signal_connect (tree_view->priv->search_window, "key_press_event",
10339                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10340                     tree_view);
10341   g_signal_connect (tree_view->priv->search_window, "button_press_event",
10342                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10343                     tree_view);
10344   g_signal_connect (tree_view->priv->search_window, "scroll_event",
10345                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10346                     tree_view);
10347
10348   frame = gtk_frame_new (NULL);
10349   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10350   gtk_widget_show (frame);
10351   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10352
10353   vbox = gtk_vbox_new (FALSE, 0);
10354   gtk_widget_show (vbox);
10355   gtk_container_add (GTK_CONTAINER (frame), vbox);
10356   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10357
10358   /* add entry */
10359   tree_view->priv->search_entry = gtk_entry_new ();
10360   gtk_widget_show (tree_view->priv->search_entry);
10361   g_signal_connect (tree_view->priv->search_entry, "populate_popup",
10362                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10363                     tree_view);
10364   g_signal_connect (tree_view->priv->search_entry,
10365                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10366                     tree_view);
10367   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10368                     "preedit_changed",
10369                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10370                     tree_view);
10371   gtk_container_add (GTK_CONTAINER (vbox),
10372                      tree_view->priv->search_entry);
10373
10374   gtk_widget_realize (tree_view->priv->search_entry);
10375 }
10376
10377 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10378  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10379  */
10380 static gboolean
10381 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10382                                              gboolean     keybinding)
10383 {
10384   /* We only start interactive search if we have focus or the columns
10385    * have focus.  If one of our children have focus, we don't want to
10386    * start the search.
10387    */
10388   GList *list;
10389   gboolean found_focus = FALSE;
10390   GtkWidgetClass *entry_parent_class;
10391   
10392   if (!tree_view->priv->enable_search && !keybinding)
10393     return FALSE;
10394
10395   if (tree_view->priv->search_custom_entry_set)
10396     return FALSE;
10397
10398   if (tree_view->priv->search_window != NULL &&
10399       GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
10400     return TRUE;
10401
10402   for (list = tree_view->priv->columns; list; list = list->next)
10403     {
10404       GtkTreeViewColumn *column;
10405
10406       column = list->data;
10407       if (! column->visible)
10408         continue;
10409
10410       if (GTK_WIDGET_HAS_FOCUS (column->button))
10411         {
10412           found_focus = TRUE;
10413           break;
10414         }
10415     }
10416   
10417   if (GTK_WIDGET_HAS_FOCUS (tree_view))
10418     found_focus = TRUE;
10419
10420   if (!found_focus)
10421     return FALSE;
10422
10423   if (tree_view->priv->search_column < 0)
10424     return FALSE;
10425
10426   gtk_tree_view_ensure_interactive_directory (tree_view);
10427
10428   if (keybinding)
10429     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10430
10431   /* done, show it */
10432   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10433   gtk_widget_show (tree_view->priv->search_window);
10434   if (tree_view->priv->search_entry_changed_id == 0)
10435     {
10436       tree_view->priv->search_entry_changed_id =
10437         g_signal_connect (tree_view->priv->search_entry, "changed",
10438                           G_CALLBACK (gtk_tree_view_search_init),
10439                           tree_view);
10440     }
10441
10442   tree_view->priv->typeselect_flush_timeout =
10443     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10444                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10445                    tree_view);
10446
10447   /* Grab focus will select all the text.  We don't want that to happen, so we
10448    * call the parent instance and bypass the selection change.  This is probably
10449    * really non-kosher. */
10450   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10451   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10452
10453   /* send focus-in event */
10454   send_focus_change (tree_view->priv->search_entry, TRUE);
10455
10456   /* search first matching iter */
10457   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10458
10459   return TRUE;
10460 }
10461
10462 static gboolean
10463 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10464 {
10465   return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
10466 }
10467
10468 /* this function returns the new width of the column being resized given
10469  * the column and x position of the cursor; the x cursor position is passed
10470  * in as a pointer and automagicly corrected if it's beyond min/max limits
10471  */
10472 static gint
10473 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10474                                 gint       i,
10475                                 gint      *x)
10476 {
10477   GtkTreeViewColumn *column;
10478   gint width;
10479   gboolean rtl;
10480
10481   /* first translate the x position from widget->window
10482    * to clist->clist_window
10483    */
10484   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10485   column = g_list_nth (tree_view->priv->columns, i)->data;
10486   width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
10487  
10488   /* Clamp down the value */
10489   if (column->min_width == -1)
10490     width = MAX (column->button->requisition.width,
10491                  width);
10492   else
10493     width = MAX (column->min_width,
10494                  width);
10495   if (column->max_width != -1)
10496     width = MIN (width, column->max_width);
10497
10498   *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
10499  
10500   return width;
10501 }
10502
10503
10504 /* FIXME this adjust_allocation is a big cut-and-paste from
10505  * GtkCList, needs to be some "official" way to do this
10506  * factored out.
10507  */
10508 typedef struct
10509 {
10510   GdkWindow *window;
10511   int dx;
10512   int dy;
10513 } ScrollData;
10514
10515 /* The window to which widget->window is relative */
10516 #define ALLOCATION_WINDOW(widget)               \
10517    (GTK_WIDGET_NO_WINDOW (widget) ?             \
10518     (widget)->window :                          \
10519      gdk_window_get_parent ((widget)->window))
10520
10521 static void
10522 adjust_allocation_recurse (GtkWidget *widget,
10523                            gpointer   data)
10524 {
10525   ScrollData *scroll_data = data;
10526
10527   /* Need to really size allocate instead of just poking
10528    * into widget->allocation if the widget is not realized.
10529    * FIXME someone figure out why this was.
10530    */
10531   if (!GTK_WIDGET_REALIZED (widget))
10532     {
10533       if (GTK_WIDGET_VISIBLE (widget))
10534         {
10535           GdkRectangle tmp_rectangle = widget->allocation;
10536           tmp_rectangle.x += scroll_data->dx;
10537           tmp_rectangle.y += scroll_data->dy;
10538           
10539           gtk_widget_size_allocate (widget, &tmp_rectangle);
10540         }
10541     }
10542   else
10543     {
10544       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10545         {
10546           widget->allocation.x += scroll_data->dx;
10547           widget->allocation.y += scroll_data->dy;
10548           
10549           if (GTK_IS_CONTAINER (widget))
10550             gtk_container_forall (GTK_CONTAINER (widget),
10551                                   adjust_allocation_recurse,
10552                                   data);
10553         }
10554     }
10555 }
10556
10557 static void
10558 adjust_allocation (GtkWidget *widget,
10559                    int        dx,
10560                    int        dy)
10561 {
10562   ScrollData scroll_data;
10563
10564   if (GTK_WIDGET_REALIZED (widget))
10565     scroll_data.window = ALLOCATION_WINDOW (widget);
10566   else
10567     scroll_data.window = NULL;
10568     
10569   scroll_data.dx = dx;
10570   scroll_data.dy = dy;
10571   
10572   adjust_allocation_recurse (widget, &scroll_data);
10573 }
10574
10575 /* Callbacks */
10576 static void
10577 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10578                                   GtkTreeView   *tree_view)
10579 {
10580   if (GTK_WIDGET_REALIZED (tree_view))
10581     {
10582       gint dy;
10583         
10584       gdk_window_move (tree_view->priv->bin_window,
10585                        - tree_view->priv->hadjustment->value,
10586                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10587       gdk_window_move (tree_view->priv->header_window,
10588                        - tree_view->priv->hadjustment->value,
10589                        0);
10590       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10591       if (dy && tree_view->priv->edited_column)
10592         {
10593           if (GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10594             {
10595               GList *list;
10596               GtkWidget *widget;
10597               GtkTreeViewChild *child = NULL;
10598
10599               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10600               adjust_allocation (widget, 0, dy); 
10601               
10602               for (list = tree_view->priv->children; list; list = list->next)
10603                 {
10604                   child = (GtkTreeViewChild *)list->data;
10605                   if (child->widget == widget)
10606                     {
10607                       child->y += dy;
10608                       break;
10609                     }
10610                 }
10611             }
10612         }
10613       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10614
10615       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10616         {
10617           /* update our dy and top_row */
10618           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10619
10620           if (!tree_view->priv->in_top_row_to_dy)
10621             gtk_tree_view_dy_to_top_row (tree_view);
10622         }
10623     }
10624 }
10625
10626 \f
10627
10628 /* Public methods
10629  */
10630
10631 /**
10632  * gtk_tree_view_new:
10633  *
10634  * Creates a new #GtkTreeView widget.
10635  *
10636  * Return value: A newly created #GtkTreeView widget.
10637  **/
10638 GtkWidget *
10639 gtk_tree_view_new (void)
10640 {
10641   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10642 }
10643
10644 /**
10645  * gtk_tree_view_new_with_model:
10646  * @model: the model.
10647  *
10648  * Creates a new #GtkTreeView widget with the model initialized to @model.
10649  *
10650  * Return value: A newly created #GtkTreeView widget.
10651  **/
10652 GtkWidget *
10653 gtk_tree_view_new_with_model (GtkTreeModel *model)
10654 {
10655   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10656 }
10657
10658 /* Public Accessors
10659  */
10660
10661 /**
10662  * gtk_tree_view_get_model:
10663  * @tree_view: a #GtkTreeView
10664  *
10665  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10666  * model is unset.
10667  *
10668  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
10669  **/
10670 GtkTreeModel *
10671 gtk_tree_view_get_model (GtkTreeView *tree_view)
10672 {
10673   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10674
10675   return tree_view->priv->model;
10676 }
10677
10678 /**
10679  * gtk_tree_view_set_model:
10680  * @tree_view: A #GtkTreeNode.
10681  * @model: The model.
10682  *
10683  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10684  * set, it will remove it before setting the new model.  If @model is %NULL, 
10685  * then it will unset the old model.
10686  **/
10687 void
10688 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10689                          GtkTreeModel *model)
10690 {
10691   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10692
10693   if (model != NULL)
10694     g_return_if_fail (GTK_IS_TREE_MODEL (model));
10695
10696   if (model == tree_view->priv->model)
10697     return;
10698
10699   if (tree_view->priv->scroll_to_path)
10700     {
10701       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10702       tree_view->priv->scroll_to_path = NULL;
10703     }
10704
10705   if (tree_view->priv->model)
10706     {
10707       GList *tmplist = tree_view->priv->columns;
10708
10709       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10710       gtk_tree_view_stop_editing (tree_view, TRUE);
10711
10712       if (tree_view->priv->expand_collapse_timeout)
10713         {
10714           g_source_remove (tree_view->priv->expand_collapse_timeout);
10715           tree_view->priv->expand_collapse_timeout = 0;
10716         }
10717
10718       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10719                                             gtk_tree_view_row_changed,
10720                                             tree_view);
10721       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10722                                             gtk_tree_view_row_inserted,
10723                                             tree_view);
10724       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10725                                             gtk_tree_view_row_has_child_toggled,
10726                                             tree_view);
10727       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10728                                             gtk_tree_view_row_deleted,
10729                                             tree_view);
10730       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10731                                             gtk_tree_view_rows_reordered,
10732                                             tree_view);
10733
10734       for (; tmplist; tmplist = tmplist->next)
10735         _gtk_tree_view_column_unset_model (tmplist->data,
10736                                            tree_view->priv->model);
10737
10738       if (tree_view->priv->tree)
10739         gtk_tree_view_free_rbtree (tree_view);
10740
10741       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10742       tree_view->priv->drag_dest_row = NULL;
10743       gtk_tree_row_reference_free (tree_view->priv->cursor);
10744       tree_view->priv->cursor = NULL;
10745       gtk_tree_row_reference_free (tree_view->priv->anchor);
10746       tree_view->priv->anchor = NULL;
10747       gtk_tree_row_reference_free (tree_view->priv->top_row);
10748       tree_view->priv->top_row = NULL;
10749       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
10750       tree_view->priv->last_button_press = NULL;
10751       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
10752       tree_view->priv->last_button_press_2 = NULL;
10753       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10754       tree_view->priv->scroll_to_path = NULL;
10755
10756       tree_view->priv->scroll_to_column = NULL;
10757
10758       g_object_unref (tree_view->priv->model);
10759
10760       tree_view->priv->search_column = -1;
10761       tree_view->priv->fixed_height_check = 0;
10762       tree_view->priv->fixed_height = -1;
10763       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10764     }
10765
10766   tree_view->priv->model = model;
10767
10768   if (tree_view->priv->model)
10769     {
10770       gint i;
10771       GtkTreePath *path;
10772       GtkTreeIter iter;
10773       GtkTreeModelFlags flags;
10774
10775       if (tree_view->priv->search_column == -1)
10776         {
10777           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10778             {
10779               GType type = gtk_tree_model_get_column_type (model, i);
10780
10781               if (g_value_type_transformable (type, G_TYPE_STRING))
10782                 {
10783                   tree_view->priv->search_column = i;
10784                   break;
10785                 }
10786             }
10787         }
10788
10789       g_object_ref (tree_view->priv->model);
10790       g_signal_connect (tree_view->priv->model,
10791                         "row_changed",
10792                         G_CALLBACK (gtk_tree_view_row_changed),
10793                         tree_view);
10794       g_signal_connect (tree_view->priv->model,
10795                         "row_inserted",
10796                         G_CALLBACK (gtk_tree_view_row_inserted),
10797                         tree_view);
10798       g_signal_connect (tree_view->priv->model,
10799                         "row_has_child_toggled",
10800                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10801                         tree_view);
10802       g_signal_connect (tree_view->priv->model,
10803                         "row_deleted",
10804                         G_CALLBACK (gtk_tree_view_row_deleted),
10805                         tree_view);
10806       g_signal_connect (tree_view->priv->model,
10807                         "rows_reordered",
10808                         G_CALLBACK (gtk_tree_view_rows_reordered),
10809                         tree_view);
10810
10811       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10812       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10813         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10814       else
10815         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10816
10817       path = gtk_tree_path_new_first ();
10818       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10819         {
10820           tree_view->priv->tree = _gtk_rbtree_new ();
10821           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10822         }
10823       gtk_tree_path_free (path);
10824
10825       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10826       install_presize_handler (tree_view);
10827     }
10828
10829   g_object_notify (G_OBJECT (tree_view), "model");
10830
10831   if (tree_view->priv->selection)
10832   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10833
10834   if (GTK_WIDGET_REALIZED (tree_view))
10835     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10836 }
10837
10838 /**
10839  * gtk_tree_view_get_selection:
10840  * @tree_view: A #GtkTreeView.
10841  *
10842  * Gets the #GtkTreeSelection associated with @tree_view.
10843  *
10844  * Return value: A #GtkTreeSelection object.
10845  **/
10846 GtkTreeSelection *
10847 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10848 {
10849   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10850
10851   return tree_view->priv->selection;
10852 }
10853
10854 /**
10855  * gtk_tree_view_get_hadjustment:
10856  * @tree_view: A #GtkTreeView
10857  *
10858  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10859  *
10860  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10861  * used.
10862  **/
10863 GtkAdjustment *
10864 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10865 {
10866   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10867
10868   if (tree_view->priv->hadjustment == NULL)
10869     gtk_tree_view_set_hadjustment (tree_view, NULL);
10870
10871   return tree_view->priv->hadjustment;
10872 }
10873
10874 /**
10875  * gtk_tree_view_set_hadjustment:
10876  * @tree_view: A #GtkTreeView
10877  * @adjustment: The #GtkAdjustment to set, or %NULL
10878  *
10879  * Sets the #GtkAdjustment for the current horizontal aspect.
10880  **/
10881 void
10882 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10883                                GtkAdjustment *adjustment)
10884 {
10885   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10886
10887   gtk_tree_view_set_adjustments (tree_view,
10888                                  adjustment,
10889                                  tree_view->priv->vadjustment);
10890
10891   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10892 }
10893
10894 /**
10895  * gtk_tree_view_get_vadjustment:
10896  * @tree_view: A #GtkTreeView
10897  *
10898  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10899  *
10900  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10901  * used.
10902  **/
10903 GtkAdjustment *
10904 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10905 {
10906   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10907
10908   if (tree_view->priv->vadjustment == NULL)
10909     gtk_tree_view_set_vadjustment (tree_view, NULL);
10910
10911   return tree_view->priv->vadjustment;
10912 }
10913
10914 /**
10915  * gtk_tree_view_set_vadjustment:
10916  * @tree_view: A #GtkTreeView
10917  * @adjustment: The #GtkAdjustment to set, or %NULL
10918  *
10919  * Sets the #GtkAdjustment for the current vertical aspect.
10920  **/
10921 void
10922 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10923                                GtkAdjustment *adjustment)
10924 {
10925   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10926
10927   gtk_tree_view_set_adjustments (tree_view,
10928                                  tree_view->priv->hadjustment,
10929                                  adjustment);
10930
10931   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10932 }
10933
10934 /* Column and header operations */
10935
10936 /**
10937  * gtk_tree_view_get_headers_visible:
10938  * @tree_view: A #GtkTreeView.
10939  *
10940  * Returns %TRUE if the headers on the @tree_view are visible.
10941  *
10942  * Return value: Whether the headers are visible or not.
10943  **/
10944 gboolean
10945 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10946 {
10947   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10948
10949   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10950 }
10951
10952 /**
10953  * gtk_tree_view_set_headers_visible:
10954  * @tree_view: A #GtkTreeView.
10955  * @headers_visible: %TRUE if the headers are visible
10956  *
10957  * Sets the visibility state of the headers.
10958  **/
10959 void
10960 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
10961                                    gboolean     headers_visible)
10962 {
10963   gint x, y;
10964   GList *list;
10965   GtkTreeViewColumn *column;
10966
10967   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10968
10969   headers_visible = !! headers_visible;
10970
10971   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
10972     return;
10973
10974   if (headers_visible)
10975     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10976   else
10977     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10978
10979   if (GTK_WIDGET_REALIZED (tree_view))
10980     {
10981       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
10982       if (headers_visible)
10983         {
10984           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));
10985
10986           if (GTK_WIDGET_MAPPED (tree_view))
10987             gtk_tree_view_map_buttons (tree_view);
10988         }
10989       else
10990         {
10991           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
10992
10993           for (list = tree_view->priv->columns; list; list = list->next)
10994             {
10995               column = list->data;
10996               gtk_widget_unmap (column->button);
10997             }
10998           gdk_window_hide (tree_view->priv->header_window);
10999         }
11000     }
11001
11002   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11003   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11004   tree_view->priv->vadjustment->lower = 0;
11005   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11006   gtk_adjustment_changed (tree_view->priv->vadjustment);
11007
11008   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11009
11010   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11011 }
11012
11013 /**
11014  * gtk_tree_view_columns_autosize:
11015  * @tree_view: A #GtkTreeView.
11016  *
11017  * Resizes all columns to their optimal width. Only works after the
11018  * treeview has been realized.
11019  **/
11020 void
11021 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11022 {
11023   gboolean dirty = FALSE;
11024   GList *list;
11025   GtkTreeViewColumn *column;
11026
11027   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11028
11029   for (list = tree_view->priv->columns; list; list = list->next)
11030     {
11031       column = list->data;
11032       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11033         continue;
11034       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11035       dirty = TRUE;
11036     }
11037
11038   if (dirty)
11039     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11040 }
11041
11042 /**
11043  * gtk_tree_view_set_headers_clickable:
11044  * @tree_view: A #GtkTreeView.
11045  * @setting: %TRUE if the columns are clickable.
11046  *
11047  * Allow the column title buttons to be clicked.
11048  **/
11049 void
11050 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11051                                      gboolean   setting)
11052 {
11053   GList *list;
11054
11055   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11056
11057   for (list = tree_view->priv->columns; list; list = list->next)
11058     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11059
11060   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11061 }
11062
11063
11064 /**
11065  * gtk_tree_view_get_headers_clickable:
11066  * @tree_view: A #GtkTreeView.
11067  *
11068  * Returns whether all header columns are clickable.
11069  *
11070  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11071  *
11072  * Since: 2.10
11073  **/
11074 gboolean 
11075 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11076 {
11077   GList *list;
11078   
11079   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11080
11081   for (list = tree_view->priv->columns; list; list = list->next)
11082     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11083       return FALSE;
11084
11085   return TRUE;
11086 }
11087
11088 /**
11089  * gtk_tree_view_set_rules_hint
11090  * @tree_view: a #GtkTreeView
11091  * @setting: %TRUE if the tree requires reading across rows
11092  *
11093  * This function tells GTK+ that the user interface for your
11094  * application requires users to read across tree rows and associate
11095  * cells with one another. By default, GTK+ will then render the tree
11096  * with alternating row colors. Do <emphasis>not</emphasis> use it
11097  * just because you prefer the appearance of the ruled tree; that's a
11098  * question for the theme. Some themes will draw tree rows in
11099  * alternating colors even when rules are turned off, and users who
11100  * prefer that appearance all the time can choose those themes. You
11101  * should call this function only as a <emphasis>semantic</emphasis>
11102  * hint to the theme engine that your tree makes alternating colors
11103  * useful from a functional standpoint (since it has lots of columns,
11104  * generally).
11105  *
11106  **/
11107 void
11108 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11109                               gboolean      setting)
11110 {
11111   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11112
11113   setting = setting != FALSE;
11114
11115   if (tree_view->priv->has_rules != setting)
11116     {
11117       tree_view->priv->has_rules = setting;
11118       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11119     }
11120
11121   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11122 }
11123
11124 /**
11125  * gtk_tree_view_get_rules_hint
11126  * @tree_view: a #GtkTreeView
11127  *
11128  * Gets the setting set by gtk_tree_view_set_rules_hint().
11129  *
11130  * Return value: %TRUE if rules are useful for the user of this tree
11131  **/
11132 gboolean
11133 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11134 {
11135   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11136
11137   return tree_view->priv->has_rules;
11138 }
11139
11140 /* Public Column functions
11141  */
11142
11143 /**
11144  * gtk_tree_view_append_column:
11145  * @tree_view: A #GtkTreeView.
11146  * @column: The #GtkTreeViewColumn to add.
11147  *
11148  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11149  * mode enabled, then @column must have its "sizing" property set to be
11150  * GTK_TREE_VIEW_COLUMN_FIXED.
11151  *
11152  * Return value: The number of columns in @tree_view after appending.
11153  **/
11154 gint
11155 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11156                              GtkTreeViewColumn *column)
11157 {
11158   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11159   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11160   g_return_val_if_fail (column->tree_view == NULL, -1);
11161
11162   return gtk_tree_view_insert_column (tree_view, column, -1);
11163 }
11164
11165
11166 /**
11167  * gtk_tree_view_remove_column:
11168  * @tree_view: A #GtkTreeView.
11169  * @column: The #GtkTreeViewColumn to remove.
11170  *
11171  * Removes @column from @tree_view.
11172  *
11173  * Return value: The number of columns in @tree_view after removing.
11174  **/
11175 gint
11176 gtk_tree_view_remove_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 == GTK_WIDGET (tree_view), -1);
11182
11183   if (tree_view->priv->focus_column == column)
11184     tree_view->priv->focus_column = NULL;
11185
11186   if (tree_view->priv->edited_column == column)
11187     {
11188       gtk_tree_view_stop_editing (tree_view, TRUE);
11189
11190       /* no need to, but just to be sure ... */
11191       tree_view->priv->edited_column = NULL;
11192     }
11193
11194   g_signal_handlers_disconnect_by_func (column,
11195                                         G_CALLBACK (column_sizing_notify),
11196                                         tree_view);
11197
11198   _gtk_tree_view_column_unset_tree_view (column);
11199
11200   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11201   tree_view->priv->n_columns--;
11202
11203   if (GTK_WIDGET_REALIZED (tree_view))
11204     {
11205       GList *list;
11206
11207       _gtk_tree_view_column_unrealize_button (column);
11208       for (list = tree_view->priv->columns; list; list = list->next)
11209         {
11210           GtkTreeViewColumn *tmp_column;
11211
11212           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11213           if (tmp_column->visible)
11214             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11215         }
11216
11217       if (tree_view->priv->n_columns == 0 &&
11218           gtk_tree_view_get_headers_visible (tree_view))
11219         gdk_window_hide (tree_view->priv->header_window);
11220
11221       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11222     }
11223
11224   g_object_unref (column);
11225   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11226
11227   return tree_view->priv->n_columns;
11228 }
11229
11230 /**
11231  * gtk_tree_view_insert_column:
11232  * @tree_view: A #GtkTreeView.
11233  * @column: The #GtkTreeViewColumn to be inserted.
11234  * @position: The position to insert @column in.
11235  *
11236  * This inserts the @column into the @tree_view at @position.  If @position is
11237  * -1, then the column is inserted at the end. If @tree_view has
11238  * "fixed_height" mode enabled, then @column must have its "sizing" property
11239  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11240  *
11241  * Return value: The number of columns in @tree_view after insertion.
11242  **/
11243 gint
11244 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11245                              GtkTreeViewColumn *column,
11246                              gint               position)
11247 {
11248   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11249   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11250   g_return_val_if_fail (column->tree_view == NULL, -1);
11251
11252   if (tree_view->priv->fixed_height_mode)
11253     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11254                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11255
11256   g_object_ref_sink (column);
11257
11258   if (tree_view->priv->n_columns == 0 &&
11259       GTK_WIDGET_REALIZED (tree_view) &&
11260       gtk_tree_view_get_headers_visible (tree_view))
11261     {
11262       gdk_window_show (tree_view->priv->header_window);
11263     }
11264
11265   g_signal_connect (column, "notify::sizing",
11266                     G_CALLBACK (column_sizing_notify), tree_view);
11267
11268   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11269                                             column, position);
11270   tree_view->priv->n_columns++;
11271
11272   _gtk_tree_view_column_set_tree_view (column, tree_view);
11273
11274   if (GTK_WIDGET_REALIZED (tree_view))
11275     {
11276       GList *list;
11277
11278       _gtk_tree_view_column_realize_button (column);
11279
11280       for (list = tree_view->priv->columns; list; list = list->next)
11281         {
11282           column = GTK_TREE_VIEW_COLUMN (list->data);
11283           if (column->visible)
11284             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11285         }
11286       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11287     }
11288
11289   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11290
11291   return tree_view->priv->n_columns;
11292 }
11293
11294 /**
11295  * gtk_tree_view_insert_column_with_attributes:
11296  * @tree_view: A #GtkTreeView
11297  * @position: The position to insert the new column in.
11298  * @title: The title to set the header to.
11299  * @cell: The #GtkCellRenderer.
11300  * @Varargs: A %NULL-terminated list of attributes.
11301  *
11302  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11303  * @position.  If @position is -1, then the newly created column is inserted at
11304  * the end.  The column is initialized with the attributes given. If @tree_view
11305  * has "fixed_height" mode enabled, then the new column will have its sizing
11306  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11307  *
11308  * Return value: The number of columns in @tree_view after insertion.
11309  **/
11310 gint
11311 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11312                                              gint             position,
11313                                              const gchar     *title,
11314                                              GtkCellRenderer *cell,
11315                                              ...)
11316 {
11317   GtkTreeViewColumn *column;
11318   gchar *attribute;
11319   va_list args;
11320   gint column_id;
11321
11322   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11323
11324   column = gtk_tree_view_column_new ();
11325   if (tree_view->priv->fixed_height_mode)
11326     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11327
11328   gtk_tree_view_column_set_title (column, title);
11329   gtk_tree_view_column_pack_start (column, cell, TRUE);
11330
11331   va_start (args, cell);
11332
11333   attribute = va_arg (args, gchar *);
11334
11335   while (attribute != NULL)
11336     {
11337       column_id = va_arg (args, gint);
11338       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11339       attribute = va_arg (args, gchar *);
11340     }
11341
11342   va_end (args);
11343
11344   gtk_tree_view_insert_column (tree_view, column, position);
11345
11346   return tree_view->priv->n_columns;
11347 }
11348
11349 /**
11350  * gtk_tree_view_insert_column_with_data_func:
11351  * @tree_view: a #GtkTreeView
11352  * @position: Position to insert, -1 for append
11353  * @title: column title
11354  * @cell: cell renderer for column
11355  * @func: function to set attributes of cell renderer
11356  * @data: data for @func
11357  * @dnotify: destroy notifier for @data
11358  *
11359  * Convenience function that inserts a new column into the #GtkTreeView
11360  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11361  * attributes (normally using data from the model). See also
11362  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11363  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11364  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11365  *
11366  * Return value: number of columns in the tree view post-insert
11367  **/
11368 gint
11369 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11370                                              gint                       position,
11371                                              const gchar               *title,
11372                                              GtkCellRenderer           *cell,
11373                                              GtkTreeCellDataFunc        func,
11374                                              gpointer                   data,
11375                                              GDestroyNotify             dnotify)
11376 {
11377   GtkTreeViewColumn *column;
11378
11379   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11380
11381   column = gtk_tree_view_column_new ();
11382   if (tree_view->priv->fixed_height_mode)
11383     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11384
11385   gtk_tree_view_column_set_title (column, title);
11386   gtk_tree_view_column_pack_start (column, cell, TRUE);
11387   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11388
11389   gtk_tree_view_insert_column (tree_view, column, position);
11390
11391   return tree_view->priv->n_columns;
11392 }
11393
11394 /**
11395  * gtk_tree_view_get_column:
11396  * @tree_view: A #GtkTreeView.
11397  * @n: The position of the column, counting from 0.
11398  *
11399  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11400  *
11401  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11402  * range of columns.
11403  **/
11404 GtkTreeViewColumn *
11405 gtk_tree_view_get_column (GtkTreeView *tree_view,
11406                           gint         n)
11407 {
11408   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11409
11410   if (n < 0 || n >= tree_view->priv->n_columns)
11411     return NULL;
11412
11413   if (tree_view->priv->columns == NULL)
11414     return NULL;
11415
11416   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11417 }
11418
11419 /**
11420  * gtk_tree_view_get_columns:
11421  * @tree_view: A #GtkTreeView
11422  *
11423  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11424  * The returned list must be freed with g_list_free ().
11425  *
11426  * Return value: A list of #GtkTreeViewColumn s
11427  **/
11428 GList *
11429 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11430 {
11431   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11432
11433   return g_list_copy (tree_view->priv->columns);
11434 }
11435
11436 /**
11437  * gtk_tree_view_move_column_after:
11438  * @tree_view: A #GtkTreeView
11439  * @column: The #GtkTreeViewColumn to be moved.
11440  * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
11441  *
11442  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11443  * @column is placed in the first position.
11444  **/
11445 void
11446 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11447                                  GtkTreeViewColumn *column,
11448                                  GtkTreeViewColumn *base_column)
11449 {
11450   GList *column_list_el, *base_el = NULL;
11451
11452   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11453
11454   column_list_el = g_list_find (tree_view->priv->columns, column);
11455   g_return_if_fail (column_list_el != NULL);
11456
11457   if (base_column)
11458     {
11459       base_el = g_list_find (tree_view->priv->columns, base_column);
11460       g_return_if_fail (base_el != NULL);
11461     }
11462
11463   if (column_list_el->prev == base_el)
11464     return;
11465
11466   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11467   if (base_el == NULL)
11468     {
11469       column_list_el->prev = NULL;
11470       column_list_el->next = tree_view->priv->columns;
11471       if (column_list_el->next)
11472         column_list_el->next->prev = column_list_el;
11473       tree_view->priv->columns = column_list_el;
11474     }
11475   else
11476     {
11477       column_list_el->prev = base_el;
11478       column_list_el->next = base_el->next;
11479       if (column_list_el->next)
11480         column_list_el->next->prev = column_list_el;
11481       base_el->next = column_list_el;
11482     }
11483
11484   if (GTK_WIDGET_REALIZED (tree_view))
11485     {
11486       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11487       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view));
11488     }
11489
11490   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11491 }
11492
11493 /**
11494  * gtk_tree_view_set_expander_column:
11495  * @tree_view: A #GtkTreeView
11496  * @column: %NULL, or the column to draw the expander arrow at.
11497  *
11498  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11499  * If @column is %NULL, then the expander arrow is always at the first 
11500  * visible column.
11501  *
11502  * If you do not want expander arrow to appear in your tree, set the 
11503  * expander column to a hidden column.
11504  **/
11505 void
11506 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11507                                    GtkTreeViewColumn *column)
11508 {
11509   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11510   if (column != NULL)
11511     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
11512
11513   if (tree_view->priv->expander_column != column)
11514     {
11515       GList *list;
11516
11517       if (column)
11518         {
11519           /* Confirm that column is in tree_view */
11520           for (list = tree_view->priv->columns; list; list = list->next)
11521             if (list->data == column)
11522               break;
11523           g_return_if_fail (list != NULL);
11524         }
11525
11526       tree_view->priv->expander_column = column;
11527       g_object_notify (G_OBJECT (tree_view), "expander-column");
11528     }
11529 }
11530
11531 /**
11532  * gtk_tree_view_get_expander_column:
11533  * @tree_view: A #GtkTreeView
11534  *
11535  * Returns the column that is the current expander column.  This
11536  * column has the expander arrow drawn next to it.
11537  *
11538  * Return value: The expander column.
11539  **/
11540 GtkTreeViewColumn *
11541 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11542 {
11543   GList *list;
11544
11545   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11546
11547   for (list = tree_view->priv->columns; list; list = list->next)
11548     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11549       return (GtkTreeViewColumn *) list->data;
11550   return NULL;
11551 }
11552
11553
11554 /**
11555  * gtk_tree_view_set_column_drag_function:
11556  * @tree_view: A #GtkTreeView.
11557  * @func: A function to determine which columns are reorderable, or %NULL.
11558  * @user_data: User data to be passed to @func, or %NULL
11559  * @destroy: Destroy notifier for @user_data, or %NULL
11560  *
11561  * Sets a user function for determining where a column may be dropped when
11562  * dragged.  This function is called on every column pair in turn at the
11563  * beginning of a column drag to determine where a drop can take place.  The
11564  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11565  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11566  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11567  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11568  * @tree_view reverts to the default behavior of allowing all columns to be
11569  * dropped everywhere.
11570  **/
11571 void
11572 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11573                                         GtkTreeViewColumnDropFunc  func,
11574                                         gpointer                   user_data,
11575                                         GtkDestroyNotify           destroy)
11576 {
11577   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11578
11579   if (tree_view->priv->column_drop_func_data_destroy)
11580     (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
11581
11582   tree_view->priv->column_drop_func = func;
11583   tree_view->priv->column_drop_func_data = user_data;
11584   tree_view->priv->column_drop_func_data_destroy = destroy;
11585 }
11586
11587 /**
11588  * gtk_tree_view_scroll_to_point:
11589  * @tree_view: a #GtkTreeView
11590  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11591  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11592  *
11593  * Scrolls the tree view such that the top-left corner of the visible
11594  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11595  * in tree coordinates.  The @tree_view must be realized before
11596  * this function is called.  If it isn't, you probably want to be
11597  * using gtk_tree_view_scroll_to_cell().
11598  *
11599  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11600  **/
11601 void
11602 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11603                                gint         tree_x,
11604                                gint         tree_y)
11605 {
11606   GtkAdjustment *hadj;
11607   GtkAdjustment *vadj;
11608
11609   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11610   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
11611
11612   hadj = tree_view->priv->hadjustment;
11613   vadj = tree_view->priv->vadjustment;
11614
11615   if (tree_x != -1)
11616     gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
11617   if (tree_y != -1)
11618     gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
11619 }
11620
11621 /**
11622  * gtk_tree_view_scroll_to_cell:
11623  * @tree_view: A #GtkTreeView.
11624  * @path: The path of the row to move to, or %NULL.
11625  * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
11626  * @use_align: whether to use alignment arguments, or %FALSE.
11627  * @row_align: The vertical alignment of the row specified by @path.
11628  * @col_align: The horizontal alignment of the column specified by @column.
11629  *
11630  * Moves the alignments of @tree_view to the position specified by @column and
11631  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11632  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11633  * or @path need to be non-%NULL.  @row_align determines where the row is
11634  * placed, and @col_align determines where @column is placed.  Both are expected
11635  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11636  * right/bottom alignment, 0.5 means center.
11637  *
11638  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11639  * tree does the minimum amount of work to scroll the cell onto the screen.
11640  * This means that the cell will be scrolled to the edge closest to its current
11641  * position.  If the cell is currently visible on the screen, nothing is done.
11642  *
11643  * This function only works if the model is set, and @path is a valid row on the
11644  * model.  If the model changes before the @tree_view is realized, the centered
11645  * path will be modified to reflect this change.
11646  **/
11647 void
11648 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11649                               GtkTreePath       *path,
11650                               GtkTreeViewColumn *column,
11651                               gboolean           use_align,
11652                               gfloat             row_align,
11653                               gfloat             col_align)
11654 {
11655   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11656   g_return_if_fail (tree_view->priv->model != NULL);
11657   g_return_if_fail (tree_view->priv->tree != NULL);
11658   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11659   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11660   g_return_if_fail (path != NULL || column != NULL);
11661
11662 #if 0
11663   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11664            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11665 #endif
11666   row_align = CLAMP (row_align, 0.0, 1.0);
11667   col_align = CLAMP (col_align, 0.0, 1.0);
11668
11669
11670   /* Note: Despite the benefits that come from having one code path for the
11671    * scrolling code, we short-circuit validate_visible_area's immplementation as
11672    * it is much slower than just going to the point.
11673    */
11674   if (! GTK_WIDGET_VISIBLE (tree_view) ||
11675       ! GTK_WIDGET_REALIZED (tree_view) ||
11676       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11677       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11678     {
11679       if (tree_view->priv->scroll_to_path)
11680         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11681
11682       tree_view->priv->scroll_to_path = NULL;
11683       tree_view->priv->scroll_to_column = NULL;
11684
11685       if (path)
11686         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11687       if (column)
11688         tree_view->priv->scroll_to_column = column;
11689       tree_view->priv->scroll_to_use_align = use_align;
11690       tree_view->priv->scroll_to_row_align = row_align;
11691       tree_view->priv->scroll_to_col_align = col_align;
11692
11693       install_presize_handler (tree_view);
11694     }
11695   else
11696     {
11697       GdkRectangle cell_rect;
11698       GdkRectangle vis_rect;
11699       gint dest_x, dest_y;
11700
11701       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11702       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11703
11704       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11705
11706       dest_x = vis_rect.x;
11707       dest_y = vis_rect.y;
11708
11709       if (column)
11710         {
11711           if (use_align)
11712             {
11713               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11714             }
11715           else
11716             {
11717               if (cell_rect.x < vis_rect.x)
11718                 dest_x = cell_rect.x;
11719               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11720                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11721             }
11722         }
11723
11724       if (path)
11725         {
11726           if (use_align)
11727             {
11728               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11729               dest_y = MAX (dest_y, 0);
11730             }
11731           else
11732             {
11733               if (cell_rect.y < vis_rect.y)
11734                 dest_y = cell_rect.y;
11735               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11736                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11737             }
11738         }
11739
11740       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11741     }
11742 }
11743
11744 /**
11745  * gtk_tree_view_row_activated:
11746  * @tree_view: A #GtkTreeView
11747  * @path: The #GtkTreePath to be activated.
11748  * @column: The #GtkTreeViewColumn to be activated.
11749  *
11750  * Activates the cell determined by @path and @column.
11751  **/
11752 void
11753 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11754                              GtkTreePath       *path,
11755                              GtkTreeViewColumn *column)
11756 {
11757   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11758
11759   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11760 }
11761
11762
11763 static void
11764 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11765                                           GtkRBNode *node,
11766                                           gpointer   data)
11767 {
11768   GtkTreeView *tree_view = data;
11769
11770   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11771       node->children)
11772     {
11773       GtkTreePath *path;
11774       GtkTreeIter iter;
11775
11776       path = _gtk_tree_view_find_path (tree_view, tree, node);
11777       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11778
11779       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11780
11781       gtk_tree_path_free (path);
11782     }
11783
11784   if (node->children)
11785     _gtk_rbtree_traverse (node->children,
11786                           node->children->root,
11787                           G_PRE_ORDER,
11788                           gtk_tree_view_expand_all_emission_helper,
11789                           tree_view);
11790 }
11791 /**
11792  * gtk_tree_view_expand_all:
11793  * @tree_view: A #GtkTreeView.
11794  *
11795  * Recursively expands all nodes in the @tree_view.
11796  **/
11797 void
11798 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11799 {
11800   GtkTreePath *path;
11801   GtkRBTree *tree;
11802   GtkRBNode *node;
11803
11804   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11805
11806   if (tree_view->priv->tree == NULL)
11807     return;
11808
11809   path = gtk_tree_path_new_first ();
11810   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11811
11812   while (node)
11813     {
11814       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11815       node = _gtk_rbtree_next (tree, node);
11816       gtk_tree_path_next (path);
11817   }
11818
11819   gtk_tree_path_free (path);
11820 }
11821
11822 /* Timeout to animate the expander during expands and collapses */
11823 static gboolean
11824 expand_collapse_timeout (gpointer data)
11825 {
11826   return do_expand_collapse (data);
11827 }
11828
11829 static gboolean
11830 do_expand_collapse (GtkTreeView *tree_view)
11831 {
11832   GtkRBNode *node;
11833   GtkRBTree *tree;
11834   gboolean expanding;
11835   gboolean redraw;
11836
11837   redraw = FALSE;
11838   expanding = TRUE;
11839
11840   node = tree_view->priv->expanded_collapsed_node;
11841   tree = tree_view->priv->expanded_collapsed_tree;
11842
11843   if (node->children == NULL)
11844     expanding = FALSE;
11845
11846   if (expanding)
11847     {
11848       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11849         {
11850           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11851           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11852
11853           redraw = TRUE;
11854
11855         }
11856       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11857         {
11858           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11859
11860           redraw = TRUE;
11861         }
11862     }
11863   else
11864     {
11865       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11866         {
11867           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11868           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11869
11870           redraw = TRUE;
11871         }
11872       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11873         {
11874           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11875
11876           redraw = TRUE;
11877
11878         }
11879     }
11880
11881   if (redraw)
11882     {
11883       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
11884
11885       return TRUE;
11886     }
11887
11888   return FALSE;
11889 }
11890
11891 /**
11892  * gtk_tree_view_collapse_all:
11893  * @tree_view: A #GtkTreeView.
11894  *
11895  * Recursively collapses all visible, expanded nodes in @tree_view.
11896  **/
11897 void
11898 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11899 {
11900   GtkRBTree *tree;
11901   GtkRBNode *node;
11902   GtkTreePath *path;
11903   gint *indices;
11904
11905   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11906
11907   if (tree_view->priv->tree == NULL)
11908     return;
11909
11910   path = gtk_tree_path_new ();
11911   gtk_tree_path_down (path);
11912   indices = gtk_tree_path_get_indices (path);
11913
11914   tree = tree_view->priv->tree;
11915   node = tree->root;
11916   while (node && node->left != tree->nil)
11917     node = node->left;
11918
11919   while (node)
11920     {
11921       if (node->children)
11922         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
11923       indices[0]++;
11924       node = _gtk_rbtree_next (tree, node);
11925     }
11926
11927   gtk_tree_path_free (path);
11928 }
11929
11930 /**
11931  * gtk_tree_view_expand_to_path:
11932  * @tree_view: A #GtkTreeView.
11933  * @path: path to a row.
11934  *
11935  * Expands the row at @path. This will also expand all parent rows of
11936  * @path as necessary.
11937  *
11938  * Since: 2.2
11939  **/
11940 void
11941 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
11942                               GtkTreePath *path)
11943 {
11944   gint i, depth;
11945   gint *indices;
11946   GtkTreePath *tmp;
11947
11948   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11949   g_return_if_fail (path != NULL);
11950
11951   depth = gtk_tree_path_get_depth (path);
11952   indices = gtk_tree_path_get_indices (path);
11953
11954   tmp = gtk_tree_path_new ();
11955   g_return_if_fail (tmp != NULL);
11956
11957   for (i = 0; i < depth; i++)
11958     {
11959       gtk_tree_path_append_index (tmp, indices[i]);
11960       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
11961     }
11962
11963   gtk_tree_path_free (tmp);
11964 }
11965
11966 /* FIXME the bool return values for expand_row and collapse_row are
11967  * not analagous; they should be TRUE if the row had children and
11968  * was not already in the requested state.
11969  */
11970
11971
11972 static gboolean
11973 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
11974                                GtkTreePath *path,
11975                                GtkRBTree   *tree,
11976                                GtkRBNode   *node,
11977                                gboolean     open_all,
11978                                gboolean     animate)
11979 {
11980   GtkTreeIter iter;
11981   GtkTreeIter temp;
11982   gboolean expand;
11983
11984   if (animate)
11985     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
11986                   "gtk-enable-animations", &animate,
11987                   NULL);
11988
11989   remove_auto_expand_timeout (tree_view);
11990
11991   if (node->children && !open_all)
11992     return FALSE;
11993
11994   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
11995     return FALSE;
11996
11997   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11998   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
11999     return FALSE;
12000
12001
12002    if (node->children && open_all)
12003     {
12004       gboolean retval = FALSE;
12005       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12006
12007       gtk_tree_path_append_index (tmp_path, 0);
12008       tree = node->children;
12009       node = tree->root;
12010       while (node->left != tree->nil)
12011         node = node->left;
12012       /* try to expand the children */
12013       do
12014         {
12015          gboolean t;
12016          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12017                                             TRUE, animate);
12018          if (t)
12019            retval = TRUE;
12020
12021          gtk_tree_path_next (tmp_path);
12022          node = _gtk_rbtree_next (tree, node);
12023        }
12024       while (node != NULL);
12025
12026       gtk_tree_path_free (tmp_path);
12027
12028       return retval;
12029     }
12030
12031   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12032
12033   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12034     return FALSE;
12035
12036   if (expand)
12037     return FALSE;
12038
12039   node->children = _gtk_rbtree_new ();
12040   node->children->parent_tree = tree;
12041   node->children->parent_node = node;
12042
12043   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12044
12045   gtk_tree_view_build_tree (tree_view,
12046                             node->children,
12047                             &temp,
12048                             gtk_tree_path_get_depth (path) + 1,
12049                             open_all);
12050
12051   if (tree_view->priv->expand_collapse_timeout)
12052     {
12053       g_source_remove (tree_view->priv->expand_collapse_timeout);
12054       tree_view->priv->expand_collapse_timeout = 0;
12055     }
12056
12057   if (tree_view->priv->expanded_collapsed_node != NULL)
12058     {
12059       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
12060       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12061
12062       tree_view->priv->expanded_collapsed_node = NULL;
12063     }
12064
12065   if (animate)
12066     {
12067       tree_view->priv->expand_collapse_timeout = gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
12068       tree_view->priv->expanded_collapsed_node = node;
12069       tree_view->priv->expanded_collapsed_tree = tree;
12070
12071       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12072     }
12073
12074   install_presize_handler (tree_view);
12075
12076   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12077   if (open_all && node->children)
12078     {
12079       _gtk_rbtree_traverse (node->children,
12080                             node->children->root,
12081                             G_PRE_ORDER,
12082                             gtk_tree_view_expand_all_emission_helper,
12083                             tree_view);
12084     }
12085   return TRUE;
12086 }
12087
12088
12089 /**
12090  * gtk_tree_view_expand_row:
12091  * @tree_view: a #GtkTreeView
12092  * @path: path to a row
12093  * @open_all: whether to recursively expand, or just expand immediate children
12094  *
12095  * Opens the row so its children are visible.
12096  *
12097  * Return value: %TRUE if the row existed and had children
12098  **/
12099 gboolean
12100 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12101                           GtkTreePath *path,
12102                           gboolean     open_all)
12103 {
12104   GtkRBTree *tree;
12105   GtkRBNode *node;
12106
12107   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12108   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12109   g_return_val_if_fail (path != NULL, FALSE);
12110
12111   if (_gtk_tree_view_find_node (tree_view,
12112                                 path,
12113                                 &tree,
12114                                 &node))
12115     return FALSE;
12116
12117   if (tree != NULL)
12118     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12119   else
12120     return FALSE;
12121 }
12122
12123 static gboolean
12124 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12125                                  GtkTreePath *path,
12126                                  GtkRBTree   *tree,
12127                                  GtkRBNode   *node,
12128                                  gboolean     animate)
12129 {
12130   GtkTreeIter iter;
12131   GtkTreeIter children;
12132   gboolean collapse;
12133   gint x, y;
12134   GList *list;
12135   GdkWindow *child, *parent;
12136
12137   if (animate)
12138     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12139                   "gtk-enable-animations", &animate,
12140                   NULL);
12141
12142   remove_auto_expand_timeout (tree_view);
12143
12144   if (node->children == NULL)
12145     return FALSE;
12146
12147   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12148
12149   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12150
12151   if (collapse)
12152     return FALSE;
12153
12154   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12155    * a chance to prelight the correct node below */
12156
12157   if (tree_view->priv->prelight_tree)
12158     {
12159       GtkRBTree *parent_tree;
12160       GtkRBNode *parent_node;
12161
12162       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12163       parent_node = tree_view->priv->prelight_tree->parent_node;
12164       while (parent_tree)
12165         {
12166           if (parent_tree == tree && parent_node == node)
12167             {
12168               ensure_unprelighted (tree_view);
12169               break;
12170             }
12171           parent_node = parent_tree->parent_node;
12172           parent_tree = parent_tree->parent_tree;
12173         }
12174     }
12175
12176   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12177
12178   for (list = tree_view->priv->columns; list; list = list->next)
12179     {
12180       GtkTreeViewColumn *column = list->data;
12181
12182       if (column->visible == FALSE)
12183         continue;
12184       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12185         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12186     }
12187
12188   if (tree_view->priv->destroy_count_func)
12189     {
12190       GtkTreePath *child_path;
12191       gint child_count = 0;
12192       child_path = gtk_tree_path_copy (path);
12193       gtk_tree_path_down (child_path);
12194       if (node->children)
12195         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12196       (* tree_view->priv->destroy_count_func) (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12197       gtk_tree_path_free (child_path);
12198     }
12199
12200   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12201     {
12202       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12203
12204       if (gtk_tree_path_is_ancestor (path, cursor_path))
12205         {
12206           gtk_tree_row_reference_free (tree_view->priv->cursor);
12207           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12208                                                                       tree_view->priv->model,
12209                                                                       path);
12210         }
12211       gtk_tree_path_free (cursor_path);
12212     }
12213
12214   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12215     {
12216       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12217       if (gtk_tree_path_is_ancestor (path, anchor_path))
12218         {
12219           gtk_tree_row_reference_free (tree_view->priv->anchor);
12220           tree_view->priv->anchor = NULL;
12221         }
12222       gtk_tree_path_free (anchor_path);
12223     }
12224
12225   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press))
12226     {
12227       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
12228       if (gtk_tree_path_is_ancestor (path, lsc))
12229         {
12230           gtk_tree_row_reference_free (tree_view->priv->last_button_press);
12231           tree_view->priv->last_button_press = NULL;
12232         }
12233       gtk_tree_path_free (lsc);
12234     }
12235
12236   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press_2))
12237     {
12238       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press_2);
12239       if (gtk_tree_path_is_ancestor (path, lsc))
12240         {
12241           gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
12242           tree_view->priv->last_button_press_2 = NULL;
12243         }
12244       gtk_tree_path_free (lsc);
12245     }
12246
12247   if (tree_view->priv->expanded_collapsed_node != NULL)
12248     {
12249       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
12250       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12251       
12252       tree_view->priv->expanded_collapsed_node = NULL;
12253     }
12254
12255   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12256     {
12257       _gtk_rbtree_remove (node->children);
12258       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12259     }
12260   else
12261     _gtk_rbtree_remove (node->children);
12262
12263   if (tree_view->priv->expand_collapse_timeout)
12264     {
12265       g_source_remove (tree_view->priv->expand_collapse_timeout);
12266       tree_view->priv->expand_collapse_timeout = 0;
12267     }
12268   
12269   if (animate)
12270     {
12271       tree_view->priv->expand_collapse_timeout = gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
12272       tree_view->priv->expanded_collapsed_node = node;
12273       tree_view->priv->expanded_collapsed_tree = tree;
12274
12275       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12276     }
12277   
12278   if (GTK_WIDGET_MAPPED (tree_view))
12279     {
12280       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12281     }
12282
12283   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12284
12285   if (GTK_WIDGET_MAPPED (tree_view))
12286     {
12287       /* now that we've collapsed all rows, we want to try to set the prelight
12288        * again. To do this, we fake a motion event and send it to ourselves. */
12289
12290       child = tree_view->priv->bin_window;
12291       parent = gdk_window_get_parent (child);
12292
12293       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12294         {
12295           GdkEventMotion event;
12296           gint child_x, child_y;
12297
12298           gdk_window_get_position (child, &child_x, &child_y);
12299
12300           event.window = tree_view->priv->bin_window;
12301           event.x = x - child_x;
12302           event.y = y - child_y;
12303
12304           /* despite the fact this isn't a real event, I'm almost positive it will
12305            * never trigger a drag event.  maybe_drag is the only function that uses
12306            * more than just event.x and event.y. */
12307           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12308         }
12309     }
12310
12311   return TRUE;
12312 }
12313
12314 /**
12315  * gtk_tree_view_collapse_row:
12316  * @tree_view: a #GtkTreeView
12317  * @path: path to a row in the @tree_view
12318  *
12319  * Collapses a row (hides its child rows, if they exist).
12320  *
12321  * Return value: %TRUE if the row was collapsed.
12322  **/
12323 gboolean
12324 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12325                             GtkTreePath *path)
12326 {
12327   GtkRBTree *tree;
12328   GtkRBNode *node;
12329
12330   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12331   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12332   g_return_val_if_fail (path != NULL, FALSE);
12333
12334   if (_gtk_tree_view_find_node (tree_view,
12335                                 path,
12336                                 &tree,
12337                                 &node))
12338     return FALSE;
12339
12340   if (tree == NULL || node->children == NULL)
12341     return FALSE;
12342
12343   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12344 }
12345
12346 static void
12347 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12348                                         GtkRBTree              *tree,
12349                                         GtkTreePath            *path,
12350                                         GtkTreeViewMappingFunc  func,
12351                                         gpointer                user_data)
12352 {
12353   GtkRBNode *node;
12354
12355   if (tree == NULL || tree->root == NULL)
12356     return;
12357
12358   node = tree->root;
12359
12360   while (node && node->left != tree->nil)
12361     node = node->left;
12362
12363   while (node)
12364     {
12365       if (node->children)
12366         {
12367           (* func) (tree_view, path, user_data);
12368           gtk_tree_path_down (path);
12369           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12370           gtk_tree_path_up (path);
12371         }
12372       gtk_tree_path_next (path);
12373       node = _gtk_rbtree_next (tree, node);
12374     }
12375 }
12376
12377 /**
12378  * gtk_tree_view_map_expanded_rows:
12379  * @tree_view: A #GtkTreeView
12380  * @func: A function to be called
12381  * @data: User data to be passed to the function.
12382  *
12383  * Calls @func on all expanded rows.
12384  **/
12385 void
12386 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12387                                  GtkTreeViewMappingFunc  func,
12388                                  gpointer                user_data)
12389 {
12390   GtkTreePath *path;
12391
12392   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12393   g_return_if_fail (func != NULL);
12394
12395   path = gtk_tree_path_new_first ();
12396
12397   gtk_tree_view_map_expanded_rows_helper (tree_view,
12398                                           tree_view->priv->tree,
12399                                           path, func, user_data);
12400
12401   gtk_tree_path_free (path);
12402 }
12403
12404 /**
12405  * gtk_tree_view_row_expanded:
12406  * @tree_view: A #GtkTreeView.
12407  * @path: A #GtkTreePath to test expansion state.
12408  *
12409  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12410  *
12411  * Return value: %TRUE if #path is expanded.
12412  **/
12413 gboolean
12414 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12415                             GtkTreePath *path)
12416 {
12417   GtkRBTree *tree;
12418   GtkRBNode *node;
12419
12420   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12421   g_return_val_if_fail (path != NULL, FALSE);
12422
12423   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12424
12425   if (node == NULL)
12426     return FALSE;
12427
12428   return (node->children != NULL);
12429 }
12430
12431 static const GtkTargetEntry row_targets[] = {
12432   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12433 };
12434
12435
12436 /**
12437  * gtk_tree_view_get_reorderable:
12438  * @tree_view: a #GtkTreeView
12439  *
12440  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12441  * gtk_tree_view_set_reorderable().
12442  *
12443  * Return value: %TRUE if the tree can be reordered.
12444  **/
12445 gboolean
12446 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12447 {
12448   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12449
12450   return tree_view->priv->reorderable;
12451 }
12452
12453 /**
12454  * gtk_tree_view_set_reorderable:
12455  * @tree_view: A #GtkTreeView.
12456  * @reorderable: %TRUE, if the tree can be reordered.
12457  *
12458  * This function is a convenience function to allow you to reorder models that
12459  * support the #GtkDragSourceIface and the #GtkDragDestIface.  Both
12460  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
12461  * the user can reorder the model by dragging and dropping rows.  The
12462  * developer can listen to these changes by connecting to the model's
12463  * row_inserted and row_deleted signals.
12464  *
12465  * This function does not give you any degree of control over the order -- any
12466  * reordering is allowed.  If more control is needed, you should probably
12467  * handle drag and drop manually.
12468  **/
12469 void
12470 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12471                                gboolean     reorderable)
12472 {
12473   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12474
12475   reorderable = reorderable != FALSE;
12476
12477   if (tree_view->priv->reorderable == reorderable)
12478     return;
12479
12480   if (reorderable)
12481     {
12482       gtk_tree_view_enable_model_drag_source (tree_view,
12483                                               GDK_BUTTON1_MASK,
12484                                               row_targets,
12485                                               G_N_ELEMENTS (row_targets),
12486                                               GDK_ACTION_MOVE);
12487       gtk_tree_view_enable_model_drag_dest (tree_view,
12488                                             row_targets,
12489                                             G_N_ELEMENTS (row_targets),
12490                                             GDK_ACTION_MOVE);
12491     }
12492   else
12493     {
12494       gtk_tree_view_unset_rows_drag_source (tree_view);
12495       gtk_tree_view_unset_rows_drag_dest (tree_view);
12496     }
12497
12498   tree_view->priv->reorderable = reorderable;
12499
12500   g_object_notify (G_OBJECT (tree_view), "reorderable");
12501 }
12502
12503 static void
12504 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12505                                GtkTreePath     *path,
12506                                gboolean         clear_and_select,
12507                                gboolean         clamp_node)
12508 {
12509   GtkRBTree *tree = NULL;
12510   GtkRBNode *node = NULL;
12511
12512   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12513     {
12514       GtkTreePath *cursor_path;
12515       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12516       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12517       gtk_tree_path_free (cursor_path);
12518     }
12519
12520   gtk_tree_row_reference_free (tree_view->priv->cursor);
12521   tree_view->priv->cursor = NULL;
12522
12523   /* One cannot set the cursor on a separator. */
12524   if (!row_is_separator (tree_view, NULL, path))
12525     {
12526       tree_view->priv->cursor =
12527         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12528                                           tree_view->priv->model,
12529                                           path);
12530       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12531     }
12532
12533   if (tree != NULL)
12534     {
12535       GtkRBTree *new_tree = NULL;
12536       GtkRBNode *new_node = NULL;
12537
12538       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12539         {
12540           GtkTreeSelectMode mode = 0;
12541
12542           if (tree_view->priv->ctrl_pressed)
12543             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12544           if (tree_view->priv->shift_pressed)
12545             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12546
12547           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12548                                                     node, tree, path, mode,
12549                                                     FALSE);
12550         }
12551
12552       /* We have to re-find tree and node here again, somebody might have
12553        * cleared the node or the whole tree in the GtkTreeSelection::changed
12554        * callback. If the nodes differ we bail out here.
12555        */
12556       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12557
12558       if (tree != new_tree || node != new_node)
12559         return;
12560
12561       if (clamp_node)
12562         {
12563           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12564           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12565         }
12566     }
12567
12568   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12569 }
12570
12571 /**
12572  * gtk_tree_view_get_cursor:
12573  * @tree_view: A #GtkTreeView
12574  * @path: A pointer to be filled with the current cursor path, or %NULL
12575  * @focus_column: A pointer to be filled with the current focus column, or %NULL
12576  *
12577  * Fills in @path and @focus_column with the current path and focus column.  If
12578  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12579  * currently has focus, then *@focus_column will be %NULL.
12580  *
12581  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12582  * you are done with it.
12583  **/
12584 void
12585 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12586                           GtkTreePath       **path,
12587                           GtkTreeViewColumn **focus_column)
12588 {
12589   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12590
12591   if (path)
12592     {
12593       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12594         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12595       else
12596         *path = NULL;
12597     }
12598
12599   if (focus_column)
12600     {
12601       *focus_column = tree_view->priv->focus_column;
12602     }
12603 }
12604
12605 /**
12606  * gtk_tree_view_set_cursor:
12607  * @tree_view: A #GtkTreeView
12608  * @path: A #GtkTreePath
12609  * @focus_column: A #GtkTreeViewColumn, or %NULL
12610  * @start_editing: %TRUE if the specified cell should start being edited.
12611  *
12612  * Sets the current keyboard focus to be at @path, and selects it.  This is
12613  * useful when you want to focus the user's attention on a particular row.  If
12614  * @focus_column is not %NULL, then focus is given to the column specified by 
12615  * it. Additionally, if @focus_column is specified, and @start_editing is 
12616  * %TRUE, then editing should be started in the specified cell.  
12617  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12618  * in order to give keyboard focus to the widget.  Please note that editing 
12619  * can only happen when the widget is realized.
12620  **/
12621 void
12622 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12623                           GtkTreePath       *path,
12624                           GtkTreeViewColumn *focus_column,
12625                           gboolean           start_editing)
12626 {
12627   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12628                                     NULL, start_editing);
12629 }
12630
12631 /**
12632  * gtk_tree_view_set_cursor_on_cell:
12633  * @tree_view: A #GtkTreeView
12634  * @path: A #GtkTreePath
12635  * @focus_column: A #GtkTreeViewColumn, or %NULL
12636  * @focus_cell: A #GtkCellRenderer, or %NULL
12637  * @start_editing: %TRUE if the specified cell should start being edited.
12638  *
12639  * Sets the current keyboard focus to be at @path, and selects it.  This is
12640  * useful when you want to focus the user's attention on a particular row.  If
12641  * @focus_column is not %NULL, then focus is given to the column specified by
12642  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12643  * contains 2 or more editable or activatable cells, then focus is given to
12644  * the cell specified by @focus_cell. Additionally, if @focus_column is
12645  * specified, and @start_editing is %TRUE, then editing should be started in
12646  * the specified cell.  This function is often followed by
12647  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12648  * widget.  Please note that editing can only happen when the widget is
12649  * realized.
12650  *
12651  * Since: 2.2
12652  **/
12653 void
12654 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12655                                   GtkTreePath       *path,
12656                                   GtkTreeViewColumn *focus_column,
12657                                   GtkCellRenderer   *focus_cell,
12658                                   gboolean           start_editing)
12659 {
12660   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12661   g_return_if_fail (path != NULL);
12662   if (focus_column)
12663     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (focus_column));
12664   if (focus_cell)
12665     {
12666       g_return_if_fail (focus_column);
12667       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12668     }
12669
12670   /* cancel the current editing, if it exists */
12671   if (tree_view->priv->edited_column &&
12672       tree_view->priv->edited_column->editable_widget)
12673     gtk_tree_view_stop_editing (tree_view, TRUE);
12674
12675   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12676
12677   if (focus_column && focus_column->visible)
12678     {
12679       GList *list;
12680       gboolean column_in_tree = FALSE;
12681
12682       for (list = tree_view->priv->columns; list; list = list->next)
12683         if (list->data == focus_column)
12684           {
12685             column_in_tree = TRUE;
12686             break;
12687           }
12688       g_return_if_fail (column_in_tree);
12689       tree_view->priv->focus_column = focus_column;
12690       if (focus_cell)
12691         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12692       if (start_editing)
12693         gtk_tree_view_start_editing (tree_view, path);
12694     }
12695 }
12696
12697 /**
12698  * gtk_tree_view_get_bin_window:
12699  * @tree_view: A #GtkTreeView
12700  * 
12701  * Returns the window that @tree_view renders to.  This is used primarily to
12702  * compare to <literal>event->window</literal> to confirm that the event on
12703  * @tree_view is on the right window.
12704  * 
12705  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12706  **/
12707 GdkWindow *
12708 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12709 {
12710   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12711
12712   return tree_view->priv->bin_window;
12713 }
12714
12715 /**
12716  * gtk_tree_view_get_path_at_pos:
12717  * @tree_view: A #GtkTreeView.
12718  * @x: The x position to be identified (relative to bin_window).
12719  * @y: The y position to be identified (relative to bin_window).
12720  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12721  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12722  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
12723  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12724  *
12725  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12726  * (please see gtk_tree_view_get_bin_window()).
12727  * That is, @x and @y are relative to an events coordinates. @x and @y must
12728  * come from an event on the @tree_view only where <literal>event->window ==
12729  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12730  * things like popup menus. If @path is non-%NULL, then it will be filled
12731  * with the #GtkTreePath at that point.  This path should be freed with
12732  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12733  * with the column at that point.  @cell_x and @cell_y return the coordinates
12734  * relative to the cell background (i.e. the @background_area passed to
12735  * gtk_cell_renderer_render()).  This function is only meaningful if
12736  * @tree_view is realized.
12737  *
12738  * For converting widget coordinates (eg. the ones you get from
12739  * GtkWidget::query-tooltip), please see
12740  * gtk_tree_view_convert_widget_to_bin_window_coords().
12741  *
12742  * Return value: %TRUE if a row exists at that coordinate.
12743  **/
12744 gboolean
12745 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12746                                gint                x,
12747                                gint                y,
12748                                GtkTreePath       **path,
12749                                GtkTreeViewColumn **column,
12750                                gint               *cell_x,
12751                                gint               *cell_y)
12752 {
12753   GtkRBTree *tree;
12754   GtkRBNode *node;
12755   gint y_offset;
12756
12757   g_return_val_if_fail (tree_view != NULL, FALSE);
12758   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
12759
12760   if (path)
12761     *path = NULL;
12762   if (column)
12763     *column = NULL;
12764
12765   if (tree_view->priv->tree == NULL)
12766     return FALSE;
12767
12768   if (x > tree_view->priv->hadjustment->upper)
12769     return FALSE;
12770
12771   if (x < 0 || y < 0)
12772     return FALSE;
12773
12774   if (column || cell_x)
12775     {
12776       GtkTreeViewColumn *tmp_column;
12777       GtkTreeViewColumn *last_column = NULL;
12778       GList *list;
12779       gint remaining_x = x;
12780       gboolean found = FALSE;
12781       gboolean rtl;
12782
12783       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12784       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12785            list;
12786            list = (rtl ? list->prev : list->next))
12787         {
12788           tmp_column = list->data;
12789
12790           if (tmp_column->visible == FALSE)
12791             continue;
12792
12793           last_column = tmp_column;
12794           if (remaining_x <= tmp_column->width)
12795             {
12796               found = TRUE;
12797
12798               if (column)
12799                 *column = tmp_column;
12800
12801               if (cell_x)
12802                 *cell_x = remaining_x;
12803
12804               break;
12805             }
12806           remaining_x -= tmp_column->width;
12807         }
12808
12809       /* If found is FALSE and there is a last_column, then it the remainder
12810        * space is in that area
12811        */
12812       if (!found)
12813         {
12814           if (last_column)
12815             {
12816               if (column)
12817                 *column = last_column;
12818               
12819               if (cell_x)
12820                 *cell_x = last_column->width + remaining_x;
12821             }
12822           else
12823             {
12824               return FALSE;
12825             }
12826         }
12827     }
12828
12829   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12830                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12831                                       &tree, &node);
12832
12833   if (tree == NULL)
12834     return FALSE;
12835
12836   if (cell_y)
12837     *cell_y = y_offset;
12838
12839   if (path)
12840     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12841
12842   return TRUE;
12843 }
12844
12845
12846 /**
12847  * gtk_tree_view_get_cell_area:
12848  * @tree_view: a #GtkTreeView
12849  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12850  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12851  * @rect: rectangle to fill with cell rect
12852  *
12853  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12854  * row specified by @path and the column specified by @column.  If @path is
12855  * %NULL, or points to a path not currently displayed, the @y and @height fields
12856  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12857  * fields will be filled with 0.  The sum of all cell rects does not cover the
12858  * entire tree; there are extra pixels in between rows, for example. The
12859  * returned rectangle is equivalent to the @cell_area passed to
12860  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12861  * realized.
12862  **/
12863 void
12864 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12865                              GtkTreePath        *path,
12866                              GtkTreeViewColumn  *column,
12867                              GdkRectangle       *rect)
12868 {
12869   GtkRBTree *tree = NULL;
12870   GtkRBNode *node = NULL;
12871   gint vertical_separator;
12872   gint horizontal_separator;
12873
12874   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12875   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12876   g_return_if_fail (rect != NULL);
12877   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12878   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
12879
12880   gtk_widget_style_get (GTK_WIDGET (tree_view),
12881                         "vertical-separator", &vertical_separator,
12882                         "horizontal-separator", &horizontal_separator,
12883                         NULL);
12884
12885   rect->x = 0;
12886   rect->y = 0;
12887   rect->width = 0;
12888   rect->height = 0;
12889
12890   if (column)
12891     {
12892       rect->x = column->button->allocation.x + horizontal_separator/2;
12893       rect->width = column->button->allocation.width - horizontal_separator;
12894     }
12895
12896   if (path)
12897     {
12898       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12899
12900       /* Get vertical coords */
12901       if ((!ret && tree == NULL) || ret)
12902         return;
12903
12904       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12905       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12906
12907       if (column &&
12908           gtk_tree_view_is_expander_column (tree_view, column))
12909         {
12910           gint depth = gtk_tree_path_get_depth (path);
12911           gboolean rtl;
12912
12913           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12914
12915           if (!rtl)
12916             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12917           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12918
12919           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12920             {
12921               if (!rtl)
12922                 rect->x += depth * tree_view->priv->expander_size;
12923               rect->width -= depth * tree_view->priv->expander_size;
12924             }
12925
12926           rect->width = MAX (rect->width, 0);
12927         }
12928     }
12929 }
12930
12931 /**
12932  * gtk_tree_view_get_background_area:
12933  * @tree_view: a #GtkTreeView
12934  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12935  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
12936  * @rect: rectangle to fill with cell background rect
12937  *
12938  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12939  * row specified by @path and the column specified by @column.  If @path is
12940  * %NULL, or points to a node not found in the tree, the @y and @height fields of
12941  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12942  * fields will be filled with 0.  The returned rectangle is equivalent to the
12943  * @background_area passed to gtk_cell_renderer_render().  These background
12944  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
12945  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
12946  * itself, excluding surrounding borders and the tree expander area.
12947  *
12948  **/
12949 void
12950 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
12951                                    GtkTreePath        *path,
12952                                    GtkTreeViewColumn  *column,
12953                                    GdkRectangle       *rect)
12954 {
12955   GtkRBTree *tree = NULL;
12956   GtkRBNode *node = NULL;
12957
12958   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12959   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12960   g_return_if_fail (rect != NULL);
12961
12962   rect->x = 0;
12963   rect->y = 0;
12964   rect->width = 0;
12965   rect->height = 0;
12966
12967   if (path)
12968     {
12969       /* Get vertical coords */
12970
12971       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
12972           tree == NULL)
12973         return;
12974
12975       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
12976
12977       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
12978     }
12979
12980   if (column)
12981     {
12982       gint x2 = 0;
12983
12984       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
12985       rect->width = x2 - rect->x;
12986     }
12987 }
12988
12989 /**
12990  * gtk_tree_view_get_visible_rect:
12991  * @tree_view: a #GtkTreeView
12992  * @visible_rect: rectangle to fill
12993  *
12994  * Fills @visible_rect with the currently-visible region of the
12995  * buffer, in tree coordinates. Convert to bin_window coordinates with
12996  * gtk_tree_view_convert_tree_to_bin_window_coords().
12997  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
12998  * scrollable area of the tree.
12999  **/
13000 void
13001 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13002                                 GdkRectangle *visible_rect)
13003 {
13004   GtkWidget *widget;
13005
13006   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13007
13008   widget = GTK_WIDGET (tree_view);
13009
13010   if (visible_rect)
13011     {
13012       visible_rect->x = tree_view->priv->hadjustment->value;
13013       visible_rect->y = tree_view->priv->vadjustment->value;
13014       visible_rect->width = widget->allocation.width;
13015       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13016     }
13017 }
13018
13019 /**
13020  * gtk_tree_view_widget_to_tree_coords:
13021  * @tree_view: a #GtkTreeView
13022  * @wx: X coordinate relative to bin_window
13023  * @wy: Y coordinate relative to bin_window
13024  * @tx: return location for tree X coordinate
13025  * @ty: return location for tree Y coordinate
13026  *
13027  * Converts bin_window coordinates to coordinates for the
13028  * tree (the full scrollable area of the tree).
13029  *
13030  * Deprecated: 2.12: Due to historial reasons the name of this function is
13031  * incorrect.  For converting coordinates relative to the widget to
13032  * bin_window coordinates, please see
13033  * gtk_tree_view_convert_widget_to_bin_window_coords().
13034  *
13035  **/
13036 void
13037 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
13038                                       gint         wx,
13039                                       gint         wy,
13040                                       gint        *tx,
13041                                       gint        *ty)
13042 {
13043   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13044
13045   if (tx)
13046     *tx = wx + tree_view->priv->hadjustment->value;
13047   if (ty)
13048     *ty = wy + tree_view->priv->dy;
13049 }
13050
13051 /**
13052  * gtk_tree_view_tree_to_widget_coords:
13053  * @tree_view: a #GtkTreeView
13054  * @tx: tree X coordinate
13055  * @ty: tree Y coordinate
13056  * @wx: return location for X coordinate relative to bin_window
13057  * @wy: return location for Y coordinate relative to bin_window
13058  *
13059  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13060  * to bin_window coordinates.
13061  *
13062  * Deprecated: 2.12: Due to historial reasons the name of this function is
13063  * incorrect.  For converting bin_window coordinates to coordinates relative
13064  * to bin_window, please see
13065  * gtk_tree_view_convert_bin_window_to_widget_coords().
13066  *
13067  **/
13068 void
13069 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
13070                                      gint         tx,
13071                                      gint         ty,
13072                                      gint        *wx,
13073                                      gint        *wy)
13074 {
13075   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13076
13077   if (wx)
13078     *wx = tx - tree_view->priv->hadjustment->value;
13079   if (wy)
13080     *wy = ty - tree_view->priv->dy;
13081 }
13082
13083
13084 /**
13085  * gtk_tree_view_convert_widget_to_tree_coords:
13086  * @tree_view: a #GtkTreeView
13087  * @wx: X coordinate relative to the widget
13088  * @wy: Y coordinate relative to the widget
13089  * @tx: return location for tree X coordinate
13090  * @ty: return location for tree Y coordinate
13091  *
13092  * Converts widget coordinates to coordinates for the
13093  * tree (the full scrollable area of the tree).
13094  *
13095  * Since: 2.12
13096  **/
13097 void
13098 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13099                                              gint         wx,
13100                                              gint         wy,
13101                                              gint        *tx,
13102                                              gint        *ty)
13103 {
13104   gint x, y;
13105
13106   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13107
13108   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13109                                                      wx, wy,
13110                                                      &x, &y);
13111   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13112                                                    x, y,
13113                                                    tx, ty);
13114 }
13115
13116 /**
13117  * gtk_tree_view_convert_tree_to_widget_coords:
13118  * @tree_view: a #GtkTreeView
13119  * @tx: X coordinate relative to the tree
13120  * @ty: Y coordinate relative to the tree
13121  * @wx: return location for widget X coordinate
13122  * @wy: return location for widget Y coordinate
13123  *
13124  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13125  * to widget coordinates.
13126  *
13127  * Since: 2.12
13128  **/
13129 void
13130 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13131                                              gint         tx,
13132                                              gint         ty,
13133                                              gint        *wx,
13134                                              gint        *wy)
13135 {
13136   gint x, y;
13137
13138   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13139
13140   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13141                                                    tx, ty,
13142                                                    &x, &y);
13143   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13144                                                      x, y,
13145                                                      wx, wy);
13146 }
13147
13148 /**
13149  * gtk_tree_view_convert_widget_to_bin_window_coords:
13150  * @tree_view: a #GtkTreeView
13151  * @wx: X coordinate relative to the widget
13152  * @wy: Y coordinate relative to the widget
13153  * @bx: return location for bin_window X coordinate
13154  * @by: return location for bin_window Y coordinate
13155  *
13156  * Converts widget coordinates to coordinates for the bin_window
13157  * (see gtk_tree_view_get_bin_window()).
13158  *
13159  * Since: 2.12
13160  **/
13161 void
13162 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13163                                                    gint         wx,
13164                                                    gint         wy,
13165                                                    gint        *bx,
13166                                                    gint        *by)
13167 {
13168   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13169
13170   if (bx)
13171     *bx = wx + tree_view->priv->hadjustment->value;
13172   if (by)
13173     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13174 }
13175
13176 /**
13177  * gtk_tree_view_convert_bin_window_to_widget_coords:
13178  * @tree_view: a #GtkTreeView
13179  * @bx: bin_window X coordinate
13180  * @by: bin_window Y coordinate
13181  * @wx: return location for widget X coordinate
13182  * @wy: return location for widget Y coordinate
13183  *
13184  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13185  * to widget relative coordinates.
13186  *
13187  * Since: 2.12
13188  **/
13189 void
13190 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13191                                                    gint         bx,
13192                                                    gint         by,
13193                                                    gint        *wx,
13194                                                    gint        *wy)
13195 {
13196   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13197
13198   if (wx)
13199     *wx = bx - tree_view->priv->hadjustment->value;
13200   if (wy)
13201     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13202 }
13203
13204 /**
13205  * gtk_tree_view_convert_tree_to_bin_window_coords:
13206  * @tree_view: a #GtkTreeView
13207  * @tx: tree X coordinate
13208  * @ty: tree Y coordinate
13209  * @bx: return location for X coordinate relative to bin_window
13210  * @by: return location for Y coordinate relative to bin_window
13211  *
13212  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13213  * to bin_window coordinates.
13214  *
13215  * Since: 2.12
13216  **/
13217 void
13218 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13219                                                  gint         tx,
13220                                                  gint         ty,
13221                                                  gint        *bx,
13222                                                  gint        *by)
13223 {
13224   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13225
13226   if (bx)
13227     *bx = tx;
13228   if (by)
13229     *by = ty - tree_view->priv->dy;
13230 }
13231
13232 /**
13233  * gtk_tree_view_convert_bin_window_to_tree_coords:
13234  * @tree_view: a #GtkTreeView
13235  * @bx: X coordinate relative to bin_window
13236  * @by: Y coordinate relative to bin_window
13237  * @tx: return location for tree X coordinate
13238  * @ty: return location for tree Y coordinate
13239  *
13240  * Converts bin_window coordinates to coordinates for the
13241  * tree (the full scrollable area of the tree).
13242  *
13243  * Since: 2.12
13244  **/
13245 void
13246 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13247                                                  gint         bx,
13248                                                  gint         by,
13249                                                  gint        *tx,
13250                                                  gint        *ty)
13251 {
13252   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13253
13254   if (tx)
13255     *tx = bx;
13256   if (ty)
13257     *ty = by + tree_view->priv->dy;
13258 }
13259
13260
13261
13262 /**
13263  * gtk_tree_view_get_visible_range:
13264  * @tree_view: A #GtkTreeView
13265  * @start_path: Return location for start of region, or %NULL.
13266  * @end_path: Return location for end of region, or %NULL.
13267  *
13268  * Sets @start_path and @end_path to be the first and last visible path.
13269  * Note that there may be invisible paths in between.
13270  *
13271  * The paths should be freed with gtk_tree_path_free() after use.
13272  *
13273  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13274  *
13275  * Since: 2.8
13276  **/
13277 gboolean
13278 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13279                                  GtkTreePath **start_path,
13280                                  GtkTreePath **end_path)
13281 {
13282   GtkRBTree *tree;
13283   GtkRBNode *node;
13284
13285   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13286
13287   if (!tree_view->priv->tree)
13288     return FALSE;
13289
13290   if (start_path)
13291     {
13292       _gtk_rbtree_find_offset (tree_view->priv->tree,
13293                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13294                                &tree, &node);
13295       *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13296     }
13297
13298   if (end_path)
13299     {
13300       gint y;
13301
13302       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13303         y = tree_view->priv->height - 1;
13304       else
13305         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13306
13307       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13308       *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13309     }
13310
13311   return TRUE;
13312 }
13313
13314 static void
13315 unset_reorderable (GtkTreeView *tree_view)
13316 {
13317   if (tree_view->priv->reorderable)
13318     {
13319       tree_view->priv->reorderable = FALSE;
13320       g_object_notify (G_OBJECT (tree_view), "reorderable");
13321     }
13322 }
13323
13324 /**
13325  * gtk_tree_view_enable_model_drag_source:
13326  * @tree_view: a #GtkTreeView
13327  * @start_button_mask: Mask of allowed buttons to start drag
13328  * @targets: the table of targets that the drag will support
13329  * @n_targets: the number of items in @targets
13330  * @actions: the bitmask of possible actions for a drag from this
13331  *    widget
13332  * 
13333  * Turns @tree_view into a drag source for automatic DND.
13334  **/
13335 void
13336 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13337                                         GdkModifierType           start_button_mask,
13338                                         const GtkTargetEntry     *targets,
13339                                         gint                      n_targets,
13340                                         GdkDragAction             actions)
13341 {
13342   TreeViewDragInfo *di;
13343
13344   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13345
13346   gtk_drag_source_set (GTK_WIDGET (tree_view),
13347                        0,
13348                        targets,
13349                        n_targets,
13350                        actions);
13351
13352   di = ensure_info (tree_view);
13353   clear_source_info (di);
13354
13355   di->start_button_mask = start_button_mask;
13356   di->source_target_list = gtk_target_list_new (targets, n_targets);
13357   di->source_actions = actions;
13358
13359   di->source_set = TRUE;
13360
13361   unset_reorderable (tree_view);
13362 }
13363
13364 /**
13365  * gtk_tree_view_enable_model_drag_dest:
13366  * @tree_view: a #GtkTreeView
13367  * @targets: the table of targets that the drag will support
13368  * @n_targets: the number of items in @targets
13369  * @actions: the bitmask of possible actions for a drag from this
13370  *    widget
13371  * 
13372  * Turns @tree_view into a drop destination for automatic DND.
13373  **/
13374 void
13375 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13376                                       const GtkTargetEntry     *targets,
13377                                       gint                      n_targets,
13378                                       GdkDragAction             actions)
13379 {
13380   TreeViewDragInfo *di;
13381
13382   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13383
13384   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13385                      0,
13386                      targets,
13387                      n_targets,
13388                      actions);
13389
13390   di = ensure_info (tree_view);
13391   clear_dest_info (di);
13392
13393   if (targets)
13394     di->dest_target_list = gtk_target_list_new (targets, n_targets);
13395
13396   di->dest_set = TRUE;
13397
13398   unset_reorderable (tree_view);
13399 }
13400
13401 /**
13402  * gtk_tree_view_unset_rows_drag_source:
13403  * @tree_view: a #GtkTreeView
13404  * 
13405  * Undoes the effect of gtk_tree_view_enable_model_drag_source().
13406  **/
13407 void
13408 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13409 {
13410   TreeViewDragInfo *di;
13411
13412   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13413
13414   di = get_info (tree_view);
13415
13416   if (di)
13417     {
13418       if (di->source_set)
13419         {
13420           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13421           clear_source_info (di);
13422           di->source_set = FALSE;
13423         }
13424
13425       if (!di->dest_set && !di->source_set)
13426         remove_info (tree_view);
13427     }
13428   
13429   unset_reorderable (tree_view);
13430 }
13431
13432 /**
13433  * gtk_tree_view_unset_rows_drag_dest:
13434  * @tree_view: a #GtkTreeView
13435  * 
13436  * Undoes the effect of gtk_tree_view_enable_model_drag_dest().
13437  **/
13438 void
13439 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13440 {
13441   TreeViewDragInfo *di;
13442
13443   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13444
13445   di = get_info (tree_view);
13446
13447   if (di)
13448     {
13449       if (di->dest_set)
13450         {
13451           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13452           clear_dest_info (di);
13453           di->dest_set = FALSE;
13454         }
13455
13456       if (!di->dest_set && !di->source_set)
13457         remove_info (tree_view);
13458     }
13459
13460   unset_reorderable (tree_view);
13461 }
13462
13463 /**
13464  * gtk_tree_view_set_drag_dest_row:
13465  * @tree_view: a #GtkTreeView
13466  * @path: The path of the row to highlight, or %NULL.
13467  * @pos: Specifies whether to drop before, after or into the row
13468  * 
13469  * Sets the row that is highlighted for feedback.
13470  **/
13471 void
13472 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13473                                  GtkTreePath            *path,
13474                                  GtkTreeViewDropPosition pos)
13475 {
13476   GtkTreePath *current_dest;
13477
13478   /* Note; this function is exported to allow a custom DND
13479    * implementation, so it can't touch TreeViewDragInfo
13480    */
13481
13482   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13483
13484   current_dest = NULL;
13485
13486   if (tree_view->priv->drag_dest_row)
13487     {
13488       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13489       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13490     }
13491
13492   /* special case a drop on an empty model */
13493   tree_view->priv->empty_view_drop = 0;
13494
13495   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13496       && gtk_tree_path_get_depth (path) == 1
13497       && gtk_tree_path_get_indices (path)[0] == 0)
13498     {
13499       gint n_children;
13500
13501       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13502                                                    NULL);
13503
13504       if (!n_children)
13505         tree_view->priv->empty_view_drop = 1;
13506     }
13507
13508   tree_view->priv->drag_dest_pos = pos;
13509
13510   if (path)
13511     {
13512       tree_view->priv->drag_dest_row =
13513         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13514       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13515     }
13516   else
13517     tree_view->priv->drag_dest_row = NULL;
13518
13519   if (current_dest)
13520     {
13521       GtkRBTree *tree, *new_tree;
13522       GtkRBNode *node, *new_node;
13523
13524       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13525       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13526
13527       if (tree && node)
13528         {
13529           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13530           if (new_tree && new_node)
13531             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13532
13533           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13534           if (new_tree && new_node)
13535             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13536         }
13537       gtk_tree_path_free (current_dest);
13538     }
13539 }
13540
13541 /**
13542  * gtk_tree_view_get_drag_dest_row:
13543  * @tree_view: a #GtkTreeView
13544  * @path: Return location for the path of the highlighted row, or %NULL.
13545  * @pos: Return location for the drop position, or %NULL
13546  * 
13547  * Gets information about the row that is highlighted for feedback.
13548  **/
13549 void
13550 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13551                                  GtkTreePath             **path,
13552                                  GtkTreeViewDropPosition  *pos)
13553 {
13554   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13555
13556   if (path)
13557     {
13558       if (tree_view->priv->drag_dest_row)
13559         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13560       else
13561         {
13562           if (tree_view->priv->empty_view_drop)
13563             *path = gtk_tree_path_new_from_indices (0, -1);
13564           else
13565             *path = NULL;
13566         }
13567     }
13568
13569   if (pos)
13570     *pos = tree_view->priv->drag_dest_pos;
13571 }
13572
13573 /**
13574  * gtk_tree_view_get_dest_row_at_pos:
13575  * @tree_view: a #GtkTreeView
13576  * @drag_x: the position to determine the destination row for
13577  * @drag_y: the position to determine the destination row for
13578  * @path: Return location for the path of the highlighted row, or %NULL.
13579  * @pos: Return location for the drop position, or %NULL
13580  * 
13581  * Determines the destination row for a given position.  @drag_x and
13582  * @drag_y are expected to be in widget coordinates.
13583  * 
13584  * Return value: whether there is a row at the given position.
13585  **/
13586 gboolean
13587 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13588                                    gint                     drag_x,
13589                                    gint                     drag_y,
13590                                    GtkTreePath            **path,
13591                                    GtkTreeViewDropPosition *pos)
13592 {
13593   gint cell_y;
13594   gint bin_x, bin_y;
13595   gdouble offset_into_row;
13596   gdouble third;
13597   GdkRectangle cell;
13598   GtkTreeViewColumn *column = NULL;
13599   GtkTreePath *tmp_path = NULL;
13600
13601   /* Note; this function is exported to allow a custom DND
13602    * implementation, so it can't touch TreeViewDragInfo
13603    */
13604
13605   g_return_val_if_fail (tree_view != NULL, FALSE);
13606   g_return_val_if_fail (drag_x >= 0, FALSE);
13607   g_return_val_if_fail (drag_y >= 0, FALSE);
13608   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
13609
13610
13611   if (path)
13612     *path = NULL;
13613
13614   if (tree_view->priv->tree == NULL)
13615     return FALSE;
13616
13617   /* If in the top third of a row, we drop before that row; if
13618    * in the bottom third, drop after that row; if in the middle,
13619    * and the row has children, drop into the row.
13620    */
13621   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13622                                                      &bin_x, &bin_y);
13623
13624   if (!gtk_tree_view_get_path_at_pos (tree_view,
13625                                       bin_x,
13626                                       bin_y,
13627                                       &tmp_path,
13628                                       &column,
13629                                       NULL,
13630                                       &cell_y))
13631     return FALSE;
13632
13633   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13634                                      &cell);
13635
13636   offset_into_row = cell_y;
13637
13638   if (path)
13639     *path = tmp_path;
13640   else
13641     gtk_tree_path_free (tmp_path);
13642
13643   tmp_path = NULL;
13644
13645   third = cell.height / 3.0;
13646
13647   if (pos)
13648     {
13649       if (offset_into_row < third)
13650         {
13651           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13652         }
13653       else if (offset_into_row < (cell.height / 2.0))
13654         {
13655           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13656         }
13657       else if (offset_into_row < third * 2.0)
13658         {
13659           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13660         }
13661       else
13662         {
13663           *pos = GTK_TREE_VIEW_DROP_AFTER;
13664         }
13665     }
13666
13667   return TRUE;
13668 }
13669
13670
13671
13672 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13673 /**
13674  * gtk_tree_view_create_row_drag_icon:
13675  * @tree_view: a #GtkTreeView
13676  * @path: a #GtkTreePath in @tree_view
13677  *
13678  * Creates a #GdkPixmap representation of the row at @path.  
13679  * This image is used for a drag icon.
13680  *
13681  * Return value: a newly-allocated pixmap of the drag icon.
13682  **/
13683 GdkPixmap *
13684 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13685                                     GtkTreePath  *path)
13686 {
13687   GtkTreeIter   iter;
13688   GtkRBTree    *tree;
13689   GtkRBNode    *node;
13690   gint cell_offset;
13691   GList *list;
13692   GdkRectangle background_area;
13693   GdkRectangle expose_area;
13694   GtkWidget *widget;
13695   gint depth;
13696   /* start drawing inside the black outline */
13697   gint x = 1, y = 1;
13698   GdkDrawable *drawable;
13699   gint bin_window_width;
13700   gboolean is_separator = FALSE;
13701   gboolean rtl;
13702
13703   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13704   g_return_val_if_fail (path != NULL, NULL);
13705
13706   widget = GTK_WIDGET (tree_view);
13707
13708   if (!GTK_WIDGET_REALIZED (tree_view))
13709     return NULL;
13710
13711   depth = gtk_tree_path_get_depth (path);
13712
13713   _gtk_tree_view_find_node (tree_view,
13714                             path,
13715                             &tree,
13716                             &node);
13717
13718   if (tree == NULL)
13719     return NULL;
13720
13721   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13722                                 &iter,
13723                                 path))
13724     return NULL;
13725   
13726   is_separator = row_is_separator (tree_view, &iter, NULL);
13727
13728   cell_offset = x;
13729
13730   background_area.y = y;
13731   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13732
13733   gdk_drawable_get_size (tree_view->priv->bin_window,
13734                          &bin_window_width, NULL);
13735
13736   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13737                              bin_window_width + 2,
13738                              background_area.height + 2,
13739                              -1);
13740
13741   expose_area.x = 0;
13742   expose_area.y = 0;
13743   expose_area.width = bin_window_width + 2;
13744   expose_area.height = background_area.height + 2;
13745
13746   gdk_draw_rectangle (drawable,
13747                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
13748                       TRUE,
13749                       0, 0,
13750                       bin_window_width + 2,
13751                       background_area.height + 2);
13752
13753   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13754
13755   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13756       list;
13757       list = (rtl ? list->prev : list->next))
13758     {
13759       GtkTreeViewColumn *column = list->data;
13760       GdkRectangle cell_area;
13761       gint vertical_separator;
13762
13763       if (!column->visible)
13764         continue;
13765
13766       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13767                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13768                                                node->children?TRUE:FALSE);
13769
13770       background_area.x = cell_offset;
13771       background_area.width = column->width;
13772
13773       gtk_widget_style_get (widget,
13774                             "vertical-separator", &vertical_separator,
13775                             NULL);
13776
13777       cell_area = background_area;
13778
13779       cell_area.y += vertical_separator / 2;
13780       cell_area.height -= vertical_separator;
13781
13782       if (gtk_tree_view_is_expander_column (tree_view, column))
13783         {
13784           if (!rtl)
13785             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13786           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13787
13788           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13789             {
13790               if (!rtl)
13791                 cell_area.x += depth * tree_view->priv->expander_size;
13792               cell_area.width -= depth * tree_view->priv->expander_size;
13793             }
13794         }
13795
13796       if (gtk_tree_view_column_cell_is_visible (column))
13797         {
13798           if (is_separator)
13799             gtk_paint_hline (widget->style,
13800                              drawable,
13801                              GTK_STATE_NORMAL,
13802                              &cell_area,
13803                              widget,
13804                              NULL,
13805                              cell_area.x,
13806                              cell_area.x + cell_area.width,
13807                              cell_area.y + cell_area.height / 2);
13808           else
13809             _gtk_tree_view_column_cell_render (column,
13810                                                drawable,
13811                                                &background_area,
13812                                                &cell_area,
13813                                                &expose_area,
13814                                                0);
13815         }
13816       cell_offset += column->width;
13817     }
13818
13819   gdk_draw_rectangle (drawable,
13820                       widget->style->black_gc,
13821                       FALSE,
13822                       0, 0,
13823                       bin_window_width + 1,
13824                       background_area.height + 1);
13825
13826   return drawable;
13827 }
13828
13829
13830 /**
13831  * gtk_tree_view_set_destroy_count_func:
13832  * @tree_view: A #GtkTreeView
13833  * @func: Function to be called when a view row is destroyed, or %NULL
13834  * @data: User data to be passed to @func, or %NULL
13835  * @destroy: Destroy notifier for @data, or %NULL
13836  *
13837  * This function should almost never be used.  It is meant for private use by
13838  * ATK for determining the number of visible children that are removed when the
13839  * user collapses a row, or a row is deleted.
13840  **/
13841 void
13842 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13843                                       GtkTreeDestroyCountFunc  func,
13844                                       gpointer                 data,
13845                                       GtkDestroyNotify         destroy)
13846 {
13847   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13848
13849   if (tree_view->priv->destroy_count_destroy)
13850     (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
13851
13852   tree_view->priv->destroy_count_func = func;
13853   tree_view->priv->destroy_count_data = data;
13854   tree_view->priv->destroy_count_destroy = destroy;
13855 }
13856
13857
13858 /*
13859  * Interactive search
13860  */
13861
13862 /**
13863  * gtk_tree_view_set_enable_search:
13864  * @tree_view: A #GtkTreeView
13865  * @enable_search: %TRUE, if the user can search interactively
13866  *
13867  * If @enable_search is set, then the user can type in text to search through
13868  * the tree interactively (this is sometimes called "typeahead find").
13869  * 
13870  * Note that even if this is %FALSE, the user can still initiate a search 
13871  * using the "start-interactive-search" key binding.
13872  */
13873 void
13874 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13875                                  gboolean     enable_search)
13876 {
13877   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13878
13879   enable_search = !!enable_search;
13880   
13881   if (tree_view->priv->enable_search != enable_search)
13882     {
13883        tree_view->priv->enable_search = enable_search;
13884        g_object_notify (G_OBJECT (tree_view), "enable-search");
13885     }
13886 }
13887
13888 /**
13889  * gtk_tree_view_get_enable_search:
13890  * @tree_view: A #GtkTreeView
13891  *
13892  * Returns whether or not the tree allows to start interactive searching 
13893  * by typing in text.
13894  *
13895  * Return value: whether or not to let the user search interactively
13896  */
13897 gboolean
13898 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13899 {
13900   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13901
13902   return tree_view->priv->enable_search;
13903 }
13904
13905
13906 /**
13907  * gtk_tree_view_get_search_column:
13908  * @tree_view: A #GtkTreeView
13909  *
13910  * Gets the column searched on by the interactive search code.
13911  *
13912  * Return value: the column the interactive search code searches in.
13913  */
13914 gint
13915 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13916 {
13917   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13918
13919   return (tree_view->priv->search_column);
13920 }
13921
13922 /**
13923  * gtk_tree_view_set_search_column:
13924  * @tree_view: A #GtkTreeView
13925  * @column: the column of the model to search in, or -1 to disable searching
13926  *
13927  * Sets @column as the column where the interactive search code should
13928  * search in. 
13929  * 
13930  * If the sort column is set, users can use the "start-interactive-search"
13931  * key binding to bring up search popup. The enable-search property controls
13932  * whether simply typing text will also start an interactive search.
13933  *
13934  * Note that @column refers to a column of the model. 
13935  */
13936 void
13937 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13938                                  gint         column)
13939 {
13940   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13941   g_return_if_fail (column >= -1);
13942
13943   if (tree_view->priv->search_column == column)
13944     return;
13945
13946   tree_view->priv->search_column = column;
13947   g_object_notify (G_OBJECT (tree_view), "search-column");
13948 }
13949
13950 /**
13951  * gtk_tree_view_get_search_equal_func:
13952  * @tree_view: A #GtkTreeView
13953  *
13954  * Returns the compare function currently in use.
13955  *
13956  * Return value: the currently used compare function for the search code.
13957  */
13958
13959 GtkTreeViewSearchEqualFunc
13960 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
13961 {
13962   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13963
13964   return tree_view->priv->search_equal_func;
13965 }
13966
13967 /**
13968  * gtk_tree_view_set_search_equal_func:
13969  * @tree_view: A #GtkTreeView
13970  * @search_equal_func: the compare function to use during the search
13971  * @search_user_data: user data to pass to @search_equal_func, or %NULL
13972  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
13973  *
13974  * Sets the compare function for the interactive search capabilities; note
13975  * that somewhat like strcmp() returning 0 for equality
13976  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
13977  **/
13978 void
13979 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
13980                                      GtkTreeViewSearchEqualFunc  search_equal_func,
13981                                      gpointer                    search_user_data,
13982                                      GtkDestroyNotify            search_destroy)
13983 {
13984   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13985   g_return_if_fail (search_equal_func != NULL);
13986
13987   if (tree_view->priv->search_destroy)
13988     (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
13989
13990   tree_view->priv->search_equal_func = search_equal_func;
13991   tree_view->priv->search_user_data = search_user_data;
13992   tree_view->priv->search_destroy = search_destroy;
13993   if (tree_view->priv->search_equal_func == NULL)
13994     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
13995 }
13996
13997 /**
13998  * gtk_tree_view_get_search_entry:
13999  * @tree_view: A #GtkTreeView
14000  *
14001  * Returns the GtkEntry which is currently in use as interactive search
14002  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14003  * will be returned.
14004  *
14005  * Return value: the entry currently in use as search entry.
14006  *
14007  * Since: 2.10
14008  */
14009 GtkEntry *
14010 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14011 {
14012   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14013
14014   if (tree_view->priv->search_custom_entry_set)
14015     return GTK_ENTRY (tree_view->priv->search_entry);
14016
14017   return NULL;
14018 }
14019
14020 /**
14021  * gtk_tree_view_set_search_entry:
14022  * @tree_view: A #GtkTreeView
14023  * @entry: the entry the interactive search code of @tree_view should use or %NULL
14024  *
14025  * Sets the entry which the interactive search code will use for this
14026  * @tree_view.  This is useful when you want to provide a search entry
14027  * in our interface at all time at a fixed position.  Passing %NULL for
14028  * @entry will make the interactive search code use the built-in popup
14029  * entry again.
14030  *
14031  * Since: 2.10
14032  */
14033 void
14034 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14035                                 GtkEntry    *entry)
14036 {
14037   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14038   if (entry != NULL)
14039     g_return_if_fail (GTK_IS_ENTRY (entry));
14040
14041   if (tree_view->priv->search_custom_entry_set)
14042     {
14043       if (tree_view->priv->search_entry_changed_id)
14044         {
14045           g_signal_handler_disconnect (tree_view->priv->search_entry,
14046                                        tree_view->priv->search_entry_changed_id);
14047           tree_view->priv->search_entry_changed_id = 0;
14048         }
14049       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14050                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14051                                             tree_view);
14052
14053       g_object_unref (tree_view->priv->search_entry);
14054     }
14055   else if (tree_view->priv->search_window)
14056     {
14057       gtk_widget_destroy (tree_view->priv->search_window);
14058
14059       tree_view->priv->search_window = NULL;
14060     }
14061
14062   if (entry)
14063     {
14064       tree_view->priv->search_entry = g_object_ref (entry);
14065       tree_view->priv->search_custom_entry_set = TRUE;
14066
14067       if (tree_view->priv->search_entry_changed_id == 0)
14068         {
14069           tree_view->priv->search_entry_changed_id =
14070             g_signal_connect (tree_view->priv->search_entry, "changed",
14071                               G_CALLBACK (gtk_tree_view_search_init),
14072                               tree_view);
14073         }
14074       
14075         g_signal_connect (tree_view->priv->search_entry, "key_press_event",
14076                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14077                           tree_view);
14078
14079         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14080     }
14081   else
14082     {
14083       tree_view->priv->search_entry = NULL;
14084       tree_view->priv->search_custom_entry_set = FALSE;
14085     }
14086 }
14087
14088 /**
14089  * gtk_tree_view_set_search_position_func:
14090  * @tree_view: A #GtkTreeView
14091  * @func: the function to use to position the search dialog, or %NULL
14092  *    to use the default search position function
14093  * @data: user data to pass to @func, or %NULL
14094  * @destroy: Destroy notifier for @data, or %NULL
14095  *
14096  * Sets the function to use when positioning the seach dialog.
14097  *
14098  * Since: 2.10
14099  **/
14100 void
14101 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14102                                         GtkTreeViewSearchPositionFunc  func,
14103                                         gpointer                       user_data,
14104                                         GDestroyNotify                 destroy)
14105 {
14106   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14107
14108   if (tree_view->priv->search_position_destroy)
14109     (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
14110
14111   tree_view->priv->search_position_func = func;
14112   tree_view->priv->search_position_user_data = user_data;
14113   tree_view->priv->search_position_destroy = destroy;
14114   if (tree_view->priv->search_position_func == NULL)
14115     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14116 }
14117
14118 /**
14119  * gtk_tree_view_get_search_position_func:
14120  * @tree_view: A #GtkTreeView
14121  *
14122  * Returns the positioning function currently in use.
14123  *
14124  * Return value: the currently used function for positioning the search dialog.
14125  *
14126  * Since: 2.10
14127  */
14128 GtkTreeViewSearchPositionFunc
14129 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14130 {
14131   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14132
14133   return tree_view->priv->search_position_func;
14134 }
14135
14136
14137 static void
14138 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14139                                   GtkTreeView *tree_view)
14140 {
14141   if (tree_view->priv->disable_popdown)
14142     return;
14143
14144   if (tree_view->priv->search_entry_changed_id)
14145     {
14146       g_signal_handler_disconnect (tree_view->priv->search_entry,
14147                                    tree_view->priv->search_entry_changed_id);
14148       tree_view->priv->search_entry_changed_id = 0;
14149     }
14150   if (tree_view->priv->typeselect_flush_timeout)
14151     {
14152       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14153       tree_view->priv->typeselect_flush_timeout = 0;
14154     }
14155         
14156   if (GTK_WIDGET_VISIBLE (search_dialog))
14157     {
14158       /* send focus-in event */
14159       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
14160       gtk_widget_hide (search_dialog);
14161       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14162       send_focus_change (GTK_WIDGET (tree_view), TRUE);
14163     }
14164 }
14165
14166 static void
14167 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14168                                     GtkWidget   *search_dialog,
14169                                     gpointer     user_data)
14170 {
14171   gint x, y;
14172   gint tree_x, tree_y;
14173   gint tree_width, tree_height;
14174   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
14175   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14176   GtkRequisition requisition;
14177   gint monitor_num;
14178   GdkRectangle monitor;
14179
14180   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14181   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14182
14183   gtk_widget_realize (search_dialog);
14184
14185   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14186   gdk_drawable_get_size (tree_window,
14187                          &tree_width,
14188                          &tree_height);
14189   gtk_widget_size_request (search_dialog, &requisition);
14190
14191   if (tree_x + tree_width > gdk_screen_get_width (screen))
14192     x = gdk_screen_get_width (screen) - requisition.width;
14193   else if (tree_x + tree_width - requisition.width < 0)
14194     x = 0;
14195   else
14196     x = tree_x + tree_width - requisition.width;
14197
14198   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14199     y = gdk_screen_get_height (screen) - requisition.height;
14200   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14201     y = 0;
14202   else
14203     y = tree_y + tree_height;
14204
14205   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14206 }
14207
14208 static void
14209 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14210                                       GtkMenu  *menu,
14211                                       gpointer  data)
14212 {
14213   GtkTreeView *tree_view = (GtkTreeView *)data;
14214
14215   tree_view->priv->disable_popdown = 1;
14216   g_signal_connect (menu, "hide",
14217                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14218 }
14219
14220 /* Because we're visible but offscreen, we just set a flag in the preedit
14221  * callback.
14222  */
14223 static void
14224 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14225                                       GtkTreeView  *tree_view)
14226 {
14227   tree_view->priv->imcontext_changed = 1;
14228   if (tree_view->priv->typeselect_flush_timeout)
14229     {
14230       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14231       tree_view->priv->typeselect_flush_timeout =
14232         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14233                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14234                        tree_view);
14235     }
14236
14237 }
14238
14239 static void
14240 gtk_tree_view_search_activate (GtkEntry    *entry,
14241                                GtkTreeView *tree_view)
14242 {
14243   GtkTreePath *path;
14244   GtkRBNode *node;
14245   GtkRBTree *tree;
14246
14247   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14248                                     tree_view);
14249
14250   /* If we have a row selected and it's the cursor row, we activate
14251    * the row XXX */
14252   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14253     {
14254       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14255       
14256       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14257       
14258       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14259         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14260       
14261       gtk_tree_path_free (path);
14262     }
14263 }
14264
14265 static gboolean
14266 gtk_tree_view_real_search_enable_popdown (gpointer data)
14267 {
14268   GtkTreeView *tree_view = (GtkTreeView *)data;
14269
14270   tree_view->priv->disable_popdown = 0;
14271
14272   return FALSE;
14273 }
14274
14275 static void
14276 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14277                                      gpointer   data)
14278 {
14279   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14280 }
14281
14282 static gboolean
14283 gtk_tree_view_search_delete_event (GtkWidget *widget,
14284                                    GdkEventAny *event,
14285                                    GtkTreeView *tree_view)
14286 {
14287   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14288
14289   gtk_tree_view_search_dialog_hide (widget, tree_view);
14290
14291   return TRUE;
14292 }
14293
14294 static gboolean
14295 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14296                                          GdkEventButton *event,
14297                                          GtkTreeView *tree_view)
14298 {
14299   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14300
14301   gtk_tree_view_search_dialog_hide (widget, tree_view);
14302
14303   if (event->window == tree_view->priv->bin_window)
14304     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14305
14306   return TRUE;
14307 }
14308
14309 static gboolean
14310 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14311                                    GdkEventScroll *event,
14312                                    GtkTreeView *tree_view)
14313 {
14314   gboolean retval = FALSE;
14315
14316   if (event->direction == GDK_SCROLL_UP)
14317     {
14318       gtk_tree_view_search_move (widget, tree_view, TRUE);
14319       retval = TRUE;
14320     }
14321   else if (event->direction == GDK_SCROLL_DOWN)
14322     {
14323       gtk_tree_view_search_move (widget, tree_view, FALSE);
14324       retval = TRUE;
14325     }
14326
14327   /* renew the flush timeout */
14328   if (retval && tree_view->priv->typeselect_flush_timeout
14329       && !tree_view->priv->search_custom_entry_set)
14330     {
14331       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14332       tree_view->priv->typeselect_flush_timeout =
14333         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14334                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14335                        tree_view);
14336     }
14337
14338   return retval;
14339 }
14340
14341 static gboolean
14342 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14343                                       GdkEventKey *event,
14344                                       GtkTreeView *tree_view)
14345 {
14346   gboolean retval = FALSE;
14347
14348   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14349   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14350
14351   /* close window and cancel the search */
14352   if (!tree_view->priv->search_custom_entry_set
14353       && (event->keyval == GDK_Escape ||
14354           event->keyval == GDK_Tab ||
14355             event->keyval == GDK_KP_Tab ||
14356             event->keyval == GDK_ISO_Left_Tab))
14357     {
14358       gtk_tree_view_search_dialog_hide (widget, tree_view);
14359       return TRUE;
14360     }
14361
14362   /* select previous matching iter */
14363   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
14364     {
14365       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14366         gtk_widget_error_bell (widget);
14367
14368       retval = TRUE;
14369     }
14370
14371   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
14372       && (event->keyval == GDK_g || event->keyval == GDK_G))
14373     {
14374       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14375         gtk_widget_error_bell (widget);
14376
14377       retval = TRUE;
14378     }
14379
14380   /* select next matching iter */
14381   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
14382     {
14383       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14384         gtk_widget_error_bell (widget);
14385
14386       retval = TRUE;
14387     }
14388
14389   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
14390       && (event->keyval == GDK_g || event->keyval == GDK_G))
14391     {
14392       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14393         gtk_widget_error_bell (widget);
14394
14395       retval = TRUE;
14396     }
14397
14398   /* renew the flush timeout */
14399   if (retval && tree_view->priv->typeselect_flush_timeout
14400       && !tree_view->priv->search_custom_entry_set)
14401     {
14402       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14403       tree_view->priv->typeselect_flush_timeout =
14404         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14405                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14406                        tree_view);
14407     }
14408
14409   return retval;
14410 }
14411
14412 /*  this function returns FALSE if there is a search string but
14413  *  nothing was found, and TRUE otherwise.
14414  */
14415 static gboolean
14416 gtk_tree_view_search_move (GtkWidget   *window,
14417                            GtkTreeView *tree_view,
14418                            gboolean     up)
14419 {
14420   gboolean ret;
14421   gint len;
14422   gint count = 0;
14423   const gchar *text;
14424   GtkTreeIter iter;
14425   GtkTreeModel *model;
14426   GtkTreeSelection *selection;
14427
14428   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14429
14430   g_return_val_if_fail (text != NULL, FALSE);
14431
14432   len = strlen (text);
14433
14434   if (up && tree_view->priv->selected_iter == 1)
14435     return strlen (text) < 1;
14436
14437   len = strlen (text);
14438
14439   if (len < 1)
14440     return TRUE;
14441
14442   model = gtk_tree_view_get_model (tree_view);
14443   selection = gtk_tree_view_get_selection (tree_view);
14444
14445   /* search */
14446   gtk_tree_selection_unselect_all (selection);
14447   if (!gtk_tree_model_get_iter_first (model, &iter))
14448     return TRUE;
14449
14450   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14451                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14452
14453   if (ret)
14454     {
14455       /* found */
14456       tree_view->priv->selected_iter += up?(-1):(1);
14457       return TRUE;
14458     }
14459   else
14460     {
14461       /* return to old iter */
14462       count = 0;
14463       gtk_tree_model_get_iter_first (model, &iter);
14464       gtk_tree_view_search_iter (model, selection,
14465                                  &iter, text,
14466                                  &count, tree_view->priv->selected_iter);
14467       return FALSE;
14468     }
14469 }
14470
14471 static gboolean
14472 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14473                                  gint          column,
14474                                  const gchar  *key,
14475                                  GtkTreeIter  *iter,
14476                                  gpointer      search_data)
14477 {
14478   gboolean retval = TRUE;
14479   const gchar *str;
14480   gchar *normalized_string;
14481   gchar *normalized_key;
14482   gchar *case_normalized_string = NULL;
14483   gchar *case_normalized_key = NULL;
14484   GValue value = {0,};
14485   GValue transformed = {0,};
14486
14487   gtk_tree_model_get_value (model, iter, column, &value);
14488
14489   g_value_init (&transformed, G_TYPE_STRING);
14490
14491   if (!g_value_transform (&value, &transformed))
14492     {
14493       g_value_unset (&value);
14494       return TRUE;
14495     }
14496
14497   g_value_unset (&value);
14498
14499   str = g_value_get_string (&transformed);
14500   if (!str)
14501     {
14502       g_value_unset (&transformed);
14503       return TRUE;
14504     }
14505
14506   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14507   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14508
14509   if (normalized_string && normalized_key)
14510     {
14511       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14512       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14513
14514       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14515         retval = FALSE;
14516     }
14517
14518   g_value_unset (&transformed);
14519   g_free (normalized_key);
14520   g_free (normalized_string);
14521   g_free (case_normalized_key);
14522   g_free (case_normalized_string);
14523
14524   return retval;
14525 }
14526
14527 static gboolean
14528 gtk_tree_view_search_iter (GtkTreeModel     *model,
14529                            GtkTreeSelection *selection,
14530                            GtkTreeIter      *iter,
14531                            const gchar      *text,
14532                            gint             *count,
14533                            gint              n)
14534 {
14535   GtkRBTree *tree = NULL;
14536   GtkRBNode *node = NULL;
14537   GtkTreePath *path;
14538
14539   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14540
14541   path = gtk_tree_model_get_path (model, iter);
14542   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14543
14544   do
14545     {
14546       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14547         {
14548           (*count)++;
14549           if (*count == n)
14550             {
14551               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14552                                             TRUE, 0.5, 0.0);
14553               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14554               gtk_tree_selection_select_iter (selection, iter);
14555
14556               if (path)
14557                 gtk_tree_path_free (path);
14558
14559               return TRUE;
14560             }
14561         }
14562
14563       if (node->children)
14564         {
14565           gboolean has_child;
14566           GtkTreeIter tmp;
14567
14568           tree = node->children;
14569           node = tree->root;
14570
14571           while (node->left != tree->nil)
14572             node = node->left;
14573
14574           tmp = *iter;
14575           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14576           gtk_tree_path_down (path);
14577
14578           /* sanity check */
14579           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14580         }
14581       else
14582         {
14583           gboolean done = FALSE;
14584
14585           do
14586             {
14587               node = _gtk_rbtree_next (tree, node);
14588
14589               if (node)
14590                 {
14591                   gboolean has_next;
14592
14593                   has_next = gtk_tree_model_iter_next (model, iter);
14594
14595                   done = TRUE;
14596                   gtk_tree_path_next (path);
14597
14598                   /* sanity check */
14599                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14600                 }
14601               else
14602                 {
14603                   gboolean has_parent;
14604                   GtkTreeIter tmp_iter = *iter;
14605
14606                   node = tree->parent_node;
14607                   tree = tree->parent_tree;
14608
14609                   if (!tree)
14610                     {
14611                       if (path)
14612                         gtk_tree_path_free (path);
14613
14614                       /* we've run out of tree, done with this func */
14615                       return FALSE;
14616                     }
14617
14618                   has_parent = gtk_tree_model_iter_parent (model,
14619                                                            iter,
14620                                                            &tmp_iter);
14621                   gtk_tree_path_up (path);
14622
14623                   /* sanity check */
14624                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14625                 }
14626             }
14627           while (!done);
14628         }
14629     }
14630   while (1);
14631
14632   return FALSE;
14633 }
14634
14635 static void
14636 gtk_tree_view_search_init (GtkWidget   *entry,
14637                            GtkTreeView *tree_view)
14638 {
14639   gint ret;
14640   gint len;
14641   gint count = 0;
14642   const gchar *text;
14643   GtkTreeIter iter;
14644   GtkTreeModel *model;
14645   GtkTreeSelection *selection;
14646
14647   g_return_if_fail (GTK_IS_ENTRY (entry));
14648   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14649
14650   text = gtk_entry_get_text (GTK_ENTRY (entry));
14651   len = strlen (text);
14652   model = gtk_tree_view_get_model (tree_view);
14653   selection = gtk_tree_view_get_selection (tree_view);
14654
14655   /* search */
14656   gtk_tree_selection_unselect_all (selection);
14657   if (tree_view->priv->typeselect_flush_timeout
14658       && !tree_view->priv->search_custom_entry_set)
14659     {
14660       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14661       tree_view->priv->typeselect_flush_timeout =
14662         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14663                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14664                        tree_view);
14665     }
14666
14667   if (len < 1)
14668     return;
14669
14670   if (!gtk_tree_model_get_iter_first (model, &iter))
14671     return;
14672
14673   ret = gtk_tree_view_search_iter (model, selection,
14674                                    &iter, text,
14675                                    &count, 1);
14676
14677   if (ret)
14678     tree_view->priv->selected_iter = 1;
14679 }
14680
14681 static void
14682 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14683                              GtkTreeView     *tree_view)
14684 {
14685   if (tree_view->priv->edited_column == NULL)
14686     return;
14687
14688   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14689   tree_view->priv->edited_column = NULL;
14690
14691   if (GTK_WIDGET_HAS_FOCUS (cell_editable))
14692     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14693
14694   g_signal_handlers_disconnect_by_func (cell_editable,
14695                                         gtk_tree_view_remove_widget,
14696                                         tree_view);
14697
14698   gtk_container_remove (GTK_CONTAINER (tree_view),
14699                         GTK_WIDGET (cell_editable));  
14700
14701   /* FIXME should only redraw a single node */
14702   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14703 }
14704
14705 static gboolean
14706 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14707                              GtkTreePath *cursor_path)
14708 {
14709   GtkTreeIter iter;
14710   GdkRectangle background_area;
14711   GdkRectangle cell_area;
14712   GtkCellEditable *editable_widget = NULL;
14713   gchar *path_string;
14714   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14715   gint retval = FALSE;
14716   GtkRBTree *cursor_tree;
14717   GtkRBNode *cursor_node;
14718
14719   g_assert (tree_view->priv->focus_column);
14720
14721   if (! GTK_WIDGET_REALIZED (tree_view))
14722     return FALSE;
14723
14724   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14725       cursor_node == NULL)
14726     return FALSE;
14727
14728   path_string = gtk_tree_path_to_string (cursor_path);
14729   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14730
14731   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14732
14733   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14734                                            tree_view->priv->model,
14735                                            &iter,
14736                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14737                                            cursor_node->children?TRUE:FALSE);
14738   gtk_tree_view_get_background_area (tree_view,
14739                                      cursor_path,
14740                                      tree_view->priv->focus_column,
14741                                      &background_area);
14742   gtk_tree_view_get_cell_area (tree_view,
14743                                cursor_path,
14744                                tree_view->priv->focus_column,
14745                                &cell_area);
14746
14747   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14748                                         &editable_widget,
14749                                         NULL,
14750                                         path_string,
14751                                         &background_area,
14752                                         &cell_area,
14753                                         flags))
14754     {
14755       retval = TRUE;
14756       if (editable_widget != NULL)
14757         {
14758           gint left, right;
14759           GdkRectangle area;
14760           GtkCellRenderer *cell;
14761
14762           area = cell_area;
14763           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14764
14765           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14766
14767           area.x += left;
14768           area.width -= right + left;
14769
14770           gtk_tree_view_real_start_editing (tree_view,
14771                                             tree_view->priv->focus_column,
14772                                             cursor_path,
14773                                             editable_widget,
14774                                             &area,
14775                                             NULL,
14776                                             flags);
14777         }
14778
14779     }
14780   g_free (path_string);
14781   return retval;
14782 }
14783
14784 static void
14785 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14786                                   GtkTreeViewColumn *column,
14787                                   GtkTreePath       *path,
14788                                   GtkCellEditable   *cell_editable,
14789                                   GdkRectangle      *cell_area,
14790                                   GdkEvent          *event,
14791                                   guint              flags)
14792 {
14793   gint pre_val = tree_view->priv->vadjustment->value;
14794   GtkRequisition requisition;
14795
14796   tree_view->priv->edited_column = column;
14797   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14798
14799   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14800   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14801
14802   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
14803
14804   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14805
14806   if (requisition.height < cell_area->height)
14807     {
14808       gint diff = cell_area->height - requisition.height;
14809       gtk_tree_view_put (tree_view,
14810                          GTK_WIDGET (cell_editable),
14811                          cell_area->x, cell_area->y + diff/2,
14812                          cell_area->width, requisition.height);
14813     }
14814   else
14815     {
14816       gtk_tree_view_put (tree_view,
14817                          GTK_WIDGET (cell_editable),
14818                          cell_area->x, cell_area->y,
14819                          cell_area->width, cell_area->height);
14820     }
14821
14822   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14823                                    (GdkEvent *)event);
14824
14825   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14826   g_signal_connect (cell_editable, "remove_widget",
14827                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14828 }
14829
14830 static void
14831 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14832                             gboolean     cancel_editing)
14833 {
14834   GtkTreeViewColumn *column;
14835   GtkCellRenderer *cell;
14836
14837   if (tree_view->priv->edited_column == NULL)
14838     return;
14839
14840   /*
14841    * This is very evil. We need to do this, because
14842    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14843    * later on. If gtk_tree_view_row_changed notices
14844    * tree_view->priv->edited_column != NULL, it'll call
14845    * gtk_tree_view_stop_editing again. Bad things will happen then.
14846    *
14847    * Please read that again if you intend to modify anything here.
14848    */
14849
14850   column = tree_view->priv->edited_column;
14851   tree_view->priv->edited_column = NULL;
14852
14853   cell = _gtk_tree_view_column_get_edited_cell (column);
14854   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14855
14856   if (!cancel_editing)
14857     gtk_cell_editable_editing_done (column->editable_widget);
14858
14859   tree_view->priv->edited_column = column;
14860
14861   gtk_cell_editable_remove_widget (column->editable_widget);
14862 }
14863
14864
14865 /**
14866  * gtk_tree_view_set_hover_selection:
14867  * @tree_view: a #GtkTreeView
14868  * @hover: %TRUE to enable hover selection mode
14869  *
14870  * Enables of disables the hover selection mode of @tree_view.
14871  * Hover selection makes the selected row follow the pointer.
14872  * Currently, this works only for the selection modes 
14873  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14874  * 
14875  * Since: 2.6
14876  **/
14877 void     
14878 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14879                                    gboolean     hover)
14880 {
14881   hover = hover != FALSE;
14882
14883   if (hover != tree_view->priv->hover_selection)
14884     {
14885       tree_view->priv->hover_selection = hover;
14886
14887       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14888     }
14889 }
14890
14891 /**
14892  * gtk_tree_view_get_hover_selection:
14893  * @tree_view: a #GtkTreeView
14894  * 
14895  * Returns whether hover selection mode is turned on for @tree_view.
14896  * 
14897  * Return value: %TRUE if @tree_view is in hover selection mode
14898  *
14899  * Since: 2.6 
14900  **/
14901 gboolean 
14902 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14903 {
14904   return tree_view->priv->hover_selection;
14905 }
14906
14907 /**
14908  * gtk_tree_view_set_hover_expand:
14909  * @tree_view: a #GtkTreeView
14910  * @expand: %TRUE to enable hover selection mode
14911  *
14912  * Enables of disables the hover expansion mode of @tree_view.
14913  * Hover expansion makes rows expand or collaps if the pointer 
14914  * moves over them.
14915  * 
14916  * Since: 2.6
14917  **/
14918 void     
14919 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14920                                 gboolean     expand)
14921 {
14922   expand = expand != FALSE;
14923
14924   if (expand != tree_view->priv->hover_expand)
14925     {
14926       tree_view->priv->hover_expand = expand;
14927
14928       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14929     }
14930 }
14931
14932 /**
14933  * gtk_tree_view_get_hover_expand:
14934  * @tree_view: a #GtkTreeView
14935  * 
14936  * Returns whether hover expansion mode is turned on for @tree_view.
14937  * 
14938  * Return value: %TRUE if @tree_view is in hover expansion mode
14939  *
14940  * Since: 2.6 
14941  **/
14942 gboolean 
14943 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14944 {
14945   return tree_view->priv->hover_expand;
14946 }
14947
14948 /**
14949  * gtk_tree_view_set_rubber_banding:
14950  * @tree_view: a #GtkTreeView
14951  * @enable: %TRUE to enable rubber banding
14952  *
14953  * Enables or disables rubber banding in @tree_view.  If the selection mode
14954  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14955  * multiple rows by dragging the mouse.
14956  * 
14957  * Since: 2.10
14958  **/
14959 void
14960 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
14961                                   gboolean     enable)
14962 {
14963   enable = enable != FALSE;
14964
14965   if (enable != tree_view->priv->rubber_banding_enable)
14966     {
14967       tree_view->priv->rubber_banding_enable = enable;
14968
14969       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
14970     }
14971 }
14972
14973 /**
14974  * gtk_tree_view_get_rubber_banding:
14975  * @tree_view: a #GtkTreeView
14976  * 
14977  * Returns whether rubber banding is turned on for @tree_view.  If the
14978  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
14979  * user to select multiple rows by dragging the mouse.
14980  * 
14981  * Return value: %TRUE if rubber banding in @tree_view is enabled.
14982  *
14983  * Since: 2.10
14984  **/
14985 gboolean
14986 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
14987 {
14988   return tree_view->priv->rubber_banding_enable;
14989 }
14990
14991 /**
14992  * gtk_tree_view_is_rubber_banding_active:
14993  * @tree_view: a #GtkTreeView
14994  * 
14995  * Returns whether a rubber banding operation is currently being done
14996  * in @tree_view.
14997  *
14998  * Return value: %TRUE if a rubber banding operation is currently being
14999  * done in @tree_view.
15000  *
15001  * Since: 2.12
15002  **/
15003 gboolean
15004 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15005 {
15006   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15007
15008   if (tree_view->priv->rubber_banding_enable
15009       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15010     return TRUE;
15011
15012   return FALSE;
15013 }
15014
15015 /**
15016  * gtk_tree_view_get_row_separator_func:
15017  * @tree_view: a #GtkTreeView
15018  * 
15019  * Returns the current row separator function.
15020  * 
15021  * Return value: the current row separator function.
15022  *
15023  * Since: 2.6
15024  **/
15025 GtkTreeViewRowSeparatorFunc 
15026 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15027 {
15028   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15029
15030   return tree_view->priv->row_separator_func;
15031 }
15032
15033 /**
15034  * gtk_tree_view_set_row_separator_func:
15035  * @tree_view: a #GtkTreeView
15036  * @func: a #GtkTreeViewRowSeparatorFunc
15037  * @data: user data to pass to @func, or %NULL
15038  * @destroy: destroy notifier for @data, or %NULL
15039  * 
15040  * Sets the row separator function, which is used to determine
15041  * whether a row should be drawn as a separator. If the row separator
15042  * function is %NULL, no separators are drawn. This is the default value.
15043  *
15044  * Since: 2.6
15045  **/
15046 void
15047 gtk_tree_view_set_row_separator_func (GtkTreeView                *tree_view,
15048                                       GtkTreeViewRowSeparatorFunc func,
15049                                       gpointer                    data,
15050                                       GtkDestroyNotify            destroy)
15051 {
15052   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15053
15054   if (tree_view->priv->row_separator_destroy)
15055     (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data);
15056
15057   tree_view->priv->row_separator_func = func;
15058   tree_view->priv->row_separator_data = data;
15059   tree_view->priv->row_separator_destroy = destroy;
15060 }
15061
15062   
15063 static void
15064 gtk_tree_view_grab_notify (GtkWidget *widget,
15065                            gboolean   was_grabbed)
15066 {
15067   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15068
15069   tree_view->priv->in_grab = !was_grabbed;
15070
15071   if (!was_grabbed)
15072     {
15073       tree_view->priv->pressed_button = -1;
15074
15075       if (tree_view->priv->rubber_band_status)
15076         gtk_tree_view_stop_rubber_band (tree_view);
15077     }
15078 }
15079
15080 static void
15081 gtk_tree_view_state_changed (GtkWidget      *widget,
15082                              GtkStateType    previous_state)
15083 {
15084   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15085
15086   if (GTK_WIDGET_REALIZED (widget))
15087     {
15088       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
15089       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
15090     }
15091
15092   gtk_widget_queue_draw (widget);
15093 }
15094
15095 /**
15096  * gtk_tree_view_get_grid_lines:
15097  * @tree_view: a #GtkTreeView
15098  *
15099  * Returns which grid lines are enabled in @tree_view.
15100  *
15101  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15102  * are enabled.
15103  *
15104  * Since: 2.10
15105  */
15106 GtkTreeViewGridLines
15107 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15108 {
15109   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15110
15111   return tree_view->priv->grid_lines;
15112 }
15113
15114 /**
15115  * gtk_tree_view_set_grid_lines:
15116  * @tree_view: a #GtkTreeView
15117  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15118  * enable.
15119  *
15120  * Sets which grid lines to draw in @tree_view.
15121  *
15122  * Since: 2.10
15123  */
15124 void
15125 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15126                               GtkTreeViewGridLines   grid_lines)
15127 {
15128   GtkTreeViewPrivate *priv;
15129   GtkWidget *widget;
15130   GtkTreeViewGridLines old_grid_lines;
15131
15132   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15133
15134   priv = tree_view->priv;
15135   widget = GTK_WIDGET (tree_view);
15136
15137   old_grid_lines = priv->grid_lines;
15138   priv->grid_lines = grid_lines;
15139   
15140   if (GTK_WIDGET_REALIZED (widget))
15141     {
15142       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15143           priv->grid_line_gc)
15144         {
15145           g_object_unref (priv->grid_line_gc);
15146           priv->grid_line_gc = NULL;
15147         }
15148       
15149       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15150           !priv->grid_line_gc)
15151         {
15152           gint line_width;
15153           guint8 *dash_list;
15154
15155           gtk_widget_style_get (widget,
15156                                 "grid-line-width", &line_width,
15157                                 "grid-line-pattern", (gchar *)&dash_list,
15158                                 NULL);
15159       
15160           priv->grid_line_gc = gdk_gc_new (widget->window);
15161           gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
15162           
15163           gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
15164                                       GDK_LINE_ON_OFF_DASH,
15165                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15166           gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
15167
15168           g_free (dash_list);
15169         }      
15170     }
15171
15172   if (old_grid_lines != grid_lines)
15173     {
15174       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15175       
15176       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15177     }
15178 }
15179
15180 /**
15181  * gtk_tree_view_get_enable_tree_lines:
15182  * @tree_view: a #GtkTreeView.
15183  *
15184  * Returns whether or not tree lines are drawn in @tree_view.
15185  *
15186  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15187  * otherwise.
15188  *
15189  * Since: 2.10
15190  */
15191 gboolean
15192 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15193 {
15194   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15195
15196   return tree_view->priv->tree_lines_enabled;
15197 }
15198
15199 /**
15200  * gtk_tree_view_set_enable_tree_lines:
15201  * @tree_view: a #GtkTreeView
15202  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15203  *
15204  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15205  * This does not have any visible effects for lists.
15206  *
15207  * Since: 2.10
15208  */
15209 void
15210 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15211                                      gboolean     enabled)
15212 {
15213   GtkTreeViewPrivate *priv;
15214   GtkWidget *widget;
15215   gboolean was_enabled;
15216
15217   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15218
15219   enabled = enabled != FALSE;
15220
15221   priv = tree_view->priv;
15222   widget = GTK_WIDGET (tree_view);
15223
15224   was_enabled = priv->tree_lines_enabled;
15225
15226   priv->tree_lines_enabled = enabled;
15227
15228   if (GTK_WIDGET_REALIZED (widget))
15229     {
15230       if (!enabled && priv->tree_line_gc)
15231         {
15232           g_object_unref (priv->tree_line_gc);
15233           priv->tree_line_gc = NULL;
15234         }
15235       
15236       if (enabled && !priv->tree_line_gc)
15237         {
15238           gint line_width;
15239           guint8 *dash_list;
15240           gtk_widget_style_get (widget,
15241                                 "tree-line-width", &line_width,
15242                                 "tree-line-pattern", (gchar *)&dash_list,
15243                                 NULL);
15244           
15245           priv->tree_line_gc = gdk_gc_new (widget->window);
15246           gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc);
15247           
15248           gdk_gc_set_line_attributes (priv->tree_line_gc, line_width,
15249                                       GDK_LINE_ON_OFF_DASH,
15250                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15251           gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2);
15252
15253           g_free (dash_list);
15254         }
15255     }
15256
15257   if (was_enabled != enabled)
15258     {
15259       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15260
15261       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15262     }
15263 }
15264
15265
15266 /**
15267  * gtk_tree_view_set_show_expanders:
15268  * @tree_view: a #GtkTreeView
15269  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15270  *
15271  * Sets whether to draw and enable expanders and indent child rows in
15272  * @tree_view.  When disabled there will be no expanders visible in trees
15273  * and there will be no way to expand and collapse rows by default.  Also
15274  * note that hiding the expanders will disable the default indentation.  You
15275  * can set a custom indentation in this case using
15276  * gtk_tree_view_set_level_indentation().
15277  * This does not have any visible effects for lists.
15278  *
15279  * Since: 2.12
15280  */
15281 void
15282 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15283                                   gboolean     enabled)
15284 {
15285   gboolean was_enabled;
15286
15287   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15288
15289   enabled = enabled != FALSE;
15290   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15291
15292   if (enabled)
15293     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15294   else
15295     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15296
15297   if (enabled != was_enabled)
15298     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15299 }
15300
15301 /**
15302  * gtk_tree_view_get_show_expanders:
15303  * @tree_view: a #GtkTreeView.
15304  *
15305  * Returns whether or not expanders are drawn in @tree_view.
15306  *
15307  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15308  * otherwise.
15309  *
15310  * Since: 2.12
15311  */
15312 gboolean
15313 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15314 {
15315   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15316
15317   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15318 }
15319
15320 /**
15321  * gtk_tree_view_set_level_indentation:
15322  * @tree_view: a #GtkTreeView
15323  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15324  *
15325  * Sets the amount of extra indentation for child levels to use in @tree_view
15326  * in addition to the default indentation.  The value should be specified in
15327  * pixels, a value of 0 disables this feature and in this case only the default
15328  * indentation will be used.
15329  * This does not have any visible effects for lists.
15330  *
15331  * Since: 2.12
15332  */
15333 void
15334 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15335                                      gint         indentation)
15336 {
15337   tree_view->priv->level_indentation = indentation;
15338
15339   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15340 }
15341
15342 /**
15343  * gtk_tree_view_get_level_indentation:
15344  * @tree_view: a #GtkTreeView.
15345  *
15346  * Returns the amount, in pixels, of extra indentation for child levels
15347  * in @tree_view.
15348  *
15349  * Return value: the amount of extra indentation for child levels in
15350  * @tree_view.  A return value of 0 means that this feature is disabled.
15351  *
15352  * Since: 2.12
15353  */
15354 gint
15355 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15356 {
15357   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15358
15359   return tree_view->priv->level_indentation;
15360 }
15361
15362 /**
15363  * gtk_tree_view_set_tooltip_row:
15364  * @tree_view: a #GtkTreeView
15365  * @tooltip: a #GtkTooltip
15366  * @path: a #GtkTreePath
15367  *
15368  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15369  * See also gtk_tooltip_set_tip_area().
15370  *
15371  * Since: 2.12
15372  */
15373 void
15374 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15375                                GtkTooltip  *tooltip,
15376                                GtkTreePath *path)
15377 {
15378   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15379   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15380
15381   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15382 }
15383
15384 /**
15385  * gtk_tree_view_set_tooltip_cell:
15386  * @tree_view: a #GtkTreeView
15387  * @tooltip: a #GtkTooltip
15388  * @path: a #GtkTreePath or %NULL
15389  * @column: a #GtkTreeViewColumn or %NULL
15390  * @cell: a #GtkCellRenderer or %NULL
15391  *
15392  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15393  * in common.  For example if @path is %NULL and @column is set, the tip
15394  * area will be set to the full area covered by @column.  See also
15395  * gtk_tooltip_set_tip_area().
15396  *
15397  * Note that if @path is not specified and @cell is set and part of a column
15398  * containing the expander, the tooltip might not show and hide at the correct
15399  * position.  In such cases @path must be set to the current node under the
15400  * mouse cursor for this function to operate correctly.
15401  *
15402  * Since: 2.12
15403  */
15404 void
15405 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15406                                 GtkTooltip        *tooltip,
15407                                 GtkTreePath       *path,
15408                                 GtkTreeViewColumn *column,
15409                                 GtkCellRenderer   *cell)
15410 {
15411   GdkRectangle rect;
15412
15413   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15414   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15415
15416   if (column)
15417     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
15418
15419   if (cell)
15420     g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
15421
15422   /* Determine x values. */
15423   if (column && cell)
15424     {
15425       GdkRectangle tmp;
15426       gint start, width;
15427
15428       /* We always pass in path here, whether it is NULL or not.
15429        * For cells in expander columns path must be specified so that
15430        * we can correctly account for the indentation.  This also means
15431        * that the tooltip is constrained vertically by the "Determine y
15432        * values" code below; this is not a real problem since cells actually
15433        * don't stretch vertically in constrast to columns.
15434        */
15435       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15436       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15437
15438       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15439                                                          tmp.x + start, 0,
15440                                                          &rect.x, NULL);
15441       rect.width = width;
15442     }
15443   else if (column)
15444     {
15445       GdkRectangle tmp;
15446
15447       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15448       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15449                                                          tmp.x, 0,
15450                                                          &rect.x, NULL);
15451       rect.width = tmp.width;
15452     }
15453   else
15454     {
15455       rect.x = 0;
15456       rect.width = GTK_WIDGET (tree_view)->allocation.width;
15457     }
15458
15459   /* Determine y values. */
15460   if (path)
15461     {
15462       GdkRectangle tmp;
15463
15464       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15465       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15466                                                          0, tmp.y,
15467                                                          NULL, &rect.y);
15468       rect.height = tmp.height;
15469     }
15470   else
15471     {
15472       rect.y = 0;
15473       rect.height = tree_view->priv->vadjustment->page_size;
15474     }
15475
15476   gtk_tooltip_set_tip_area (tooltip, &rect);
15477 }
15478
15479 /**
15480  * gtk_tree_view_get_tooltip_context:
15481  * @tree_view: a #GtkTreeView
15482  * @x: the x coordinate (relative to widget coordinates)
15483  * @y: the y coordinate (relative to widget coordinates)
15484  * @keyboard_tip: whether this is a keyboard tooltip or not
15485  * @model: a pointer to receive a #GtkTreeModel or %NULL
15486  * @path: a pointer to receive a #GtkTreePath or %NULL
15487  * @iter: a pointer to receive a #GtkTreeIter or %NULL
15488  *
15489  * This function is supposed to be used in a #GtkWidget::query-tooltip
15490  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15491  * which are received in the signal handler, should be passed to this
15492  * function without modification.
15493  *
15494  * The return value indicates whether there is a tree view row at the given
15495  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15496  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15497  * @model, @path and @iter which have been provided will be set to point to
15498  * that row and the corresponding model.  @x and @y will always be converted
15499  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15500  *
15501  * Return value: whether or not the given tooltip context points to a row.
15502  *
15503  * Since: 2.12
15504  */
15505 gboolean
15506 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15507                                    gint          *x,
15508                                    gint          *y,
15509                                    gboolean       keyboard_tip,
15510                                    GtkTreeModel **model,
15511                                    GtkTreePath  **path,
15512                                    GtkTreeIter   *iter)
15513 {
15514   GtkTreePath *tmppath = NULL;
15515
15516   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15517   g_return_val_if_fail (x != NULL, FALSE);
15518   g_return_val_if_fail (y != NULL, FALSE);
15519
15520   if (keyboard_tip)
15521     {
15522       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15523
15524       if (!tmppath)
15525         return FALSE;
15526     }
15527   else
15528     {
15529       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15530                                                          x, y);
15531
15532       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15533                                           &tmppath, NULL, NULL, NULL))
15534         return FALSE;
15535     }
15536
15537   if (model)
15538     *model = gtk_tree_view_get_model (tree_view);
15539
15540   if (iter)
15541     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15542                              iter, tmppath);
15543
15544   if (path)
15545     *path = tmppath;
15546   else
15547     gtk_tree_path_free (tmppath);
15548
15549   return TRUE;
15550 }
15551
15552 static gboolean
15553 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15554                                     gint        x,
15555                                     gint        y,
15556                                     gboolean    keyboard_tip,
15557                                     GtkTooltip *tooltip,
15558                                     gpointer    data)
15559 {
15560   gchar *str;
15561   GtkTreeIter iter;
15562   GtkTreePath *path;
15563   GtkTreeModel *model;
15564   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15565
15566   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15567                                           &x, &y,
15568                                           keyboard_tip,
15569                                           &model, &path, &iter))
15570     return FALSE;
15571
15572   gtk_tree_model_get (model, &iter, tree_view->priv->tooltip_column, &str, -1);
15573
15574   if (!str)
15575     {
15576       gtk_tree_path_free (path);
15577       return FALSE;
15578     }
15579
15580   gtk_tooltip_set_markup (tooltip, str);
15581   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15582
15583   gtk_tree_path_free (path);
15584   g_free (str);
15585
15586   return TRUE;
15587 }
15588
15589 /**
15590  * gtk_tree_view_set_tooltip_column:
15591  * @tree_view: a #GtkTreeView
15592  * @column: an integer, which is a valid column number for @tree_view's model
15593  *
15594  * If you only plan to have simple (text-only) tooltips on full rows, you
15595  * can use this function to have #GtkTreeView handle these automatically
15596  * for you. @column should be set to the column in @tree_view's model
15597  * containing the tooltip texts, or -1 to disable this feature.
15598  *
15599  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15600  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15601  *
15602  * Since: 2.12
15603  */
15604 void
15605 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15606                                   gint         column)
15607 {
15608   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15609
15610   if (column == tree_view->priv->tooltip_column)
15611     return;
15612
15613   if (column == -1)
15614     {
15615       g_signal_handlers_disconnect_by_func (tree_view,
15616                                             gtk_tree_view_set_tooltip_query_cb,
15617                                             NULL);
15618       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15619     }
15620   else
15621     {
15622       if (tree_view->priv->tooltip_column == -1)
15623         {
15624           g_signal_connect (tree_view, "query-tooltip",
15625                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15626           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15627         }
15628     }
15629
15630   tree_view->priv->tooltip_column = column;
15631   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15632 }
15633
15634 /**
15635  * gtk_tree_view_get_tooltip_column:
15636  * @tree_view: a #GtkTreeView
15637  *
15638  * Returns the column of @tree_view's model which is being used for
15639  * displaying tooltips on @tree_view's rows.
15640  *
15641  * Return value: the index of the tooltip column that is currently being
15642  * used, or -1 if this is disabled.
15643  *
15644  * Since: 2.12
15645  */
15646 gint
15647 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15648 {
15649   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15650
15651   return tree_view->priv->tooltip_column;
15652 }
15653
15654 #define __GTK_TREE_VIEW_C__
15655 #include "gtkaliasdef.c"