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