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