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