]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
gtk/gtkcombobox.c gtk/gtkiconview.c gtk/gtkrange.c gtk/gtkscrolledwindow.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   if (GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy)
1696     (* GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy) (object);
1697 }
1698
1699 \f
1700
1701 /* GtkWidget Methods
1702  */
1703
1704 /* GtkWidget::map helper */
1705 static void
1706 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1707 {
1708   GList *list;
1709
1710   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1711
1712   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1713     {
1714       GtkTreeViewColumn *column;
1715
1716       for (list = tree_view->priv->columns; list; list = list->next)
1717         {
1718           column = list->data;
1719           if (GTK_WIDGET_VISIBLE (column->button) &&
1720               !GTK_WIDGET_MAPPED (column->button))
1721             gtk_widget_map (column->button);
1722         }
1723       for (list = tree_view->priv->columns; list; list = list->next)
1724         {
1725           column = list->data;
1726           if (column->visible == FALSE)
1727             continue;
1728           if (column->resizable)
1729             {
1730               gdk_window_raise (column->window);
1731               gdk_window_show (column->window);
1732             }
1733           else
1734             gdk_window_hide (column->window);
1735         }
1736       gdk_window_show (tree_view->priv->header_window);
1737     }
1738 }
1739
1740 static void
1741 gtk_tree_view_map (GtkWidget *widget)
1742 {
1743   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1744   GList *tmp_list;
1745
1746   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1747
1748   tmp_list = tree_view->priv->children;
1749   while (tmp_list)
1750     {
1751       GtkTreeViewChild *child = tmp_list->data;
1752       tmp_list = tmp_list->next;
1753
1754       if (GTK_WIDGET_VISIBLE (child->widget))
1755         {
1756           if (!GTK_WIDGET_MAPPED (child->widget))
1757             gtk_widget_map (child->widget);
1758         }
1759     }
1760   gdk_window_show (tree_view->priv->bin_window);
1761
1762   gtk_tree_view_map_buttons (tree_view);
1763
1764   gdk_window_show (widget->window);
1765 }
1766
1767 static void
1768 gtk_tree_view_realize (GtkWidget *widget)
1769 {
1770   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1771   GList *tmp_list;
1772   GdkWindowAttr attributes;
1773   gint attributes_mask;
1774
1775   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1776
1777   /* Make the main, clipping window */
1778   attributes.window_type = GDK_WINDOW_CHILD;
1779   attributes.x = widget->allocation.x;
1780   attributes.y = widget->allocation.y;
1781   attributes.width = widget->allocation.width;
1782   attributes.height = widget->allocation.height;
1783   attributes.wclass = GDK_INPUT_OUTPUT;
1784   attributes.visual = gtk_widget_get_visual (widget);
1785   attributes.colormap = gtk_widget_get_colormap (widget);
1786   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1787
1788   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1789
1790   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1791                                    &attributes, attributes_mask);
1792   gdk_window_set_user_data (widget->window, widget);
1793
1794   /* Make the window for the tree */
1795   attributes.x = 0;
1796   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1797   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1798   attributes.height = widget->allocation.height;
1799   attributes.event_mask = GDK_EXPOSURE_MASK |
1800     GDK_SCROLL_MASK |
1801     GDK_POINTER_MOTION_MASK |
1802     GDK_ENTER_NOTIFY_MASK |
1803     GDK_LEAVE_NOTIFY_MASK |
1804     GDK_BUTTON_PRESS_MASK |
1805     GDK_BUTTON_RELEASE_MASK |
1806     gtk_widget_get_events (widget);
1807
1808   tree_view->priv->bin_window = gdk_window_new (widget->window,
1809                                                 &attributes, attributes_mask);
1810   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1811
1812   /* Make the column header window */
1813   attributes.x = 0;
1814   attributes.y = 0;
1815   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1816   attributes.height = tree_view->priv->header_height;
1817   attributes.event_mask = (GDK_EXPOSURE_MASK |
1818                            GDK_SCROLL_MASK |
1819                            GDK_BUTTON_PRESS_MASK |
1820                            GDK_BUTTON_RELEASE_MASK |
1821                            GDK_KEY_PRESS_MASK |
1822                            GDK_KEY_RELEASE_MASK) |
1823     gtk_widget_get_events (widget);
1824
1825   tree_view->priv->header_window = gdk_window_new (widget->window,
1826                                                    &attributes, attributes_mask);
1827   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1828
1829   /* Add them all up. */
1830   widget->style = gtk_style_attach (widget->style, widget->window);
1831   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1832   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1833   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1834
1835   tmp_list = tree_view->priv->children;
1836   while (tmp_list)
1837     {
1838       GtkTreeViewChild *child = tmp_list->data;
1839       tmp_list = tmp_list->next;
1840
1841       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1842     }
1843
1844   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1845     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1846
1847   /* Need to call those here, since they create GCs */
1848   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1849   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1850
1851   install_presize_handler (tree_view); 
1852 }
1853
1854 static void
1855 gtk_tree_view_unrealize (GtkWidget *widget)
1856 {
1857   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1858   GtkTreeViewPrivate *priv = tree_view->priv;
1859   GList *list;
1860
1861   if (priv->scroll_timeout != 0)
1862     {
1863       g_source_remove (priv->scroll_timeout);
1864       priv->scroll_timeout = 0;
1865     }
1866
1867   if (priv->auto_expand_timeout != 0)
1868     {
1869       g_source_remove (priv->auto_expand_timeout);
1870       priv->auto_expand_timeout = 0;
1871     }
1872
1873   if (priv->open_dest_timeout != 0)
1874     {
1875       g_source_remove (priv->open_dest_timeout);
1876       priv->open_dest_timeout = 0;
1877     }
1878
1879   remove_expand_collapse_timeout (tree_view);
1880   
1881   if (priv->presize_handler_timer != 0)
1882     {
1883       g_source_remove (priv->presize_handler_timer);
1884       priv->presize_handler_timer = 0;
1885     }
1886
1887   if (priv->validate_rows_timer != 0)
1888     {
1889       g_source_remove (priv->validate_rows_timer);
1890       priv->validate_rows_timer = 0;
1891     }
1892
1893   if (priv->scroll_sync_timer != 0)
1894     {
1895       g_source_remove (priv->scroll_sync_timer);
1896       priv->scroll_sync_timer = 0;
1897     }
1898
1899   if (priv->typeselect_flush_timeout)
1900     {
1901       g_source_remove (priv->typeselect_flush_timeout);
1902       priv->typeselect_flush_timeout = 0;
1903     }
1904   
1905   for (list = priv->columns; list; list = list->next)
1906     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1907
1908   gdk_window_set_user_data (priv->bin_window, NULL);
1909   gdk_window_destroy (priv->bin_window);
1910   priv->bin_window = NULL;
1911
1912   gdk_window_set_user_data (priv->header_window, NULL);
1913   gdk_window_destroy (priv->header_window);
1914   priv->header_window = NULL;
1915
1916   if (priv->drag_window)
1917     {
1918       gdk_window_set_user_data (priv->drag_window, NULL);
1919       gdk_window_destroy (priv->drag_window);
1920       priv->drag_window = NULL;
1921     }
1922
1923   if (priv->drag_highlight_window)
1924     {
1925       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1926       gdk_window_destroy (priv->drag_highlight_window);
1927       priv->drag_highlight_window = NULL;
1928     }
1929
1930   if (priv->tree_line_gc)
1931     {
1932       g_object_unref (priv->tree_line_gc);
1933       priv->tree_line_gc = NULL;
1934     }
1935
1936   if (priv->grid_line_gc)
1937     {
1938       g_object_unref (priv->grid_line_gc);
1939       priv->grid_line_gc = NULL;
1940     }
1941
1942   /* GtkWidget::unrealize destroys children and widget->window */
1943   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize)
1944     (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize) (widget);
1945 }
1946
1947 /* GtkWidget::size_request helper */
1948 static void
1949 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1950 {
1951   GList *list;
1952
1953   tree_view->priv->header_height = 0;
1954
1955   if (tree_view->priv->model)
1956     {
1957       for (list = tree_view->priv->columns; list; list = list->next)
1958         {
1959           GtkRequisition requisition;
1960           GtkTreeViewColumn *column = list->data;
1961
1962           if (column->button == NULL)
1963             continue;
1964
1965           column = list->data;
1966           
1967           gtk_widget_size_request (column->button, &requisition);
1968           column->button_request = requisition.width;
1969           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1970         }
1971     }
1972 }
1973
1974
1975 /* Called only by ::size_request */
1976 static void
1977 gtk_tree_view_update_size (GtkTreeView *tree_view)
1978 {
1979   GList *list;
1980   GtkTreeViewColumn *column;
1981   gint i;
1982
1983   if (tree_view->priv->model == NULL)
1984     {
1985       tree_view->priv->width = 0;
1986       tree_view->priv->prev_width = 0;                   
1987       tree_view->priv->height = 0;
1988       return;
1989     }
1990
1991   tree_view->priv->prev_width = tree_view->priv->width;  
1992   tree_view->priv->width = 0;
1993
1994   /* keep this in sync with size_allocate below */
1995   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1996     {
1997       gint real_requested_width = 0;
1998       column = list->data;
1999       if (!column->visible)
2000         continue;
2001
2002       if (column->use_resized_width)
2003         {
2004           real_requested_width = column->resized_width;
2005         }
2006       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2007         {
2008           real_requested_width = column->fixed_width;
2009         }
2010       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2011         {
2012           real_requested_width = MAX (column->requested_width, column->button_request);
2013         }
2014       else
2015         {
2016           real_requested_width = column->requested_width;
2017         }
2018
2019       if (column->min_width != -1)
2020         real_requested_width = MAX (real_requested_width, column->min_width);
2021       if (column->max_width != -1)
2022         real_requested_width = MIN (real_requested_width, column->max_width);
2023
2024       tree_view->priv->width += real_requested_width;
2025     }
2026
2027   if (tree_view->priv->tree == NULL)
2028     tree_view->priv->height = 0;
2029   else
2030     tree_view->priv->height = tree_view->priv->tree->root->offset;
2031 }
2032
2033 static void
2034 gtk_tree_view_size_request (GtkWidget      *widget,
2035                             GtkRequisition *requisition)
2036 {
2037   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2038   GList *tmp_list;
2039
2040   /* we validate GTK_TREE_VIEW_NUM_ROWS_PER_IDLE rows initially just to make
2041    * sure we have some size. In practice, with a lot of static lists, this
2042    * should get a good width.
2043    */
2044   do_validate_rows (tree_view, FALSE);
2045   gtk_tree_view_size_request_columns (tree_view);
2046   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2047
2048   requisition->width = tree_view->priv->width;
2049   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2050
2051   tmp_list = tree_view->priv->children;
2052
2053   while (tmp_list)
2054     {
2055       GtkTreeViewChild *child = tmp_list->data;
2056       GtkRequisition child_requisition;
2057
2058       tmp_list = tmp_list->next;
2059
2060       if (GTK_WIDGET_VISIBLE (child->widget))
2061         gtk_widget_size_request (child->widget, &child_requisition);
2062     }
2063 }
2064
2065
2066 static void
2067 invalidate_column (GtkTreeView       *tree_view,
2068                    GtkTreeViewColumn *column)
2069 {
2070   gint column_offset = 0;
2071   GList *list;
2072   GtkWidget *widget = GTK_WIDGET (tree_view);
2073   gboolean rtl;
2074
2075   if (!GTK_WIDGET_REALIZED (widget))
2076     return;
2077
2078   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2079   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2080        list;
2081        list = (rtl ? list->prev : list->next))
2082     {
2083       GtkTreeViewColumn *tmpcolumn = list->data;
2084       if (tmpcolumn == column)
2085         {
2086           GdkRectangle invalid_rect;
2087           
2088           invalid_rect.x = column_offset;
2089           invalid_rect.y = 0;
2090           invalid_rect.width = column->width;
2091           invalid_rect.height = widget->allocation.height;
2092           
2093           gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
2094           break;
2095         }
2096       
2097       column_offset += tmpcolumn->width;
2098     }
2099 }
2100
2101 static void
2102 invalidate_last_column (GtkTreeView *tree_view)
2103 {
2104   GList *last_column;
2105   gboolean rtl;
2106
2107   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2108
2109   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2110        last_column;
2111        last_column = (rtl ? last_column->next : last_column->prev))
2112     {
2113       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2114         {
2115           invalidate_column (tree_view, last_column->data);
2116           return;
2117         }
2118     }
2119 }
2120
2121 static gint
2122 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2123                                                     GtkTreeViewColumn *column)
2124 {
2125   gint real_requested_width;
2126
2127   if (column->use_resized_width)
2128     {
2129       real_requested_width = column->resized_width;
2130     }
2131   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2132     {
2133       real_requested_width = column->fixed_width;
2134     }
2135   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2136     {
2137       real_requested_width = MAX (column->requested_width, column->button_request);
2138     }
2139   else
2140     {
2141       real_requested_width = column->requested_width;
2142       if (real_requested_width < 0)
2143         real_requested_width = 0;
2144     }
2145
2146   if (column->min_width != -1)
2147     real_requested_width = MAX (real_requested_width, column->min_width);
2148   if (column->max_width != -1)
2149     real_requested_width = MIN (real_requested_width, column->max_width);
2150
2151   return real_requested_width;
2152 }
2153
2154 /* GtkWidget::size_allocate helper */
2155 static void
2156 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2157                                      gboolean  *width_changed)
2158 {
2159   GtkTreeView *tree_view;
2160   GList *list, *first_column, *last_column;
2161   GtkTreeViewColumn *column;
2162   GtkAllocation allocation;
2163   gint width = 0;
2164   gint extra, extra_per_column, extra_for_last;
2165   gint full_requested_width = 0;
2166   gint number_of_expand_columns = 0;
2167   gboolean column_changed = FALSE;
2168   gboolean rtl;
2169   gboolean update_expand;
2170   
2171   tree_view = GTK_TREE_VIEW (widget);
2172
2173   for (last_column = g_list_last (tree_view->priv->columns);
2174        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2175        last_column = last_column->prev)
2176     ;
2177   if (last_column == NULL)
2178     return;
2179
2180   for (first_column = g_list_first (tree_view->priv->columns);
2181        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2182        first_column = first_column->next)
2183     ;
2184
2185   allocation.y = 0;
2186   allocation.height = tree_view->priv->header_height;
2187
2188   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2189
2190   /* find out how many extra space and expandable columns we have */
2191   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2192     {
2193       column = (GtkTreeViewColumn *)list->data;
2194
2195       if (!column->visible)
2196         continue;
2197
2198       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2199
2200       if (column->expand)
2201         number_of_expand_columns++;
2202     }
2203
2204   /* Only update the expand value if the width of the widget has changed,
2205    * or the number of expand columns has changed, or if there are no expand
2206    * columns, or if we didn't have an size-allocation yet after the
2207    * last validated node.
2208    */
2209   update_expand = (width_changed && *width_changed == TRUE)
2210       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2211       || number_of_expand_columns == 0
2212       || tree_view->priv->post_validation_flag == TRUE;
2213
2214   tree_view->priv->post_validation_flag = FALSE;
2215
2216   if (!update_expand)
2217     {
2218       extra = tree_view->priv->last_extra_space;
2219       extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
2220     }
2221   else
2222     {
2223       extra = MAX (widget->allocation.width - full_requested_width, 0);
2224       extra_for_last = 0;
2225
2226       tree_view->priv->last_extra_space = extra;
2227     }
2228
2229   if (number_of_expand_columns > 0)
2230     extra_per_column = extra/number_of_expand_columns;
2231   else
2232     extra_per_column = 0;
2233
2234   if (update_expand)
2235     {
2236       tree_view->priv->last_extra_space_per_column = extra_per_column;
2237       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2238     }
2239
2240   for (list = (rtl ? last_column : first_column); 
2241        list != (rtl ? first_column->prev : last_column->next);
2242        list = (rtl ? list->prev : list->next)) 
2243     {
2244       gint real_requested_width = 0;
2245       gint old_width;
2246
2247       column = list->data;
2248       old_width = column->width;
2249
2250       if (!column->visible)
2251         continue;
2252
2253       /* We need to handle the dragged button specially.
2254        */
2255       if (column == tree_view->priv->drag_column)
2256         {
2257           GtkAllocation drag_allocation;
2258           gdk_drawable_get_size (tree_view->priv->drag_window,
2259                                  &(drag_allocation.width),
2260                                  &(drag_allocation.height));
2261           drag_allocation.x = 0;
2262           drag_allocation.y = 0;
2263           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2264                                     &drag_allocation);
2265           width += drag_allocation.width;
2266           continue;
2267         }
2268
2269       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2270
2271       allocation.x = width;
2272       column->width = real_requested_width;
2273
2274       if (column->expand)
2275         {
2276           if (number_of_expand_columns == 1)
2277             {
2278               /* We add the remander to the last column as
2279                * */
2280               column->width += extra;
2281             }
2282           else
2283             {
2284               column->width += extra_per_column;
2285               extra -= extra_per_column;
2286               number_of_expand_columns --;
2287             }
2288         }
2289       else if (number_of_expand_columns == 0 &&
2290                list == last_column)
2291         {
2292           column->width += extra;
2293         }
2294
2295       /* In addition to expand, the last column can get even more
2296        * extra space so all available space is filled up.
2297        */
2298       if (extra_for_last > 0 && list == last_column)
2299         column->width += extra_for_last;
2300
2301       g_object_notify (G_OBJECT (column), "width");
2302
2303       allocation.width = column->width;
2304       width += column->width;
2305
2306       if (column->width > old_width)
2307         column_changed = TRUE;
2308
2309       gtk_widget_size_allocate (column->button, &allocation);
2310
2311       if (column->window)
2312         gdk_window_move_resize (column->window,
2313                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2314                                 allocation.y,
2315                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2316     }
2317
2318   /* We change the width here.  The user might have been resizing columns,
2319    * so the total width of the tree view changes.
2320    */
2321   tree_view->priv->width = width;
2322   if (width_changed)
2323     *width_changed = TRUE;
2324
2325   if (column_changed)
2326     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2327 }
2328
2329
2330 static void
2331 gtk_tree_view_size_allocate (GtkWidget     *widget,
2332                              GtkAllocation *allocation)
2333 {
2334   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2335   GList *tmp_list;
2336   gboolean width_changed = FALSE;
2337   gint old_width = widget->allocation.width;
2338
2339   if (allocation->width != widget->allocation.width)
2340     width_changed = TRUE;
2341
2342   widget->allocation = *allocation;
2343
2344   tmp_list = tree_view->priv->children;
2345
2346   while (tmp_list)
2347     {
2348       GtkAllocation allocation;
2349
2350       GtkTreeViewChild *child = tmp_list->data;
2351       tmp_list = tmp_list->next;
2352
2353       /* totally ignore our child's requisition */
2354       allocation.x = child->x;
2355       allocation.y = child->y;
2356       allocation.width = child->width;
2357       allocation.height = child->height;
2358       gtk_widget_size_allocate (child->widget, &allocation);
2359     }
2360
2361   /* We size-allocate the columns first because the width of the
2362    * tree view (used in updating the adjustments below) might change.
2363    */
2364   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2365
2366   tree_view->priv->hadjustment->page_size = allocation->width;
2367   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2368   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2369   tree_view->priv->hadjustment->lower = 0;
2370   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2371
2372   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2373     {
2374       if (allocation->width < tree_view->priv->width)
2375         {
2376           if (tree_view->priv->init_hadjust_value)
2377             {
2378               tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2379               tree_view->priv->init_hadjust_value = FALSE;
2380             }
2381           else if (allocation->width != old_width)
2382             {
2383               tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2384             }
2385           else
2386             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);
2387         }
2388       else
2389         {
2390           tree_view->priv->hadjustment->value = 0;
2391           tree_view->priv->init_hadjust_value = TRUE;
2392         }
2393     }
2394   else
2395     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2396       tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2397
2398   gtk_adjustment_changed (tree_view->priv->hadjustment);
2399
2400   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2401   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2402   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2403   tree_view->priv->vadjustment->lower = 0;
2404   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2405
2406   gtk_adjustment_changed (tree_view->priv->vadjustment);
2407
2408   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2409   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2410     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2411   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2412     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2413                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2414   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2415     gtk_tree_view_top_row_to_dy (tree_view);
2416   else
2417     gtk_tree_view_dy_to_top_row (tree_view);
2418   
2419   if (GTK_WIDGET_REALIZED (widget))
2420     {
2421       gdk_window_move_resize (widget->window,
2422                               allocation->x, allocation->y,
2423                               allocation->width, allocation->height);
2424       gdk_window_move_resize (tree_view->priv->header_window,
2425                               - (gint) tree_view->priv->hadjustment->value,
2426                               0,
2427                               MAX (tree_view->priv->width, allocation->width),
2428                               tree_view->priv->header_height);
2429       gdk_window_move_resize (tree_view->priv->bin_window,
2430                               - (gint) tree_view->priv->hadjustment->value,
2431                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2432                               MAX (tree_view->priv->width, allocation->width),
2433                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2434     }
2435
2436   if (tree_view->priv->tree == NULL)
2437     invalidate_empty_focus (tree_view);
2438
2439   if (GTK_WIDGET_REALIZED (widget))
2440     {
2441       gboolean has_expand_column = FALSE;
2442       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2443         {
2444           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2445             {
2446               has_expand_column = TRUE;
2447               break;
2448             }
2449         }
2450
2451       /* This little hack only works if we have an LTR locale, and no column has the  */
2452       if (width_changed)
2453         {
2454           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2455               ! has_expand_column)
2456             invalidate_last_column (tree_view);
2457           else
2458             gtk_widget_queue_draw (widget);
2459         }
2460     }
2461 }
2462
2463 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2464 static void
2465 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2466 {
2467   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
2468     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2469   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2470 }
2471
2472 static inline gboolean
2473 row_is_separator (GtkTreeView *tree_view,
2474                   GtkTreeIter *iter,
2475                   GtkTreePath *path)
2476 {
2477   gboolean is_separator = FALSE;
2478
2479   if (tree_view->priv->row_separator_func)
2480     {
2481       GtkTreeIter tmpiter;
2482
2483       if (iter)
2484         tmpiter = *iter;
2485       else
2486         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2487
2488       is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
2489                                                               &tmpiter,
2490                                                               tree_view->priv->row_separator_data);
2491     }
2492
2493   return is_separator;
2494 }
2495
2496 static gboolean
2497 gtk_tree_view_button_press (GtkWidget      *widget,
2498                             GdkEventButton *event)
2499 {
2500   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2501   GList *list;
2502   GtkTreeViewColumn *column = NULL;
2503   gint i;
2504   GdkRectangle background_area;
2505   GdkRectangle cell_area;
2506   gint vertical_separator;
2507   gint horizontal_separator;
2508   gboolean path_is_selectable;
2509   gboolean rtl;
2510
2511   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2512   gtk_tree_view_stop_editing (tree_view, FALSE);
2513   gtk_widget_style_get (widget,
2514                         "vertical-separator", &vertical_separator,
2515                         "horizontal-separator", &horizontal_separator,
2516                         NULL);
2517
2518
2519   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2520    * we're done handling the button press.
2521    */
2522
2523   if (event->window == tree_view->priv->bin_window)
2524     {
2525       GtkRBNode *node;
2526       GtkRBTree *tree;
2527       GtkTreePath *path;
2528       gchar *path_string;
2529       gint depth;
2530       gint new_y;
2531       gint y_offset;
2532       gint dval;
2533       gint pre_val, aft_val;
2534       GtkTreeViewColumn *column = NULL;
2535       GtkCellRenderer *focus_cell = NULL;
2536       gint column_handled_click = FALSE;
2537       gboolean row_double_click = FALSE;
2538       gboolean rtl;
2539       gboolean node_selected;
2540
2541       /* Empty tree? */
2542       if (tree_view->priv->tree == NULL)
2543         {
2544           grab_focus_and_unset_draw_keyfocus (tree_view);
2545           return TRUE;
2546         }
2547
2548       /* are we in an arrow? */
2549       if (tree_view->priv->prelight_node &&
2550           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2551           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2552         {
2553           if (event->button == 1)
2554             {
2555               gtk_grab_add (widget);
2556               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2557               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2558               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2559                                         tree_view->priv->prelight_tree,
2560                                         tree_view->priv->prelight_node,
2561                                         event->x,
2562                                         event->y);
2563             }
2564
2565           grab_focus_and_unset_draw_keyfocus (tree_view);
2566           return TRUE;
2567         }
2568
2569       /* find the node that was clicked */
2570       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2571       if (new_y < 0)
2572         new_y = 0;
2573       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2574
2575       if (node == NULL)
2576         {
2577           /* We clicked in dead space */
2578           grab_focus_and_unset_draw_keyfocus (tree_view);
2579           return TRUE;
2580         }
2581
2582       /* Get the path and the node */
2583       path = _gtk_tree_view_find_path (tree_view, tree, node);
2584       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2585
2586       if (!path_is_selectable)
2587         {
2588           gtk_tree_path_free (path);
2589           grab_focus_and_unset_draw_keyfocus (tree_view);
2590           return TRUE;
2591         }
2592
2593       depth = gtk_tree_path_get_depth (path);
2594       background_area.y = y_offset + event->y;
2595       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2596       background_area.x = 0;
2597
2598
2599       /* Let the column have a chance at selecting it. */
2600       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2601       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2602            list; list = (rtl ? list->prev : list->next))
2603         {
2604           GtkTreeViewColumn *candidate = list->data;
2605
2606           if (!candidate->visible)
2607             continue;
2608
2609           background_area.width = candidate->width;
2610           if ((background_area.x > (gint) event->x) ||
2611               (background_area.x + background_area.width <= (gint) event->x))
2612             {
2613               background_area.x += background_area.width;
2614               continue;
2615             }
2616
2617           /* we found the focus column */
2618           column = candidate;
2619           cell_area = background_area;
2620           cell_area.width -= horizontal_separator;
2621           cell_area.height -= vertical_separator;
2622           cell_area.x += horizontal_separator/2;
2623           cell_area.y += vertical_separator/2;
2624           if (gtk_tree_view_is_expander_column (tree_view, column))
2625             {
2626               if (!rtl)
2627                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2628               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2629
2630               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2631                 {
2632                   if (!rtl)
2633                     cell_area.x += depth * tree_view->priv->expander_size;
2634                   cell_area.width -= depth * tree_view->priv->expander_size;
2635                 }
2636             }
2637           break;
2638         }
2639
2640       if (column == NULL)
2641         {
2642           gtk_tree_path_free (path);
2643           grab_focus_and_unset_draw_keyfocus (tree_view);
2644           return FALSE;
2645         }
2646
2647       tree_view->priv->focus_column = column;
2648
2649       /* decide if we edit */
2650       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2651           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2652         {
2653           GtkTreePath *anchor;
2654           GtkTreeIter iter;
2655
2656           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2657           gtk_tree_view_column_cell_set_cell_data (column,
2658                                                    tree_view->priv->model,
2659                                                    &iter,
2660                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2661                                                    node->children?TRUE:FALSE);
2662
2663           if (tree_view->priv->anchor)
2664             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2665           else
2666             anchor = NULL;
2667
2668           if ((anchor && !gtk_tree_path_compare (anchor, path))
2669               || !_gtk_tree_view_column_has_editable_cell (column))
2670             {
2671               GtkCellEditable *cell_editable = NULL;
2672
2673               /* FIXME: get the right flags */
2674               guint flags = 0;
2675
2676               path_string = gtk_tree_path_to_string (path);
2677
2678               if (_gtk_tree_view_column_cell_event (column,
2679                                                     &cell_editable,
2680                                                     (GdkEvent *)event,
2681                                                     path_string,
2682                                                     &background_area,
2683                                                     &cell_area, flags))
2684                 {
2685                   if (cell_editable != NULL)
2686                     {
2687                       gint left, right;
2688                       GdkRectangle area;
2689
2690                       area = cell_area;
2691                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2692
2693                       area.x += left;
2694                       area.width -= right + left;
2695
2696                       gtk_tree_view_real_start_editing (tree_view,
2697                                                         column,
2698                                                         path,
2699                                                         cell_editable,
2700                                                         &area,
2701                                                         (GdkEvent *)event,
2702                                                         flags);
2703                       g_free (path_string);
2704                       gtk_tree_path_free (path);
2705                       gtk_tree_path_free (anchor);
2706                       return TRUE;
2707                     }
2708                   column_handled_click = TRUE;
2709                 }
2710               g_free (path_string);
2711             }
2712           if (anchor)
2713             gtk_tree_path_free (anchor);
2714         }
2715
2716       /* select */
2717       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2718       pre_val = tree_view->priv->vadjustment->value;
2719
2720       /* we only handle selection modifications on the first button press
2721        */
2722       if (event->type == GDK_BUTTON_PRESS)
2723         {
2724           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2725             tree_view->priv->ctrl_pressed = TRUE;
2726           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2727             tree_view->priv->shift_pressed = TRUE;
2728
2729           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2730           if (focus_cell)
2731             gtk_tree_view_column_focus_cell (column, focus_cell);
2732
2733           if (event->state & GDK_CONTROL_MASK)
2734             {
2735               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2736               gtk_tree_view_real_toggle_cursor_row (tree_view);
2737             }
2738           else if (event->state & GDK_SHIFT_MASK)
2739             {
2740               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2741               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2742             }
2743           else
2744             {
2745               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2746             }
2747
2748           tree_view->priv->ctrl_pressed = FALSE;
2749           tree_view->priv->shift_pressed = FALSE;
2750         }
2751
2752       /* the treeview may have been scrolled because of _set_cursor,
2753        * correct here
2754        */
2755
2756       aft_val = tree_view->priv->vadjustment->value;
2757       dval = pre_val - aft_val;
2758
2759       cell_area.y += dval;
2760       background_area.y += dval;
2761
2762       /* Save press to possibly begin a drag
2763        */
2764       if (!column_handled_click &&
2765           !tree_view->priv->in_grab &&
2766           tree_view->priv->pressed_button < 0)
2767         {
2768           tree_view->priv->pressed_button = event->button;
2769           tree_view->priv->press_start_x = event->x;
2770           tree_view->priv->press_start_y = event->y;
2771
2772           if (tree_view->priv->rubber_banding_enable
2773               && !node_selected
2774               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2775             {
2776               tree_view->priv->press_start_y += tree_view->priv->dy;
2777               tree_view->priv->rubber_band_x = event->x;
2778               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2779               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2780
2781               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2782                 tree_view->priv->rubber_band_ctrl = TRUE;
2783               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2784                 tree_view->priv->rubber_band_shift = TRUE;
2785             }
2786         }
2787
2788       /* Test if a double click happened on the same row. */
2789       if (event->button == 1)
2790         {
2791           /* We also handle triple clicks here, because a user could have done
2792            * a first click and a second double click on different rows.
2793            */
2794           if ((event->type == GDK_2BUTTON_PRESS
2795                || event->type == GDK_3BUTTON_PRESS)
2796               && tree_view->priv->last_button_press)
2797             {
2798               GtkTreePath *lsc;
2799
2800               lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
2801
2802               if (lsc)
2803                 {
2804                   row_double_click = !gtk_tree_path_compare (lsc, path);
2805                   gtk_tree_path_free (lsc);
2806                 }
2807             }
2808
2809           if (row_double_click)
2810             {
2811               if (tree_view->priv->last_button_press)
2812                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2813               if (tree_view->priv->last_button_press_2)
2814                 gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
2815               tree_view->priv->last_button_press = NULL;
2816               tree_view->priv->last_button_press_2 = NULL;
2817             }
2818           else
2819             {
2820               if (tree_view->priv->last_button_press)
2821                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2822               tree_view->priv->last_button_press = tree_view->priv->last_button_press_2;
2823               tree_view->priv->last_button_press_2 = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
2824             }
2825         }
2826
2827       if (row_double_click)
2828         {
2829           gtk_grab_remove (widget);
2830           gtk_tree_view_row_activated (tree_view, path, column);
2831
2832           if (tree_view->priv->pressed_button == event->button)
2833             tree_view->priv->pressed_button = -1;
2834         }
2835
2836       gtk_tree_path_free (path);
2837
2838       /* If we activated the row through a double click we don't want to grab
2839        * focus back, as moving focus to another widget is pretty common.
2840        */
2841       if (!row_double_click)
2842         grab_focus_and_unset_draw_keyfocus (tree_view);
2843
2844       return TRUE;
2845     }
2846
2847   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2848    */
2849   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2850     {
2851       column = list->data;
2852       if (event->window == column->window &&
2853           column->resizable &&
2854           column->window)
2855         {
2856           gpointer drag_data;
2857
2858           if (event->type == GDK_2BUTTON_PRESS &&
2859               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2860             {
2861               column->use_resized_width = FALSE;
2862               _gtk_tree_view_column_autosize (tree_view, column);
2863               return TRUE;
2864             }
2865
2866           if (gdk_pointer_grab (column->window, FALSE,
2867                                 GDK_POINTER_MOTION_HINT_MASK |
2868                                 GDK_BUTTON1_MOTION_MASK |
2869                                 GDK_BUTTON_RELEASE_MASK,
2870                                 NULL, NULL, event->time))
2871             return FALSE;
2872
2873           gtk_grab_add (widget);
2874           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2875           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2876
2877           /* block attached dnd signal handler */
2878           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2879           if (drag_data)
2880             g_signal_handlers_block_matched (widget,
2881                                              G_SIGNAL_MATCH_DATA,
2882                                              0, 0, NULL, NULL,
2883                                              drag_data);
2884
2885           tree_view->priv->drag_pos = i;
2886           tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
2887
2888           if (!GTK_WIDGET_HAS_FOCUS (widget))
2889             gtk_widget_grab_focus (widget);
2890
2891           return TRUE;
2892         }
2893     }
2894   return FALSE;
2895 }
2896
2897 /* GtkWidget::button_release_event helper */
2898 static gboolean
2899 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2900                                           GdkEventButton *event)
2901 {
2902   GtkTreeView *tree_view;
2903   GList *l;
2904   gboolean rtl;
2905
2906   tree_view = GTK_TREE_VIEW (widget);
2907
2908   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2909   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2910   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2911
2912   /* Move the button back */
2913   g_object_ref (tree_view->priv->drag_column->button);
2914   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2915   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2916   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2917   g_object_unref (tree_view->priv->drag_column->button);
2918   gtk_widget_queue_resize (widget);
2919   if (tree_view->priv->drag_column->resizable)
2920     {
2921       gdk_window_raise (tree_view->priv->drag_column->window);
2922       gdk_window_show (tree_view->priv->drag_column->window);
2923     }
2924   else
2925     gdk_window_hide (tree_view->priv->drag_column->window);
2926
2927   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2928
2929   if (rtl)
2930     {
2931       if (tree_view->priv->cur_reorder &&
2932           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2933         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2934                                          tree_view->priv->cur_reorder->right_column);
2935     }
2936   else
2937     {
2938       if (tree_view->priv->cur_reorder &&
2939           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2940         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2941                                          tree_view->priv->cur_reorder->left_column);
2942     }
2943   tree_view->priv->drag_column = NULL;
2944   gdk_window_hide (tree_view->priv->drag_window);
2945
2946   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
2947     g_slice_free (GtkTreeViewColumnReorder, l->data);
2948   g_list_free (tree_view->priv->column_drag_info);
2949   tree_view->priv->column_drag_info = NULL;
2950   tree_view->priv->cur_reorder = NULL;
2951
2952   if (tree_view->priv->drag_highlight_window)
2953     gdk_window_hide (tree_view->priv->drag_highlight_window);
2954
2955   /* Reset our flags */
2956   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
2957   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
2958
2959   return TRUE;
2960 }
2961
2962 /* GtkWidget::button_release_event helper */
2963 static gboolean
2964 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
2965                                             GdkEventButton *event)
2966 {
2967   GtkTreeView *tree_view;
2968   gpointer drag_data;
2969
2970   tree_view = GTK_TREE_VIEW (widget);
2971
2972   tree_view->priv->drag_pos = -1;
2973
2974   /* unblock attached dnd signal handler */
2975   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2976   if (drag_data)
2977     g_signal_handlers_unblock_matched (widget,
2978                                        G_SIGNAL_MATCH_DATA,
2979                                        0, 0, NULL, NULL,
2980                                        drag_data);
2981
2982   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2983   gtk_grab_remove (widget);
2984   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
2985                               event->time);
2986   return TRUE;
2987 }
2988
2989 static gboolean
2990 gtk_tree_view_button_release (GtkWidget      *widget,
2991                               GdkEventButton *event)
2992 {
2993   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2994
2995   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2996     return gtk_tree_view_button_release_drag_column (widget, event);
2997
2998   if (tree_view->priv->rubber_band_status)
2999     gtk_tree_view_stop_rubber_band (tree_view);
3000
3001   if (tree_view->priv->pressed_button == event->button)
3002     tree_view->priv->pressed_button = -1;
3003
3004   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3005     return gtk_tree_view_button_release_column_resize (widget, event);
3006
3007   if (tree_view->priv->button_pressed_node == NULL)
3008     return FALSE;
3009
3010   if (event->button == 1)
3011     {
3012       gtk_grab_remove (widget);
3013       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3014           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3015         {
3016           GtkTreePath *path = NULL;
3017
3018           path = _gtk_tree_view_find_path (tree_view,
3019                                            tree_view->priv->button_pressed_tree,
3020                                            tree_view->priv->button_pressed_node);
3021           /* Actually activate the node */
3022           if (tree_view->priv->button_pressed_node->children == NULL)
3023             gtk_tree_view_real_expand_row (tree_view, path,
3024                                            tree_view->priv->button_pressed_tree,
3025                                            tree_view->priv->button_pressed_node,
3026                                            FALSE, TRUE);
3027           else
3028             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3029                                              tree_view->priv->button_pressed_tree,
3030                                              tree_view->priv->button_pressed_node, TRUE);
3031           gtk_tree_path_free (path);
3032         }
3033
3034       tree_view->priv->button_pressed_tree = NULL;
3035       tree_view->priv->button_pressed_node = NULL;
3036     }
3037
3038   return TRUE;
3039 }
3040
3041 static gboolean
3042 gtk_tree_view_grab_broken (GtkWidget          *widget,
3043                            GdkEventGrabBroken *event)
3044 {
3045   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3046
3047   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3048     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3049
3050   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3051     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3052
3053   return TRUE;
3054 }
3055
3056 #if 0
3057 static gboolean
3058 gtk_tree_view_configure (GtkWidget *widget,
3059                          GdkEventConfigure *event)
3060 {
3061   GtkTreeView *tree_view;
3062
3063   tree_view = GTK_TREE_VIEW (widget);
3064   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3065
3066   return FALSE;
3067 }
3068 #endif
3069
3070 /* GtkWidget::motion_event function set.
3071  */
3072
3073 static gboolean
3074 coords_are_over_arrow (GtkTreeView *tree_view,
3075                        GtkRBTree   *tree,
3076                        GtkRBNode   *node,
3077                        /* these are in bin window coords */
3078                        gint         x,
3079                        gint         y)
3080 {
3081   GdkRectangle arrow;
3082   gint x2;
3083
3084   if (!GTK_WIDGET_REALIZED (tree_view))
3085     return FALSE;
3086
3087   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3088     return FALSE;
3089
3090   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3091
3092   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3093
3094   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3095
3096   arrow.width = x2 - arrow.x;
3097
3098   return (x >= arrow.x &&
3099           x < (arrow.x + arrow.width) &&
3100           y >= arrow.y &&
3101           y < (arrow.y + arrow.height));
3102 }
3103
3104 static gboolean
3105 auto_expand_timeout (gpointer data)
3106 {
3107   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3108   GtkTreePath *path;
3109
3110   if (tree_view->priv->prelight_node)
3111     {
3112       path = _gtk_tree_view_find_path (tree_view,
3113                                        tree_view->priv->prelight_tree,
3114                                        tree_view->priv->prelight_node);   
3115
3116       if (tree_view->priv->prelight_node->children)
3117         gtk_tree_view_collapse_row (tree_view, path);
3118       else
3119         gtk_tree_view_expand_row (tree_view, path, FALSE);
3120
3121       gtk_tree_path_free (path);
3122     }
3123
3124   tree_view->priv->auto_expand_timeout = 0;
3125
3126   return FALSE;
3127 }
3128
3129 static void
3130 remove_auto_expand_timeout (GtkTreeView *tree_view)
3131 {
3132   if (tree_view->priv->auto_expand_timeout != 0)
3133     {
3134       g_source_remove (tree_view->priv->auto_expand_timeout);
3135       tree_view->priv->auto_expand_timeout = 0;
3136     }
3137 }
3138
3139 static void
3140 do_prelight (GtkTreeView *tree_view,
3141              GtkRBTree   *tree,
3142              GtkRBNode   *node,
3143              /* these are in bin_window coords */
3144              gint         x,
3145              gint         y)
3146 {
3147   if (tree_view->priv->prelight_tree == tree &&
3148       tree_view->priv->prelight_node == node)
3149     {
3150       /*  We are still on the same node,
3151           but we might need to take care of the arrow  */
3152
3153       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3154         {
3155           gboolean over_arrow;
3156           gboolean flag_set;
3157
3158           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3159           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3160                                              GTK_TREE_VIEW_ARROW_PRELIT);
3161
3162           if (over_arrow != flag_set)
3163             {
3164               if (over_arrow)
3165                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3166                                         GTK_TREE_VIEW_ARROW_PRELIT);
3167               else
3168                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3169                                           GTK_TREE_VIEW_ARROW_PRELIT);
3170
3171               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3172             }
3173         }
3174
3175       return;
3176     }
3177
3178   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3179     {
3180       /*  Unprelight the old node and arrow  */
3181
3182       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3183                              GTK_RBNODE_IS_PRELIT);
3184
3185       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3186           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3187         {
3188           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3189           
3190           gtk_tree_view_draw_arrow (tree_view,
3191                                     tree_view->priv->prelight_tree,
3192                                     tree_view->priv->prelight_node,
3193                                     x,
3194                                     y);
3195         }
3196
3197       _gtk_tree_view_queue_draw_node (tree_view,
3198                                       tree_view->priv->prelight_tree,
3199                                       tree_view->priv->prelight_node,
3200                                       NULL);
3201     }
3202
3203
3204   if (tree_view->priv->hover_expand)
3205     remove_auto_expand_timeout (tree_view);
3206
3207   /*  Set the new prelight values  */
3208   tree_view->priv->prelight_node = node;
3209   tree_view->priv->prelight_tree = tree;
3210
3211   if (!node || !tree)
3212     return;
3213
3214   /*  Prelight the new node and arrow  */
3215
3216   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3217       && coords_are_over_arrow (tree_view, tree, node, x, y))
3218     {
3219       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3220
3221       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3222     }
3223
3224   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3225
3226   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3227
3228   if (tree_view->priv->hover_expand)
3229     {
3230       tree_view->priv->auto_expand_timeout = 
3231         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3232     }
3233 }
3234
3235 static void
3236 prelight_or_select (GtkTreeView *tree_view,
3237                     GtkRBTree   *tree,
3238                     GtkRBNode   *node,
3239                     /* these are in bin_window coords */
3240                     gint         x,
3241                     gint         y)
3242 {
3243   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3244   
3245   if (tree_view->priv->hover_selection &&
3246       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3247       !(tree_view->priv->edited_column &&
3248         tree_view->priv->edited_column->editable_widget))
3249     {
3250       if (node)
3251         {
3252           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3253             {
3254               GtkTreePath *path;
3255               
3256               path = _gtk_tree_view_find_path (tree_view, tree, node);
3257               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3258               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3259                 {
3260                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3261                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3262                 }
3263               gtk_tree_path_free (path);
3264             }
3265         }
3266
3267       else if (mode == GTK_SELECTION_SINGLE)
3268         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3269     }
3270
3271     do_prelight (tree_view, tree, node, x, y);
3272 }
3273
3274 static void
3275 ensure_unprelighted (GtkTreeView *tree_view)
3276 {
3277   do_prelight (tree_view,
3278                NULL, NULL,
3279                -1000, -1000); /* coords not possibly over an arrow */
3280
3281   g_assert (tree_view->priv->prelight_node == NULL);
3282 }
3283
3284
3285
3286
3287 /* Our motion arrow is either a box (in the case of the original spot)
3288  * or an arrow.  It is expander_size wide.
3289  */
3290 /*
3291  * 11111111111111
3292  * 01111111111110
3293  * 00111111111100
3294  * 00011111111000
3295  * 00001111110000
3296  * 00000111100000
3297  * 00000111100000
3298  * 00000111100000
3299  * ~ ~ ~ ~ ~ ~ ~
3300  * 00000111100000
3301  * 00000111100000
3302  * 00000111100000
3303  * 00001111110000
3304  * 00011111111000
3305  * 00111111111100
3306  * 01111111111110
3307  * 11111111111111
3308  */
3309
3310 static void
3311 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3312 {
3313   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3314   GtkWidget *widget = GTK_WIDGET (tree_view);
3315   GdkBitmap *mask = NULL;
3316   gint x;
3317   gint y;
3318   gint width;
3319   gint height;
3320   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3321   GdkWindowAttr attributes;
3322   guint attributes_mask;
3323
3324   if (!reorder ||
3325       reorder->left_column == tree_view->priv->drag_column ||
3326       reorder->right_column == tree_view->priv->drag_column)
3327     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3328   else if (reorder->left_column || reorder->right_column)
3329     {
3330       GdkRectangle visible_rect;
3331       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3332       if (reorder->left_column)
3333         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
3334       else
3335         x = reorder->right_column->button->allocation.x;
3336
3337       if (x < visible_rect.x)
3338         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3339       else if (x > visible_rect.x + visible_rect.width)
3340         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3341       else
3342         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3343     }
3344
3345   /* We want to draw the rectangle over the initial location. */
3346   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3347     {
3348       GdkGC *gc;
3349       GdkColor col;
3350
3351       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3352         {
3353           if (tree_view->priv->drag_highlight_window)
3354             {
3355               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3356                                         NULL);
3357               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3358             }
3359
3360           attributes.window_type = GDK_WINDOW_CHILD;
3361           attributes.wclass = GDK_INPUT_OUTPUT;
3362           attributes.x = tree_view->priv->drag_column_x;
3363           attributes.y = 0;
3364           width = attributes.width = tree_view->priv->drag_column->button->allocation.width;
3365           height = attributes.height = tree_view->priv->drag_column->button->allocation.height;
3366           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3367           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3368           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3369           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3370           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3371           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3372
3373           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3374           gc = gdk_gc_new (mask);
3375           col.pixel = 1;
3376           gdk_gc_set_foreground (gc, &col);
3377           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3378           col.pixel = 0;
3379           gdk_gc_set_foreground(gc, &col);
3380           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
3381           g_object_unref (gc);
3382
3383           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3384                                          mask, 0, 0);
3385           if (mask) g_object_unref (mask);
3386           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3387         }
3388     }
3389   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3390     {
3391       gint i, j = 1;
3392       GdkGC *gc;
3393       GdkColor col;
3394
3395       width = tree_view->priv->expander_size;
3396
3397       /* Get x, y, width, height of arrow */
3398       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3399       if (reorder->left_column)
3400         {
3401           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
3402           height = reorder->left_column->button->allocation.height;
3403         }
3404       else
3405         {
3406           x += reorder->right_column->button->allocation.x - width/2;
3407           height = reorder->right_column->button->allocation.height;
3408         }
3409       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3410       height += tree_view->priv->expander_size;
3411
3412       /* Create the new window */
3413       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3414         {
3415           if (tree_view->priv->drag_highlight_window)
3416             {
3417               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3418                                         NULL);
3419               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3420             }
3421
3422           attributes.window_type = GDK_WINDOW_TEMP;
3423           attributes.wclass = GDK_INPUT_OUTPUT;
3424           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3425           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3426           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3427           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3428           attributes.x = x;
3429           attributes.y = y;
3430           attributes.width = width;
3431           attributes.height = height;
3432           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3433                                                                    &attributes, attributes_mask);
3434           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3435
3436           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3437           gc = gdk_gc_new (mask);
3438           col.pixel = 1;
3439           gdk_gc_set_foreground (gc, &col);
3440           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3441
3442           /* Draw the 2 arrows as per above */
3443           col.pixel = 0;
3444           gdk_gc_set_foreground (gc, &col);
3445           for (i = 0; i < width; i ++)
3446             {
3447               if (i == (width/2 - 1))
3448                 continue;
3449               gdk_draw_line (mask, gc, i, j, i, height - j);
3450               if (i < (width/2 - 1))
3451                 j++;
3452               else
3453                 j--;
3454             }
3455           g_object_unref (gc);
3456           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3457                                          mask, 0, 0);
3458           if (mask) g_object_unref (mask);
3459         }
3460
3461       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3462       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3463     }
3464   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3465            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3466     {
3467       gint i, j = 1;
3468       GdkGC *gc;
3469       GdkColor col;
3470
3471       width = tree_view->priv->expander_size;
3472
3473       /* Get x, y, width, height of arrow */
3474       width = width/2; /* remember, the arrow only takes half the available width */
3475       gdk_window_get_origin (widget->window, &x, &y);
3476       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3477         x += widget->allocation.width - width;
3478
3479       if (reorder->left_column)
3480         height = reorder->left_column->button->allocation.height;
3481       else
3482         height = reorder->right_column->button->allocation.height;
3483
3484       y -= tree_view->priv->expander_size;
3485       height += 2*tree_view->priv->expander_size;
3486
3487       /* Create the new window */
3488       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3489           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3490         {
3491           if (tree_view->priv->drag_highlight_window)
3492             {
3493               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3494                                         NULL);
3495               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3496             }
3497
3498           attributes.window_type = GDK_WINDOW_TEMP;
3499           attributes.wclass = GDK_INPUT_OUTPUT;
3500           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3501           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3502           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3503           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3504           attributes.x = x;
3505           attributes.y = y;
3506           attributes.width = width;
3507           attributes.height = height;
3508           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3509           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3510
3511           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3512           gc = gdk_gc_new (mask);
3513           col.pixel = 1;
3514           gdk_gc_set_foreground (gc, &col);
3515           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3516
3517           /* Draw the 2 arrows as per above */
3518           col.pixel = 0;
3519           gdk_gc_set_foreground (gc, &col);
3520           j = tree_view->priv->expander_size;
3521           for (i = 0; i < width; i ++)
3522             {
3523               gint k;
3524               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3525                 k = width - i - 1;
3526               else
3527                 k = i;
3528               gdk_draw_line (mask, gc, k, j, k, height - j);
3529               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
3530               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
3531               j--;
3532             }
3533           g_object_unref (gc);
3534           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3535                                          mask, 0, 0);
3536           if (mask) g_object_unref (mask);
3537         }
3538
3539       tree_view->priv->drag_column_window_state = arrow_type;
3540       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3541    }
3542   else
3543     {
3544       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3545       gdk_window_hide (tree_view->priv->drag_highlight_window);
3546       return;
3547     }
3548
3549   gdk_window_show (tree_view->priv->drag_highlight_window);
3550   gdk_window_raise (tree_view->priv->drag_highlight_window);
3551 }
3552
3553 static gboolean
3554 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3555                                     GdkEventMotion *event)
3556 {
3557   gint x;
3558   gint new_width;
3559   GtkTreeViewColumn *column;
3560   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3561
3562   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3563
3564   if (event->is_hint || event->window != widget->window)
3565     gtk_widget_get_pointer (widget, &x, NULL);
3566   else
3567     x = event->x;
3568
3569   if (tree_view->priv->hadjustment)
3570     x += tree_view->priv->hadjustment->value;
3571
3572   new_width = gtk_tree_view_new_column_width (tree_view,
3573                                               tree_view->priv->drag_pos, &x);
3574   if (x != tree_view->priv->x_drag &&
3575       (new_width != column->fixed_width))
3576     {
3577       column->use_resized_width = TRUE;
3578       column->resized_width = new_width;
3579       if (column->expand)
3580         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3581       gtk_widget_queue_resize (widget);
3582     }
3583
3584   return FALSE;
3585 }
3586
3587
3588 static void
3589 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3590 {
3591   GtkTreeViewColumnReorder *reorder = NULL;
3592   GList *list;
3593   gint mouse_x;
3594
3595   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3596   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3597     {
3598       reorder = (GtkTreeViewColumnReorder *) list->data;
3599       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3600         break;
3601       reorder = NULL;
3602     }
3603
3604   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3605       return;*/
3606
3607   tree_view->priv->cur_reorder = reorder;
3608   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3609 }
3610
3611 static void
3612 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3613 {
3614   GdkRectangle visible_rect;
3615   gint y;
3616   gint offset;
3617
3618   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3619   y += tree_view->priv->dy;
3620
3621   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3622
3623   /* see if we are near the edge. */
3624   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3625   if (offset > 0)
3626     {
3627       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3628       if (offset < 0)
3629         return;
3630     }
3631
3632   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3633                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3634 }
3635
3636 static gboolean
3637 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3638 {
3639   GdkRectangle visible_rect;
3640   gint x;
3641   gint offset;
3642
3643   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3644
3645   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3646
3647   /* See if we are near the edge. */
3648   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3649   if (offset > 0)
3650     {
3651       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3652       if (offset < 0)
3653         return TRUE;
3654     }
3655   offset = offset/3;
3656
3657   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3658                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3659
3660   return TRUE;
3661
3662 }
3663
3664 static gboolean
3665 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3666                                   GdkEventMotion *event)
3667 {
3668   GtkTreeView *tree_view = (GtkTreeView *) widget;
3669   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3670   gint x, y;
3671
3672   /* Sanity Check */
3673   if ((column == NULL) ||
3674       (event->window != tree_view->priv->drag_window))
3675     return FALSE;
3676
3677   /* Handle moving the header */
3678   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3679   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3680              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
3681   gdk_window_move (tree_view->priv->drag_window, x, y);
3682   
3683   /* autoscroll, if needed */
3684   gtk_tree_view_horizontal_autoscroll (tree_view);
3685   /* Update the current reorder position and arrow; */
3686   gtk_tree_view_update_current_reorder (tree_view);
3687
3688   return TRUE;
3689 }
3690
3691 static void
3692 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3693 {
3694   remove_scroll_timeout (tree_view);
3695   gtk_grab_remove (GTK_WIDGET (tree_view));
3696
3697   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3698     {
3699       GtkTreePath *tmp_path;
3700
3701       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3702
3703       /* The anchor path should be set to the start path */
3704       tmp_path = _gtk_tree_view_find_path (tree_view,
3705                                            tree_view->priv->rubber_band_start_tree,
3706                                            tree_view->priv->rubber_band_start_node);
3707
3708       if (tree_view->priv->anchor)
3709         gtk_tree_row_reference_free (tree_view->priv->anchor);
3710
3711       tree_view->priv->anchor =
3712         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3713                                           tree_view->priv->model,
3714                                           tmp_path);
3715
3716       gtk_tree_path_free (tmp_path);
3717
3718       /* ... and the cursor to the end path */
3719       tmp_path = _gtk_tree_view_find_path (tree_view,
3720                                            tree_view->priv->rubber_band_end_tree,
3721                                            tree_view->priv->rubber_band_end_node);
3722       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3723       gtk_tree_path_free (tmp_path);
3724
3725       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3726     }
3727
3728   /* Clear status variables */
3729   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3730   tree_view->priv->rubber_band_shift = 0;
3731   tree_view->priv->rubber_band_ctrl = 0;
3732
3733   tree_view->priv->rubber_band_start_node = NULL;
3734   tree_view->priv->rubber_band_start_tree = NULL;
3735   tree_view->priv->rubber_band_end_node = NULL;
3736   tree_view->priv->rubber_band_end_tree = NULL;
3737 }
3738
3739 static void
3740 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3741                                                  GtkRBTree   *start_tree,
3742                                                  GtkRBNode   *start_node,
3743                                                  GtkRBTree   *end_tree,
3744                                                  GtkRBNode   *end_node,
3745                                                  gboolean     select,
3746                                                  gboolean     skip_start,
3747                                                  gboolean     skip_end)
3748 {
3749   if (start_node == end_node)
3750     return;
3751
3752   /* We skip the first node and jump inside the loop */
3753   if (skip_start)
3754     goto skip_first;
3755
3756   do
3757     {
3758       /* Small optimization by assuming insensitive nodes are never
3759        * selected.
3760        */
3761       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3762         {
3763           GtkTreePath *path;
3764           gboolean selectable;
3765
3766           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3767           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3768           gtk_tree_path_free (path);
3769
3770           if (!selectable)
3771             goto node_not_selectable;
3772         }
3773
3774       if (select)
3775         {
3776           if (tree_view->priv->rubber_band_shift)
3777             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3778           else if (tree_view->priv->rubber_band_ctrl)
3779             {
3780               /* Toggle the selection state */
3781               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3782                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3783               else
3784                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3785             }
3786           else
3787             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3788         }
3789       else
3790         {
3791           /* Mirror the above */
3792           if (tree_view->priv->rubber_band_shift)
3793             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3794           else if (tree_view->priv->rubber_band_ctrl)
3795             {
3796               /* Toggle the selection state */
3797               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3798                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3799               else
3800                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3801             }
3802           else
3803             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3804         }
3805
3806       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3807
3808 node_not_selectable:
3809       if (start_node == end_node)
3810         break;
3811
3812 skip_first:
3813
3814       if (start_node->children)
3815         {
3816           start_tree = start_node->children;
3817           start_node = start_tree->root;
3818           while (start_node->left != start_tree->nil)
3819             start_node = start_node->left;
3820         }
3821       else
3822         {
3823           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3824
3825           if (!start_tree)
3826             /* Ran out of tree */
3827             break;
3828         }
3829
3830       if (skip_end && start_node == end_node)
3831         break;
3832     }
3833   while (TRUE);
3834 }
3835
3836 static void
3837 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3838 {
3839   GtkRBTree *start_tree, *end_tree;
3840   GtkRBNode *start_node, *end_node;
3841
3842   _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);
3843   _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);
3844
3845   /* Handle the start area first */
3846   if (!tree_view->priv->rubber_band_start_node)
3847     {
3848       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3849                                                        start_tree,
3850                                                        start_node,
3851                                                        end_tree,
3852                                                        end_node,
3853                                                        TRUE,
3854                                                        FALSE,
3855                                                        FALSE);
3856     }
3857   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3858            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3859     {
3860       /* New node is above the old one; selection became bigger */
3861       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3862                                                        start_tree,
3863                                                        start_node,
3864                                                        tree_view->priv->rubber_band_start_tree,
3865                                                        tree_view->priv->rubber_band_start_node,
3866                                                        TRUE,
3867                                                        FALSE,
3868                                                        TRUE);
3869     }
3870   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3871            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3872     {
3873       /* New node is below the old one; selection became smaller */
3874       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3875                                                        tree_view->priv->rubber_band_start_tree,
3876                                                        tree_view->priv->rubber_band_start_node,
3877                                                        start_tree,
3878                                                        start_node,
3879                                                        FALSE,
3880                                                        FALSE,
3881                                                        TRUE);
3882     }
3883
3884   tree_view->priv->rubber_band_start_tree = start_tree;
3885   tree_view->priv->rubber_band_start_node = start_node;
3886
3887   /* Next, handle the end area */
3888   if (!tree_view->priv->rubber_band_end_node)
3889     {
3890       /* In the event this happens, start_node was also NULL; this case is
3891        * handled above.
3892        */
3893     }
3894   else if (!end_node)
3895     {
3896       /* Find the last node in the tree */
3897       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3898                                &end_tree, &end_node);
3899
3900       /* Selection reached end of the tree */
3901       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3902                                                        tree_view->priv->rubber_band_end_tree,
3903                                                        tree_view->priv->rubber_band_end_node,
3904                                                        end_tree,
3905                                                        end_node,
3906                                                        TRUE,
3907                                                        TRUE,
3908                                                        FALSE);
3909     }
3910   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3911            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3912     {
3913       /* New node is below the old one; selection became bigger */
3914       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3915                                                        tree_view->priv->rubber_band_end_tree,
3916                                                        tree_view->priv->rubber_band_end_node,
3917                                                        end_tree,
3918                                                        end_node,
3919                                                        TRUE,
3920                                                        TRUE,
3921                                                        FALSE);
3922     }
3923   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
3924            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3925     {
3926       /* New node is above the old one; selection became smaller */
3927       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3928                                                        end_tree,
3929                                                        end_node,
3930                                                        tree_view->priv->rubber_band_end_tree,
3931                                                        tree_view->priv->rubber_band_end_node,
3932                                                        FALSE,
3933                                                        TRUE,
3934                                                        FALSE);
3935     }
3936
3937   tree_view->priv->rubber_band_end_tree = end_tree;
3938   tree_view->priv->rubber_band_end_node = end_node;
3939 }
3940
3941 static void
3942 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
3943 {
3944   gint x, y;
3945   GdkRectangle old_area;
3946   GdkRectangle new_area;
3947   GdkRectangle common;
3948   GdkRegion *invalid_region;
3949
3950   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
3951   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
3952   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
3953   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
3954
3955   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
3956
3957   x = MAX (x, 0);
3958   y = MAX (y, 0) + tree_view->priv->dy;
3959
3960   new_area.x = MIN (tree_view->priv->press_start_x, x);
3961   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
3962   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
3963   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
3964
3965   invalid_region = gdk_region_rectangle (&old_area);
3966   gdk_region_union_with_rect (invalid_region, &new_area);
3967
3968   gdk_rectangle_intersect (&old_area, &new_area, &common);
3969   if (common.width > 2 && common.height > 2)
3970     {
3971       GdkRegion *common_region;
3972
3973       /* make sure the border is invalidated */
3974       common.x += 1;
3975       common.y += 1;
3976       common.width -= 2;
3977       common.height -= 2;
3978
3979       common_region = gdk_region_rectangle (&common);
3980
3981       gdk_region_subtract (invalid_region, common_region);
3982       gdk_region_destroy (common_region);
3983     }
3984
3985   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
3986
3987   gdk_region_destroy (invalid_region);
3988
3989   tree_view->priv->rubber_band_x = x;
3990   tree_view->priv->rubber_band_y = y;
3991
3992   gtk_tree_view_update_rubber_band_selection (tree_view);
3993 }
3994
3995 static void
3996 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
3997                                 GdkRectangle *area)
3998 {
3999   cairo_t *cr;
4000   GdkRectangle rect;
4001   GdkRectangle rubber_rect;
4002
4003   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4004   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4005   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4006   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4007
4008   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
4009     return;
4010
4011   cr = gdk_cairo_create (tree_view->priv->bin_window);
4012   cairo_set_line_width (cr, 1.0);
4013
4014   cairo_set_source_rgba (cr,
4015                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4016                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4017                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
4018                          .25);
4019
4020   gdk_cairo_rectangle (cr, &rect);
4021   cairo_clip (cr);
4022   cairo_paint (cr);
4023
4024   cairo_set_source_rgb (cr,
4025                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4026                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4027                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
4028
4029   cairo_rectangle (cr,
4030                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4031                    rubber_rect.width - 1, rubber_rect.height - 1);
4032   cairo_stroke (cr);
4033
4034   cairo_destroy (cr);
4035 }
4036
4037 static gboolean
4038 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4039                                  GdkEventMotion *event)
4040 {
4041   GtkTreeView *tree_view;
4042   GtkRBTree *tree;
4043   GtkRBNode *node;
4044   gint new_y;
4045
4046   tree_view = (GtkTreeView *) widget;
4047
4048   if (tree_view->priv->tree == NULL)
4049     return FALSE;
4050
4051   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4052     {
4053       gtk_grab_add (GTK_WIDGET (tree_view));
4054       gtk_tree_view_update_rubber_band (tree_view);
4055
4056       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4057     }
4058   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4059     {
4060       gtk_tree_view_update_rubber_band (tree_view);
4061
4062       add_scroll_timeout (tree_view);
4063     }
4064
4065   /* only check for an initiated drag when a button is pressed */
4066   if (tree_view->priv->pressed_button >= 0
4067       && !tree_view->priv->rubber_band_status)
4068     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4069
4070   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4071   if (new_y < 0)
4072     new_y = 0;
4073
4074   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4075
4076   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4077   if ((tree_view->priv->button_pressed_node != NULL) &&
4078       (tree_view->priv->button_pressed_node != node))
4079     node = NULL;
4080
4081   prelight_or_select (tree_view, tree, node, event->x, event->y);
4082
4083   return TRUE;
4084 }
4085
4086 static gboolean
4087 gtk_tree_view_motion (GtkWidget      *widget,
4088                       GdkEventMotion *event)
4089 {
4090   GtkTreeView *tree_view;
4091
4092   tree_view = (GtkTreeView *) widget;
4093
4094   /* Resizing a column */
4095   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4096     return gtk_tree_view_motion_resize_column (widget, event);
4097
4098   /* Drag column */
4099   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4100     return gtk_tree_view_motion_drag_column (widget, event);
4101
4102   /* Sanity check it */
4103   if (event->window == tree_view->priv->bin_window)
4104     return gtk_tree_view_motion_bin_window (widget, event);
4105
4106   return FALSE;
4107 }
4108
4109 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4110  * the tree is empty.
4111  */
4112 static void
4113 invalidate_empty_focus (GtkTreeView *tree_view)
4114 {
4115   GdkRectangle area;
4116
4117   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4118     return;
4119
4120   area.x = 0;
4121   area.y = 0;
4122   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4123   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4124 }
4125
4126 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4127  * is empty.
4128  */
4129 static void
4130 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4131 {
4132   gint w, h;
4133
4134   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4135     return;
4136
4137   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4138
4139   w -= 2;
4140   h -= 2;
4141
4142   if (w > 0 && h > 0)
4143     gtk_paint_focus (GTK_WIDGET (tree_view)->style,
4144                      tree_view->priv->bin_window,
4145                      GTK_WIDGET_STATE (tree_view),
4146                      clip_area,
4147                      GTK_WIDGET (tree_view),
4148                      NULL,
4149                      1, 1, w, h);
4150 }
4151
4152 static void
4153 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4154                                GdkEventExpose *event,
4155                                gint            n_visible_columns)
4156 {
4157   GList *list = tree_view->priv->columns;
4158   gint i = 0;
4159   gint current_x = 0;
4160
4161   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4162       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4163     return;
4164
4165   /* Only draw the lines for visible rows and columns */
4166   for (list = tree_view->priv->columns; list; list = list->next, i++)
4167     {
4168       GtkTreeViewColumn *column = list->data;
4169
4170       /* We don't want a line for the last column */
4171       if (i == n_visible_columns - 1)
4172         break;
4173
4174       if (! column->visible)
4175         continue;
4176
4177       current_x += column->width;
4178
4179       gdk_draw_line (event->window,
4180                      tree_view->priv->grid_line_gc,
4181                      current_x - 1, 0,
4182                      current_x - 1, tree_view->priv->height);
4183     }
4184 }
4185
4186 /* Warning: Very scary function.
4187  * Modify at your own risk
4188  *
4189  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4190  * FIXME: It's not...
4191  */
4192 static gboolean
4193 gtk_tree_view_bin_expose (GtkWidget      *widget,
4194                           GdkEventExpose *event)
4195 {
4196   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4197   GtkTreePath *path;
4198   GtkRBTree *tree;
4199   GList *list;
4200   GtkRBNode *node;
4201   GtkRBNode *cursor = NULL;
4202   GtkRBTree *cursor_tree = NULL;
4203   GtkRBNode *drag_highlight = NULL;
4204   GtkRBTree *drag_highlight_tree = NULL;
4205   GtkTreeIter iter;
4206   gint new_y;
4207   gint y_offset, cell_offset;
4208   gint max_height;
4209   gint depth;
4210   GdkRectangle background_area;
4211   GdkRectangle cell_area;
4212   guint flags;
4213   gint highlight_x;
4214   gint expander_cell_width;
4215   gint bin_window_width;
4216   gint bin_window_height;
4217   GtkTreePath *cursor_path;
4218   GtkTreePath *drag_dest_path;
4219   GList *first_column, *last_column;
4220   gint vertical_separator;
4221   gint horizontal_separator;
4222   gint focus_line_width;
4223   gboolean allow_rules;
4224   gboolean has_special_cell;
4225   gboolean rtl;
4226   gint n_visible_columns;
4227   gint pointer_x, pointer_y;
4228   gint grid_line_width;
4229   gboolean got_pointer = FALSE;
4230   gboolean row_ending_details;
4231   gboolean draw_vgrid_lines, draw_hgrid_lines;
4232
4233   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4234
4235   gtk_widget_style_get (widget,
4236                         "horizontal-separator", &horizontal_separator,
4237                         "vertical-separator", &vertical_separator,
4238                         "allow-rules", &allow_rules,
4239                         "focus-line-width", &focus_line_width,
4240                         "row-ending-details", &row_ending_details,
4241                         NULL);
4242
4243   if (tree_view->priv->tree == NULL)
4244     {
4245       draw_empty_focus (tree_view, &event->area);
4246       return TRUE;
4247     }
4248
4249   /* clip event->area to the visible area */
4250   if (event->area.height < 0)
4251     return TRUE;
4252
4253   validate_visible_area (tree_view);
4254
4255   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4256
4257   if (new_y < 0)
4258     new_y = 0;
4259   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4260   gdk_drawable_get_size (tree_view->priv->bin_window,
4261                          &bin_window_width, &bin_window_height);
4262
4263   if (tree_view->priv->height < bin_window_height)
4264     {
4265       gtk_paint_flat_box (widget->style,
4266                           event->window,
4267                           widget->state,
4268                           GTK_SHADOW_NONE,
4269                           &event->area,
4270                           widget,
4271                           "cell_even",
4272                           0, tree_view->priv->height,
4273                           bin_window_width,
4274                           bin_window_height - tree_view->priv->height);
4275     }
4276
4277   if (node == NULL)
4278     return TRUE;
4279
4280   /* find the path for the node */
4281   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4282                                    tree,
4283                                    node);
4284   gtk_tree_model_get_iter (tree_view->priv->model,
4285                            &iter,
4286                            path);
4287   depth = gtk_tree_path_get_depth (path);
4288   gtk_tree_path_free (path);
4289   
4290   cursor_path = NULL;
4291   drag_dest_path = NULL;
4292
4293   if (tree_view->priv->cursor)
4294     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4295
4296   if (cursor_path)
4297     _gtk_tree_view_find_node (tree_view, cursor_path,
4298                               &cursor_tree, &cursor);
4299
4300   if (tree_view->priv->drag_dest_row)
4301     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4302
4303   if (drag_dest_path)
4304     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4305                               &drag_highlight_tree, &drag_highlight);
4306
4307   draw_vgrid_lines =
4308     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4309     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4310   draw_hgrid_lines =
4311     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4312     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4313
4314   if (draw_vgrid_lines || draw_hgrid_lines)
4315     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4316   
4317   n_visible_columns = 0;
4318   for (list = tree_view->priv->columns; list; list = list->next)
4319     {
4320       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4321         continue;
4322       n_visible_columns ++;
4323     }
4324
4325   /* Find the last column */
4326   for (last_column = g_list_last (tree_view->priv->columns);
4327        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4328        last_column = last_column->prev)
4329     ;
4330
4331   /* and the first */
4332   for (first_column = g_list_first (tree_view->priv->columns);
4333        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4334        first_column = first_column->next)
4335     ;
4336
4337   /* Actually process the expose event.  To do this, we want to
4338    * start at the first node of the event, and walk the tree in
4339    * order, drawing each successive node.
4340    */
4341
4342   do
4343     {
4344       gboolean parity;
4345       gboolean is_separator = FALSE;
4346       gboolean is_first = FALSE;
4347       gboolean is_last = FALSE;
4348       
4349       is_separator = row_is_separator (tree_view, &iter, NULL);
4350
4351       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4352
4353       cell_offset = 0;
4354       highlight_x = 0; /* should match x coord of first cell */
4355       expander_cell_width = 0;
4356
4357       background_area.y = y_offset + event->area.y;
4358       background_area.height = max_height;
4359
4360       flags = 0;
4361
4362       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4363         flags |= GTK_CELL_RENDERER_PRELIT;
4364
4365       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4366         flags |= GTK_CELL_RENDERER_SELECTED;
4367
4368       parity = _gtk_rbtree_node_find_parity (tree, node);
4369
4370       /* we *need* to set cell data on all cells before the call
4371        * to _has_special_cell, else _has_special_cell() does not
4372        * return a correct value.
4373        */
4374       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4375            list;
4376            list = (rtl ? list->prev : list->next))
4377         {
4378           GtkTreeViewColumn *column = list->data;
4379           gtk_tree_view_column_cell_set_cell_data (column,
4380                                                    tree_view->priv->model,
4381                                                    &iter,
4382                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4383                                                    node->children?TRUE:FALSE);
4384         }
4385
4386       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4387
4388       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4389            list;
4390            list = (rtl ? list->prev : list->next))
4391         {
4392           GtkTreeViewColumn *column = list->data;
4393           const gchar *detail = NULL;
4394           GtkStateType state;
4395
4396           if (!column->visible)
4397             continue;
4398
4399           if (cell_offset > event->area.x + event->area.width ||
4400               cell_offset + column->width < event->area.x)
4401             {
4402               cell_offset += column->width;
4403               continue;
4404             }
4405
4406           if (column->show_sort_indicator)
4407             flags |= GTK_CELL_RENDERER_SORTED;
4408           else
4409             flags &= ~GTK_CELL_RENDERER_SORTED;
4410
4411           if (cursor == node)
4412             flags |= GTK_CELL_RENDERER_FOCUSED;
4413           else
4414             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4415
4416           background_area.x = cell_offset;
4417           background_area.width = column->width;
4418
4419           cell_area = background_area;
4420           cell_area.y += vertical_separator / 2;
4421           cell_area.x += horizontal_separator / 2;
4422           cell_area.height -= vertical_separator;
4423           cell_area.width -= horizontal_separator;
4424
4425           if (draw_vgrid_lines)
4426             {
4427               if (list == first_column)
4428                 {
4429                   cell_area.width -= grid_line_width / 2;
4430                 }
4431               else if (list == last_column)
4432                 {
4433                   cell_area.x += grid_line_width / 2;
4434                   cell_area.width -= grid_line_width / 2;
4435                 }
4436               else
4437                 {
4438                   cell_area.x += grid_line_width / 2;
4439                   cell_area.width -= grid_line_width;
4440                 }
4441             }
4442
4443           if (draw_hgrid_lines)
4444             {
4445               cell_area.y += grid_line_width / 2;
4446               cell_area.height -= grid_line_width;
4447             }
4448
4449           if (gdk_region_rect_in (event->region, &background_area) == GDK_OVERLAP_RECTANGLE_OUT)
4450             {
4451               cell_offset += column->width;
4452               continue;
4453             }
4454
4455           gtk_tree_view_column_cell_set_cell_data (column,
4456                                                    tree_view->priv->model,
4457                                                    &iter,
4458                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4459                                                    node->children?TRUE:FALSE);
4460
4461           /* Select the detail for drawing the cell.  relevant
4462            * factors are parity, sortedness, and whether to
4463            * display rules.
4464            */
4465           if (allow_rules && tree_view->priv->has_rules)
4466             {
4467               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4468                   n_visible_columns >= 3)
4469                 {
4470                   if (parity)
4471                     detail = "cell_odd_ruled_sorted";
4472                   else
4473                     detail = "cell_even_ruled_sorted";
4474                 }
4475               else
4476                 {
4477                   if (parity)
4478                     detail = "cell_odd_ruled";
4479                   else
4480                     detail = "cell_even_ruled";
4481                 }
4482             }
4483           else
4484             {
4485               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4486                   n_visible_columns >= 3)
4487                 {
4488                   if (parity)
4489                     detail = "cell_odd_sorted";
4490                   else
4491                     detail = "cell_even_sorted";
4492                 }
4493               else
4494                 {
4495                   if (parity)
4496                     detail = "cell_odd";
4497                   else
4498                     detail = "cell_even";
4499                 }
4500             }
4501
4502           g_assert (detail);
4503
4504           if (widget->state == GTK_STATE_INSENSITIVE)
4505             state = GTK_STATE_INSENSITIVE;          
4506           else if (flags & GTK_CELL_RENDERER_SELECTED)
4507             state = GTK_STATE_SELECTED;
4508           else
4509             state = GTK_STATE_NORMAL;
4510
4511           /* Draw background */
4512           if (row_ending_details)
4513             {
4514               char new_detail[128];
4515
4516               is_first = (rtl ? !list->next : !list->prev);
4517               is_last = (rtl ? !list->prev : !list->next);
4518
4519               /* (I don't like the snprintfs either, but couldn't find a
4520                * less messy way).
4521                */
4522               if (is_first && is_last)
4523                 g_snprintf (new_detail, 127, "%s", detail);
4524               else if (is_first)
4525                 g_snprintf (new_detail, 127, "%s_start", detail);
4526               else if (is_last)
4527                 g_snprintf (new_detail, 127, "%s_end", detail);
4528               else
4529                 g_snprintf (new_detail, 128, "%s_middle", detail);
4530
4531               gtk_paint_flat_box (widget->style,
4532                                   event->window,
4533                                   state,
4534                                   GTK_SHADOW_NONE,
4535                                   &event->area,
4536                                   widget,
4537                                   new_detail,
4538                                   background_area.x,
4539                                   background_area.y,
4540                                   background_area.width,
4541                                   background_area.height);
4542             }
4543           else
4544             {
4545               gtk_paint_flat_box (widget->style,
4546                                   event->window,
4547                                   state,
4548                                   GTK_SHADOW_NONE,
4549                                   &event->area,
4550                                   widget,
4551                                   detail,
4552                                   background_area.x,
4553                                   background_area.y,
4554                                   background_area.width,
4555                                   background_area.height);
4556             }
4557
4558           if (draw_hgrid_lines)
4559             {
4560               if (background_area.y > 0)
4561                 gdk_draw_line (event->window,
4562                                tree_view->priv->grid_line_gc,
4563                                background_area.x, background_area.y,
4564                                background_area.x + background_area.width,
4565                                background_area.y);
4566
4567               if (y_offset + max_height >= event->area.height)
4568                 gdk_draw_line (event->window,
4569                                tree_view->priv->grid_line_gc,
4570                                background_area.x, background_area.y + max_height,
4571                                background_area.x + background_area.width,
4572                                background_area.y + max_height);
4573             }
4574
4575           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4576               tree_view->priv->tree_lines_enabled)
4577             {
4578               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4579                   && depth > 1)
4580                 {
4581                   gdk_draw_line (event->window,
4582                                  tree_view->priv->tree_line_gc,
4583                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4584                                  background_area.y + background_area.height / 2,
4585                                  background_area.x + tree_view->priv->expander_size * (depth - 1.1),
4586                                  background_area.y + background_area.height / 2);
4587                 }
4588               else if (depth > 1)
4589                 {
4590                   gdk_draw_line (event->window,
4591                                  tree_view->priv->tree_line_gc,
4592                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4593                                  background_area.y + background_area.height / 2,
4594                                  background_area.x + tree_view->priv->expander_size * (depth - 0.5),
4595                                  background_area.y + background_area.height / 2);
4596                 }
4597
4598               if (depth > 1)
4599                 {
4600                   gint i;
4601                   GtkRBNode *tmp_node;
4602                   GtkRBTree *tmp_tree;
4603
4604                   if (!_gtk_rbtree_next (tree, node))
4605                     gdk_draw_line (event->window,
4606                                    tree_view->priv->tree_line_gc,
4607                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4608                                    background_area.y,
4609                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4610                                    background_area.y + background_area.height / 2);
4611                   else
4612                     gdk_draw_line (event->window,
4613                                    tree_view->priv->tree_line_gc,
4614                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4615                                    background_area.y,
4616                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4617                                    background_area.y + background_area.height);
4618
4619                   tmp_node = tree->parent_node;
4620                   tmp_tree = tree->parent_tree;
4621
4622                   for (i = depth - 2; i > 0; i--)
4623                     {
4624                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4625                         gdk_draw_line (event->window,
4626                                        tree_view->priv->tree_line_gc,
4627                                        background_area.x + tree_view->priv->expander_size * (i - 0.5),
4628                                        background_area.y,
4629                                        background_area.x + tree_view->priv->expander_size * (i - 0.5),
4630                                        background_area.y + background_area.height);
4631
4632                       tmp_node = tmp_tree->parent_node;
4633                       tmp_tree = tmp_tree->parent_tree;
4634                     }
4635                 }
4636             }
4637
4638           if (gtk_tree_view_is_expander_column (tree_view, column))
4639             {
4640               if (!rtl)
4641                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4642               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4643
4644               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4645                 {
4646                   if (!rtl)
4647                     cell_area.x += depth * tree_view->priv->expander_size;
4648                   cell_area.width -= depth * tree_view->priv->expander_size;
4649                 }
4650
4651               /* If we have an expander column, the highlight underline
4652                * starts with that column, so that it indicates which
4653                * level of the tree we're dropping at.
4654                */
4655               highlight_x = cell_area.x;
4656               expander_cell_width = cell_area.width;
4657
4658               if (is_separator)
4659                 gtk_paint_hline (widget->style,
4660                                  event->window,
4661                                  state,
4662                                  &cell_area,
4663                                  widget,
4664                                  NULL,
4665                                  cell_area.x,
4666                                  cell_area.x + cell_area.width,
4667                                  cell_area.y + cell_area.height / 2);
4668               else
4669                 _gtk_tree_view_column_cell_render (column,
4670                                                    event->window,
4671                                                    &background_area,
4672                                                    &cell_area,
4673                                                    &event->area,
4674                                                    flags);
4675               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4676                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4677                 {
4678                   if (!got_pointer)
4679                     {
4680                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4681                                               &pointer_x, &pointer_y, NULL);
4682                       got_pointer = TRUE;
4683                     }
4684
4685                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4686                                             tree,
4687                                             node,
4688                                             pointer_x, pointer_y);
4689                 }
4690             }
4691           else
4692             {
4693               if (is_separator)
4694                 gtk_paint_hline (widget->style,
4695                                  event->window,
4696                                  state,
4697                                  &cell_area,
4698                                  widget,
4699                                  NULL,
4700                                  cell_area.x,
4701                                  cell_area.x + cell_area.width,
4702                                  cell_area.y + cell_area.height / 2);
4703               else
4704                 _gtk_tree_view_column_cell_render (column,
4705                                                    event->window,
4706                                                    &background_area,
4707                                                    &cell_area,
4708                                                    &event->area,
4709                                                    flags);
4710             }
4711           if (node == cursor && has_special_cell &&
4712               ((column == tree_view->priv->focus_column &&
4713                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4714                 GTK_WIDGET_HAS_FOCUS (widget)) ||
4715                (column == tree_view->priv->edited_column)))
4716             {
4717               _gtk_tree_view_column_cell_draw_focus (column,
4718                                                      event->window,
4719                                                      &background_area,
4720                                                      &cell_area,
4721                                                      &event->area,
4722                                                      flags);
4723             }
4724           cell_offset += column->width;
4725         }
4726
4727       if (node == drag_highlight)
4728         {
4729           /* Draw indicator for the drop
4730            */
4731           gint highlight_y = -1;
4732           GtkRBTree *tree = NULL;
4733           GtkRBNode *node = NULL;
4734           gint width;
4735
4736           switch (tree_view->priv->drag_dest_pos)
4737             {
4738             case GTK_TREE_VIEW_DROP_BEFORE:
4739               highlight_y = background_area.y - 1;
4740               if (highlight_y < 0)
4741                       highlight_y = 0;
4742               break;
4743
4744             case GTK_TREE_VIEW_DROP_AFTER:
4745               highlight_y = background_area.y + background_area.height - 1;
4746               break;
4747
4748             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4749             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4750               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4751
4752               if (tree == NULL)
4753                 break;
4754               gdk_drawable_get_size (tree_view->priv->bin_window,
4755                                      &width, NULL);
4756
4757               if (row_ending_details)
4758                 gtk_paint_focus (widget->style,
4759                                  tree_view->priv->bin_window,
4760                                  GTK_WIDGET_STATE (widget),
4761                                  &event->area,
4762                                  widget,
4763                                  (is_first
4764                                   ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4765                                   : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4766                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4767                                  - focus_line_width / 2,
4768                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4769                                - focus_line_width + 1);
4770               else
4771                 gtk_paint_focus (widget->style,
4772                                  tree_view->priv->bin_window,
4773                                  GTK_WIDGET_STATE (widget),
4774                                  &event->area,
4775                                  widget,
4776                                  "treeview-drop-indicator",
4777                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4778                                  - focus_line_width / 2,
4779                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4780                                  - focus_line_width + 1);
4781               break;
4782             }
4783
4784           if (highlight_y >= 0)
4785             {
4786               gdk_draw_line (event->window,
4787                              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
4788                              rtl ? highlight_x + expander_cell_width : highlight_x,
4789                              highlight_y,
4790                              rtl ? 0 : bin_window_width,
4791                              highlight_y);
4792             }
4793         }
4794
4795       /* draw the big row-spanning focus rectangle, if needed */
4796       if (!has_special_cell && node == cursor &&
4797           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4798           GTK_WIDGET_HAS_FOCUS (widget))
4799         {
4800           gint tmp_y, tmp_height;
4801           gint width;
4802           GtkStateType focus_rect_state;
4803
4804           focus_rect_state =
4805             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4806             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4807              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4808               GTK_STATE_NORMAL));
4809
4810           gdk_drawable_get_size (tree_view->priv->bin_window,
4811                                  &width, NULL);
4812           
4813           if (draw_hgrid_lines)
4814             {
4815               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4816               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4817             }
4818           else
4819             {
4820               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4821               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4822             }
4823
4824           if (row_ending_details)
4825             gtk_paint_focus (widget->style,
4826                              tree_view->priv->bin_window,
4827                              focus_rect_state,
4828                              &event->area,
4829                              widget,
4830                              (is_first
4831                               ? (is_last ? "treeview" : "treeview-left" )
4832                               : (is_last ? "treeview-right" : "treeview-middle" )),
4833                              0, tmp_y,
4834                              width, tmp_height);
4835           else
4836             gtk_paint_focus (widget->style,
4837                              tree_view->priv->bin_window,
4838                              focus_rect_state,
4839                              &event->area,
4840                              widget,
4841                              "treeview",
4842                              0, tmp_y,
4843                              width, tmp_height);
4844         }
4845
4846       y_offset += max_height;
4847       if (node->children)
4848         {
4849           GtkTreeIter parent = iter;
4850           gboolean has_child;
4851
4852           tree = node->children;
4853           node = tree->root;
4854
4855           g_assert (node != tree->nil);
4856
4857           while (node->left != tree->nil)
4858             node = node->left;
4859           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4860                                                     &iter,
4861                                                     &parent);
4862           depth++;
4863
4864           /* Sanity Check! */
4865           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4866         }
4867       else
4868         {
4869           gboolean done = FALSE;
4870
4871           do
4872             {
4873               node = _gtk_rbtree_next (tree, node);
4874               if (node != NULL)
4875                 {
4876                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4877                   done = TRUE;
4878
4879                   /* Sanity Check! */
4880                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4881                 }
4882               else
4883                 {
4884                   GtkTreeIter parent_iter = iter;
4885                   gboolean has_parent;
4886
4887                   node = tree->parent_node;
4888                   tree = tree->parent_tree;
4889                   if (tree == NULL)
4890                     /* we should go to done to free some memory */
4891                     goto done;
4892                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4893                                                            &iter,
4894                                                            &parent_iter);
4895                   depth--;
4896
4897                   /* Sanity check */
4898                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
4899                 }
4900             }
4901           while (!done);
4902         }
4903     }
4904   while (y_offset < event->area.height);
4905
4906 done:
4907   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
4908
4909  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4910    {
4911      GdkRectangle *rectangles;
4912      gint n_rectangles;
4913
4914      gdk_region_get_rectangles (event->region,
4915                                 &rectangles,
4916                                 &n_rectangles);
4917
4918      while (n_rectangles--)
4919        gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
4920
4921      g_free (rectangles);
4922    }
4923
4924   if (cursor_path)
4925     gtk_tree_path_free (cursor_path);
4926
4927   if (drag_dest_path)
4928     gtk_tree_path_free (drag_dest_path);
4929
4930   return FALSE;
4931 }
4932
4933 static gboolean
4934 gtk_tree_view_expose (GtkWidget      *widget,
4935                       GdkEventExpose *event)
4936 {
4937   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4938
4939   if (event->window == tree_view->priv->bin_window)
4940     {
4941       gboolean retval;
4942       GList *tmp_list;
4943
4944       retval = gtk_tree_view_bin_expose (widget, event);
4945
4946       /* We can't just chain up to Container::expose as it will try to send the
4947        * event to the headers, so we handle propagating it to our children
4948        * (eg. widgets being edited) ourselves.
4949        */
4950       tmp_list = tree_view->priv->children;
4951       while (tmp_list)
4952         {
4953           GtkTreeViewChild *child = tmp_list->data;
4954           tmp_list = tmp_list->next;
4955
4956           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
4957         }
4958
4959       return retval;
4960     }
4961
4962   else if (event->window == tree_view->priv->header_window)
4963     {
4964       GList *list;
4965       
4966       for (list = tree_view->priv->columns; list != NULL; list = list->next)
4967         {
4968           GtkTreeViewColumn *column = list->data;
4969
4970           if (column == tree_view->priv->drag_column)
4971             continue;
4972
4973           if (column->visible)
4974             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4975                                             column->button,
4976                                             event);
4977         }
4978     }
4979   else if (event->window == tree_view->priv->drag_window)
4980     {
4981       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4982                                       tree_view->priv->drag_column->button,
4983                                       event);
4984     }
4985   return TRUE;
4986 }
4987
4988 enum
4989 {
4990   DROP_HOME,
4991   DROP_RIGHT,
4992   DROP_LEFT,
4993   DROP_END
4994 };
4995
4996 /* returns 0x1 when no column has been found -- yes it's hackish */
4997 static GtkTreeViewColumn *
4998 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
4999                                GtkTreeViewColumn *column,
5000                                gint               drop_position)
5001 {
5002   GtkTreeViewColumn *left_column = NULL;
5003   GtkTreeViewColumn *cur_column = NULL;
5004   GList *tmp_list;
5005
5006   if (!column->reorderable)
5007     return (GtkTreeViewColumn *)0x1;
5008
5009   switch (drop_position)
5010     {
5011       case DROP_HOME:
5012         /* find first column where we can drop */
5013         tmp_list = tree_view->priv->columns;
5014         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5015           return (GtkTreeViewColumn *)0x1;
5016
5017         while (tmp_list)
5018           {
5019             g_assert (tmp_list);
5020
5021             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5022             tmp_list = tmp_list->next;
5023
5024             if (left_column && left_column->visible == FALSE)
5025               continue;
5026
5027             if (!tree_view->priv->column_drop_func)
5028               return left_column;
5029
5030             if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5031               {
5032                 left_column = cur_column;
5033                 continue;
5034               }
5035
5036             return left_column;
5037           }
5038
5039         if (!tree_view->priv->column_drop_func)
5040           return left_column;
5041
5042         if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5043           return left_column;
5044         else
5045           return (GtkTreeViewColumn *)0x1;
5046         break;
5047
5048       case DROP_RIGHT:
5049         /* find first column after column where we can drop */
5050         tmp_list = tree_view->priv->columns;
5051
5052         for (; tmp_list; tmp_list = tmp_list->next)
5053           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5054             break;
5055
5056         if (!tmp_list || !tmp_list->next)
5057           return (GtkTreeViewColumn *)0x1;
5058
5059         tmp_list = tmp_list->next;
5060         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5061         tmp_list = tmp_list->next;
5062
5063         while (tmp_list)
5064           {
5065             g_assert (tmp_list);
5066
5067             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5068             tmp_list = tmp_list->next;
5069
5070             if (left_column && left_column->visible == FALSE)
5071               {
5072                 left_column = cur_column;
5073                 if (tmp_list)
5074                   tmp_list = tmp_list->next;
5075                 continue;
5076               }
5077
5078             if (!tree_view->priv->column_drop_func)
5079               return left_column;
5080
5081             if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5082               {
5083                 left_column = cur_column;
5084                 continue;
5085               }
5086
5087             return left_column;
5088           }
5089
5090         if (!tree_view->priv->column_drop_func)
5091           return left_column;
5092
5093         if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5094           return left_column;
5095         else
5096           return (GtkTreeViewColumn *)0x1;
5097         break;
5098
5099       case DROP_LEFT:
5100         /* find first column before column where we can drop */
5101         tmp_list = tree_view->priv->columns;
5102
5103         for (; tmp_list; tmp_list = tmp_list->next)
5104           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5105             break;
5106
5107         if (!tmp_list || !tmp_list->prev)
5108           return (GtkTreeViewColumn *)0x1;
5109
5110         tmp_list = tmp_list->prev;
5111         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5112         tmp_list = tmp_list->prev;
5113
5114         while (tmp_list)
5115           {
5116             g_assert (tmp_list);
5117
5118             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5119
5120             if (left_column && !left_column->visible)
5121               {
5122                 /*if (!tmp_list->prev)
5123                   return (GtkTreeViewColumn *)0x1;
5124                   */
5125 /*
5126                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5127                 tmp_list = tmp_list->prev->prev;
5128                 continue;*/
5129
5130                 cur_column = left_column;
5131                 if (tmp_list)
5132                   tmp_list = tmp_list->prev;
5133                 continue;
5134               }
5135
5136             if (!tree_view->priv->column_drop_func)
5137               return left_column;
5138
5139             if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5140               return left_column;
5141
5142             cur_column = left_column;
5143             tmp_list = tmp_list->prev;
5144           }
5145
5146         if (!tree_view->priv->column_drop_func)
5147           return NULL;
5148
5149         if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5150           return NULL;
5151         else
5152           return (GtkTreeViewColumn *)0x1;
5153         break;
5154
5155       case DROP_END:
5156         /* same as DROP_HOME case, but doing it backwards */
5157         tmp_list = g_list_last (tree_view->priv->columns);
5158         cur_column = NULL;
5159
5160         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5161           return (GtkTreeViewColumn *)0x1;
5162
5163         while (tmp_list)
5164           {
5165             g_assert (tmp_list);
5166
5167             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5168
5169             if (left_column && !left_column->visible)
5170               {
5171                 cur_column = left_column;
5172                 tmp_list = tmp_list->prev;
5173               }
5174
5175             if (!tree_view->priv->column_drop_func)
5176               return left_column;
5177
5178             if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5179               return left_column;
5180
5181             cur_column = left_column;
5182             tmp_list = tmp_list->prev;
5183           }
5184
5185         if (!tree_view->priv->column_drop_func)
5186           return NULL;
5187
5188         if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5189           return NULL;
5190         else
5191           return (GtkTreeViewColumn *)0x1;
5192         break;
5193     }
5194
5195   return (GtkTreeViewColumn *)0x1;
5196 }
5197
5198 static gboolean
5199 gtk_tree_view_key_press (GtkWidget   *widget,
5200                          GdkEventKey *event)
5201 {
5202   GtkTreeView *tree_view = (GtkTreeView *) widget;
5203
5204   if (tree_view->priv->rubber_band_status)
5205     {
5206       if (event->keyval == GDK_Escape)
5207         gtk_tree_view_stop_rubber_band (tree_view);
5208
5209       return TRUE;
5210     }
5211
5212   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5213     {
5214       if (event->keyval == GDK_Escape)
5215         {
5216           tree_view->priv->cur_reorder = NULL;
5217           gtk_tree_view_button_release_drag_column (widget, NULL);
5218         }
5219       return TRUE;
5220     }
5221
5222   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5223     {
5224       GList *focus_column;
5225       gboolean rtl;
5226
5227       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5228
5229       for (focus_column = tree_view->priv->columns;
5230            focus_column;
5231            focus_column = focus_column->next)
5232         {
5233           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5234
5235           if (GTK_WIDGET_HAS_FOCUS (column->button))
5236             break;
5237         }
5238
5239       if (focus_column &&
5240           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5241           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5242            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
5243         {
5244           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5245
5246           if (!column->resizable)
5247             {
5248               gtk_widget_error_bell (widget);
5249               return TRUE;
5250             }
5251
5252           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5253               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5254             {
5255               gint old_width = column->resized_width;
5256
5257               column->resized_width = MAX (column->resized_width,
5258                                            column->width);
5259               column->resized_width -= 2;
5260               if (column->resized_width < 0)
5261                 column->resized_width = 0;
5262
5263               if (column->min_width == -1)
5264                 column->resized_width = MAX (column->button->requisition.width,
5265                                              column->resized_width);
5266               else
5267                 column->resized_width = MAX (column->min_width,
5268                                              column->resized_width);
5269
5270               if (column->max_width != -1)
5271                 column->resized_width = MIN (column->resized_width,
5272                                              column->max_width);
5273
5274               column->use_resized_width = TRUE;
5275
5276               if (column->resized_width != old_width)
5277                 gtk_widget_queue_resize (widget);
5278               else
5279                 gtk_widget_error_bell (widget);
5280             }
5281           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5282                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5283             {
5284               gint old_width = column->resized_width;
5285
5286               column->resized_width = MAX (column->resized_width,
5287                                            column->width);
5288               column->resized_width += 2;
5289
5290               if (column->max_width != -1)
5291                 column->resized_width = MIN (column->resized_width,
5292                                              column->max_width);
5293
5294               column->use_resized_width = TRUE;
5295
5296               if (column->resized_width != old_width)
5297                 gtk_widget_queue_resize (widget);
5298               else
5299                 gtk_widget_error_bell (widget);
5300             }
5301
5302           return TRUE;
5303         }
5304
5305       if (focus_column &&
5306           (event->state & GDK_MOD1_MASK) &&
5307           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5308            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
5309            || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
5310            || event->keyval == GDK_End || event->keyval == GDK_KP_End))
5311         {
5312           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5313
5314           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5315               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5316             {
5317               GtkTreeViewColumn *col;
5318               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5319               if (col != (GtkTreeViewColumn *)0x1)
5320                 gtk_tree_view_move_column_after (tree_view, column, col);
5321               else
5322                 gtk_widget_error_bell (widget);
5323             }
5324           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5325                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5326             {
5327               GtkTreeViewColumn *col;
5328               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5329               if (col != (GtkTreeViewColumn *)0x1)
5330                 gtk_tree_view_move_column_after (tree_view, column, col);
5331               else
5332                 gtk_widget_error_bell (widget);
5333             }
5334           else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
5335             {
5336               GtkTreeViewColumn *col;
5337               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5338               if (col != (GtkTreeViewColumn *)0x1)
5339                 gtk_tree_view_move_column_after (tree_view, column, col);
5340               else
5341                 gtk_widget_error_bell (widget);
5342             }
5343           else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
5344             {
5345               GtkTreeViewColumn *col;
5346               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5347               if (col != (GtkTreeViewColumn *)0x1)
5348                 gtk_tree_view_move_column_after (tree_view, column, col);
5349               else
5350                 gtk_widget_error_bell (widget);
5351             }
5352
5353           return TRUE;
5354         }
5355     }
5356
5357   /* Chain up to the parent class.  It handles the keybindings. */
5358   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5359     return TRUE;
5360
5361   /* We pass the event to the search_entry.  If its text changes, then we start
5362    * the typeahead find capabilities. */
5363   if (GTK_WIDGET_HAS_FOCUS (tree_view)
5364       && tree_view->priv->enable_search
5365       && !tree_view->priv->search_custom_entry_set)
5366     {
5367       GdkEvent *new_event;
5368       char *old_text;
5369       const char *new_text;
5370       gboolean retval;
5371       GdkScreen *screen;
5372       gboolean text_modified;
5373       gulong popup_menu_id;
5374
5375       gtk_tree_view_ensure_interactive_directory (tree_view);
5376
5377       /* Make a copy of the current text */
5378       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5379       new_event = gdk_event_copy ((GdkEvent *) event);
5380       g_object_unref (((GdkEventKey *) new_event)->window);
5381       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5382       gtk_widget_realize (tree_view->priv->search_window);
5383
5384       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5385                                         "popup_menu", G_CALLBACK (gtk_true), 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"