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