]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Remove GTK_OBJECT_CONNECTED.
[~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 "gtktreeview.h"
22 #include "gtkrbtree.h"
23 #include "gtktreednd.h"
24 #include "gtktreeprivate.h"
25 #include "gtkcellrenderer.h"
26 #include "gtksignal.h"
27 #include "gtkmain.h"
28 #include "gtkmarshalers.h"
29 #include "gtkbutton.h"
30 #include "gtkalignment.h"
31 #include "gtklabel.h"
32 #include "gtkhbox.h"
33 #include "gtkarrow.h"
34 #include "gtkintl.h"
35 #include "gtkbindings.h"
36 #include "gtkcontainer.h"
37 #include "gtkentry.h"
38 #include "gtktreemodelsort.h"
39
40 #include <string.h>
41 #include <gdk/gdkkeysyms.h>
42
43 #define GTK_TREE_VIEW_SEARCH_DIALOG_KEY "gtk-tree-view-search-dialog"
44 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
45 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
46 #define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 500
47 #define SCROLL_EDGE_SIZE 15
48 #define EXPANDER_EXTRA_PADDING 4
49
50 /* The "background" areas of all rows/cells add up to cover the entire tree.
51  * The background includes all inter-row and inter-cell spacing.
52  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
53  * i.e. just the cells, no spacing.
54  */
55
56 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
57 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
58
59 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
60 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
61
62 /* This is in Window coordinates */
63 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
64 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
65
66
67 typedef struct _GtkTreeViewChild GtkTreeViewChild;
68 struct _GtkTreeViewChild
69 {
70   GtkWidget *widget;
71   gint x;
72   gint y;
73   gint width;
74   gint height;
75 };
76
77
78 typedef struct _TreeViewDragInfo TreeViewDragInfo;
79 struct _TreeViewDragInfo
80 {
81   GdkModifierType start_button_mask;
82   GtkTargetList *source_target_list;
83   GdkDragAction source_actions;
84
85   GtkTargetList *dest_target_list;
86
87   guint source_set : 1;
88   guint dest_set : 1;
89 };
90
91
92 /* Signals */
93 enum
94 {
95   ROW_ACTIVATED,
96   TEST_EXPAND_ROW,
97   TEST_COLLAPSE_ROW,
98   ROW_EXPANDED,
99   ROW_COLLAPSED,
100   COLUMNS_CHANGED,
101   CURSOR_CHANGED,
102   MOVE_CURSOR,
103   SELECT_ALL,
104   UNSELECT_ALL,
105   SELECT_CURSOR_ROW,
106   TOGGLE_CURSOR_ROW,
107   EXPAND_COLLAPSE_CURSOR_ROW,
108   SELECT_CURSOR_PARENT,
109   START_INTERACTIVE_SEARCH,
110   LAST_SIGNAL
111 };
112
113 /* Properties */
114 enum {
115   PROP_0,
116   PROP_MODEL,
117   PROP_HADJUSTMENT,
118   PROP_VADJUSTMENT,
119   PROP_HEADERS_VISIBLE,
120   PROP_HEADERS_CLICKABLE,
121   PROP_EXPANDER_COLUMN,
122   PROP_REORDERABLE,
123   PROP_RULES_HINT,
124   PROP_ENABLE_SEARCH,
125   PROP_SEARCH_COLUMN
126 };
127
128 static void     gtk_tree_view_class_init           (GtkTreeViewClass *klass);
129 static void     gtk_tree_view_init                 (GtkTreeView      *tree_view);
130
131 /* object signals */
132 static void     gtk_tree_view_finalize             (GObject          *object);
133 static void     gtk_tree_view_set_property         (GObject         *object,
134                                                     guint            prop_id,
135                                                     const GValue    *value,
136                                                     GParamSpec      *pspec);
137 static void     gtk_tree_view_get_property         (GObject         *object,
138                                                     guint            prop_id,
139                                                     GValue          *value,
140                                                     GParamSpec      *pspec);
141
142 /* gtkobject signals */
143 static void     gtk_tree_view_destroy              (GtkObject        *object);
144
145 /* gtkwidget signals */
146 static void     gtk_tree_view_realize              (GtkWidget        *widget);
147 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
148 static void     gtk_tree_view_map                  (GtkWidget        *widget);
149 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
150                                                     GtkRequisition   *requisition);
151 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
152                                                     GtkAllocation    *allocation);
153 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
154                                                     GdkEventExpose   *event);
155 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
156                                                     GdkEventKey      *event);
157 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
158                                                     GdkEventMotion   *event);
159 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
160                                                     GdkEventCrossing *event);
161 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
162                                                     GdkEventCrossing *event);
163 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
164                                                     GdkEventButton   *event);
165 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
166                                                     GdkEventButton   *event);
167 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
168                                                     GtkWidget        *child);
169 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
170                                                     GdkEventFocus    *event);
171 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
172                                                     GtkDirectionType  direction);
173 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
174 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
175                                                     GtkStyle         *previous_style);
176
177 /* container signals */
178 static void     gtk_tree_view_remove               (GtkContainer     *container,
179                                                     GtkWidget        *widget);
180 static void     gtk_tree_view_forall               (GtkContainer     *container,
181                                                     gboolean          include_internals,
182                                                     GtkCallback       callback,
183                                                     gpointer          callback_data);
184
185 /* Source side drag signals */
186 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
187                                             GdkDragContext   *context);
188 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
189                                             GdkDragContext   *context);
190 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
191                                             GdkDragContext   *context,
192                                             GtkSelectionData *selection_data,
193                                             guint             info,
194                                             guint             time);
195 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
196                                             GdkDragContext   *context);
197
198 /* Target side drag signals */
199 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
200                                                   GdkDragContext   *context,
201                                                   guint             time);
202 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
203                                                   GdkDragContext   *context,
204                                                   gint              x,
205                                                   gint              y,
206                                                   guint             time);
207 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
208                                                   GdkDragContext   *context,
209                                                   gint              x,
210                                                   gint              y,
211                                                   guint             time);
212 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
213                                                   GdkDragContext   *context,
214                                                   gint              x,
215                                                   gint              y,
216                                                   GtkSelectionData *selection_data,
217                                                   guint             info,
218                                                   guint             time);
219
220 /* tree_model signals */
221 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
222                                                            GtkAdjustment   *hadj,
223                                                            GtkAdjustment   *vadj);
224 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
225                                                            GtkMovementStep  step,
226                                                            gint             count);
227 static void gtk_tree_view_real_select_all                 (GtkTreeView     *tree_view);
228 static void gtk_tree_view_real_unselect_all               (GtkTreeView     *tree_view);
229 static void gtk_tree_view_real_select_cursor_row          (GtkTreeView     *tree_view,
230                                                            gboolean         start_editing);
231 static void gtk_tree_view_real_toggle_cursor_row          (GtkTreeView     *tree_view);
232 static void gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
233                                                            gboolean         logical,
234                                                            gboolean         expand,
235                                                            gboolean         open_all);
236 static void gtk_tree_view_real_select_cursor_parent       (GtkTreeView     *tree_view);
237 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
238                                                            GtkTreePath     *path,
239                                                            GtkTreeIter     *iter,
240                                                            gpointer         data);
241 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
242                                                            GtkTreePath     *path,
243                                                            GtkTreeIter     *iter,
244                                                            gpointer         data);
245 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
246                                                            GtkTreePath     *path,
247                                                            GtkTreeIter     *iter,
248                                                            gpointer         data);
249 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
250                                                            GtkTreePath     *path,
251                                                            gpointer         data);
252 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
253                                                            GtkTreePath     *parent,
254                                                            GtkTreeIter     *iter,
255                                                            gint            *new_order,
256                                                            gpointer         data);
257
258 /* Incremental reflow */
259 static gboolean validate_row             (GtkTreeView *tree_view,
260                                           GtkRBTree   *tree,
261                                           GtkRBNode   *node,
262                                           GtkTreeIter *iter,
263                                           GtkTreePath *path);
264 static void     validate_visible_area    (GtkTreeView *tree_view);
265 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
266 static gboolean do_validate_rows         (GtkTreeView *tree_view);
267 static gboolean presize_handler_callback (gpointer     data);
268 static void     install_presize_handler  (GtkTreeView *tree_view);
269 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
270 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
271 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
272
273
274 /* Internal functions */
275 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView       *tree_view,
276                                                               GtkTreeViewColumn *column);
277 static void     gtk_tree_view_add_move_binding               (GtkBindingSet     *binding_set,
278                                                               guint              keyval,
279                                                               guint              modmask,
280                                                               GtkMovementStep    step,
281                                                               gint               count);
282 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView       *tree_view,
283                                                               GtkRBTree         *tree);
284 static void     gtk_tree_view_queue_draw_path                (GtkTreeView       *tree_view,
285                                                               GtkTreePath       *path,
286                                                               GdkRectangle      *clip_rect);
287 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView       *tree_view,
288                                                               GtkRBTree         *tree,
289                                                               GtkRBNode         *node,
290                                                               GdkRectangle      *clip_rect);
291 static void     gtk_tree_view_draw_arrow                     (GtkTreeView       *tree_view,
292                                                               GtkRBTree         *tree,
293                                                               GtkRBNode         *node,
294                                                               gint               x,
295                                                               gint               y);
296 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView       *tree_view,
297                                                               GtkRBTree         *tree,
298                                                               gint              *x1,
299                                                               gint              *x2);
300 static gint     gtk_tree_view_new_column_width               (GtkTreeView       *tree_view,
301                                                               gint               i,
302                                                               gint              *x);
303 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment     *adjustment,
304                                                               GtkTreeView       *tree_view);
305 static void     gtk_tree_view_build_tree                     (GtkTreeView       *tree_view,
306                                                               GtkRBTree         *tree,
307                                                               GtkTreeIter       *iter,
308                                                               gint               depth,
309                                                               gboolean           recurse);
310 static gboolean gtk_tree_view_discover_dirty_iter            (GtkTreeView       *tree_view,
311                                                               GtkTreeIter       *iter,
312                                                               gint               depth,
313                                                               gint              *height,
314                                                               GtkRBNode         *node);
315 static void     gtk_tree_view_discover_dirty                 (GtkTreeView       *tree_view,
316                                                               GtkRBTree         *tree,
317                                                               GtkTreeIter       *iter,
318                                                               gint               depth);
319 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView       *tree_view,
320                                                               GtkRBTree         *tree,
321                                                               GtkRBNode         *node);
322 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView       *tree_view,
323                                                               GtkTreeViewColumn *column);
324 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView       *tree_view,
325                                                               GdkEventMotion    *event);
326 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView       *tree_view);
327 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView       *tree_view,
328                                                               gint               count);
329 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView       *tree_view,
330                                                               gint               count);
331 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView       *tree_view,
332                                                               gint               count);
333 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView       *tree_view,
334                                                               gint               count);
335 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView       *tree_view,
336                                                               GtkTreePath       *path,
337                                                               GtkRBTree         *tree,
338                                                               GtkRBNode         *node,
339                                                               gboolean           animate);
340 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView       *tree_view,
341                                                               GtkTreePath       *path,
342                                                               GtkRBTree         *tree,
343                                                               GtkRBNode         *node,
344                                                               gboolean           open_all,
345                                                               gboolean           animate);
346 static void     gtk_tree_view_real_set_cursor                (GtkTreeView       *tree_view,
347                                                               GtkTreePath       *path,
348                                                               gboolean           clear_and_select,
349                                                               gboolean           clamp_node);
350
351 /* interactive search */
352 static void     gtk_tree_view_search_dialog_destroy     (GtkWidget        *search_dialog,
353                                                          GtkTreeView      *tree_view);
354 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
355                                                          GtkWidget        *search_dialog);
356 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
357                                                          GtkMenu          *menu,
358                                                          gpointer          data);
359 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
360 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
361                                                          gpointer          data);
362 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
363                                                          GdkEventAny      *event,
364                                                          GtkTreeView      *tree_view);
365 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
366                                                          GdkEventButton   *event,
367                                                          GtkTreeView      *tree_view);
368 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
369                                                          GdkEventKey      *event,
370                                                          GtkTreeView      *tree_view);
371 static void     gtk_tree_view_search_move               (GtkWidget        *window,
372                                                          GtkTreeView      *tree_view,
373                                                          gboolean          up);
374 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
375                                                          gint              column,
376                                                          const gchar      *key,
377                                                          GtkTreeIter      *iter,
378                                                          gpointer          search_data);
379 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
380                                                          GtkTreeSelection *selection,
381                                                          GtkTreeIter      *iter,
382                                                          const gchar      *text,
383                                                          gint             *count,
384                                                          gint              n);
385 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
386                                                          GtkTreeView      *tree_view);
387 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
388                                                          GtkWidget        *child_widget,
389                                                          gint              x,
390                                                          gint              y,
391                                                          gint              width,
392                                                          gint              height);
393 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
394                                                          GtkTreePath      *cursor_path);
395 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
396                                               GtkTreeViewColumn *column,
397                                               GtkTreePath       *path,
398                                               GtkCellEditable   *cell_editable,
399                                               GdkRectangle      *cell_area,
400                                               GdkEvent          *event,
401                                               guint              flags);
402 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
403                                                          gboolean     cancel_editing);
404 static void gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view);
405 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
406                                                          GtkTreeViewColumn *column,
407                                                          gint               drop_position);
408
409
410 static GtkContainerClass *parent_class = NULL;
411 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
412
413 \f
414
415 /* GType Methods
416  */
417
418 GtkType
419 gtk_tree_view_get_type (void)
420 {
421   static GtkType tree_view_type = 0;
422
423   if (!tree_view_type)
424     {
425       static const GTypeInfo tree_view_info =
426       {
427         sizeof (GtkTreeViewClass),
428         NULL,           /* base_init */
429         NULL,           /* base_finalize */
430         (GClassInitFunc) gtk_tree_view_class_init,
431         NULL,           /* class_finalize */
432         NULL,           /* class_data */
433         sizeof (GtkTreeView),
434         0,              /* n_preallocs */
435         (GInstanceInitFunc) gtk_tree_view_init
436       };
437
438       tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info, 0);
439     }
440
441   return tree_view_type;
442 }
443
444 static void
445 gtk_tree_view_class_init (GtkTreeViewClass *class)
446 {
447   GObjectClass *o_class;
448   GtkObjectClass *object_class;
449   GtkWidgetClass *widget_class;
450   GtkContainerClass *container_class;
451   GtkBindingSet *binding_set;
452
453   parent_class = g_type_class_peek_parent (class);
454   binding_set = gtk_binding_set_by_class (class);
455
456   o_class = (GObjectClass *) class;
457   object_class = (GtkObjectClass *) class;
458   widget_class = (GtkWidgetClass *) class;
459   container_class = (GtkContainerClass *) class;
460
461   /* GObject signals */
462   o_class->set_property = gtk_tree_view_set_property;
463   o_class->get_property = gtk_tree_view_get_property;
464   o_class->finalize = gtk_tree_view_finalize;
465
466   /* GtkObject signals */
467   object_class->destroy = gtk_tree_view_destroy;
468
469   /* GtkWidget signals */
470   widget_class->map = gtk_tree_view_map;
471   widget_class->realize = gtk_tree_view_realize;
472   widget_class->unrealize = gtk_tree_view_unrealize;
473   widget_class->size_request = gtk_tree_view_size_request;
474   widget_class->size_allocate = gtk_tree_view_size_allocate;
475   widget_class->button_press_event = gtk_tree_view_button_press;
476   widget_class->button_release_event = gtk_tree_view_button_release;
477   widget_class->motion_notify_event = gtk_tree_view_motion;
478   widget_class->expose_event = gtk_tree_view_expose;
479   widget_class->key_press_event = gtk_tree_view_key_press;
480   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
481   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
482   widget_class->focus_out_event = gtk_tree_view_focus_out;
483   widget_class->drag_begin = gtk_tree_view_drag_begin;
484   widget_class->drag_end = gtk_tree_view_drag_end;
485   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
486   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
487   widget_class->drag_leave = gtk_tree_view_drag_leave;
488   widget_class->drag_motion = gtk_tree_view_drag_motion;
489   widget_class->drag_drop = gtk_tree_view_drag_drop;
490   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
491   widget_class->focus = gtk_tree_view_focus;
492   widget_class->grab_focus = gtk_tree_view_grab_focus;
493   widget_class->style_set = gtk_tree_view_style_set;
494
495   /* GtkContainer signals */
496   container_class->remove = gtk_tree_view_remove;
497   container_class->forall = gtk_tree_view_forall;
498   container_class->set_focus_child = gtk_tree_view_set_focus_child;
499
500   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
501   class->move_cursor = gtk_tree_view_real_move_cursor;
502   class->select_all = gtk_tree_view_real_select_all;
503   class->unselect_all = gtk_tree_view_real_unselect_all;
504   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
505   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
506   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
507   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
508   class->start_interactive_search = gtk_tree_view_real_start_interactive_search;
509
510   /* Properties */
511
512   g_object_class_install_property (o_class,
513                                    PROP_MODEL,
514                                    g_param_spec_object ("model",
515                                                         _("TreeView Model"),
516                                                         _("The model for the tree view"),
517                                                         GTK_TYPE_TREE_MODEL,
518                                                         G_PARAM_READWRITE));
519
520   g_object_class_install_property (o_class,
521                                    PROP_HADJUSTMENT,
522                                    g_param_spec_object ("hadjustment",
523                                                         _("Horizontal Adjustment"),
524                                                         _("Horizontal Adjustment for the widget"),
525                                                         GTK_TYPE_ADJUSTMENT,
526                                                         G_PARAM_READWRITE));
527
528   g_object_class_install_property (o_class,
529                                    PROP_VADJUSTMENT,
530                                    g_param_spec_object ("vadjustment",
531                                                         _("Vertical Adjustment"),
532                                                         _("Vertical Adjustment for the widget"),
533                                                         GTK_TYPE_ADJUSTMENT,
534                                                         G_PARAM_READWRITE));
535
536   g_object_class_install_property (o_class,
537                                    PROP_HEADERS_VISIBLE,
538                                    g_param_spec_boolean ("headers_visible",
539                                                          _("Visible"),
540                                                          _("Show the column header buttons"),
541                                                          TRUE,
542                                                          G_PARAM_READWRITE));
543
544   g_object_class_install_property (o_class,
545                                    PROP_HEADERS_CLICKABLE,
546                                    g_param_spec_boolean ("headers_clickable",
547                                                          _("Headers Clickable"),
548                                                          _("Column headers respond to click events"),
549                                                          FALSE,
550                                                          G_PARAM_WRITABLE));
551
552   g_object_class_install_property (o_class,
553                                    PROP_EXPANDER_COLUMN,
554                                    g_param_spec_object ("expander_column",
555                                                         _("Expander Column"),
556                                                         _("Set the column for the expander column"),
557                                                         GTK_TYPE_TREE_VIEW_COLUMN,
558                                                         G_PARAM_READWRITE));
559
560   g_object_class_install_property (o_class,
561                                    PROP_REORDERABLE,
562                                    g_param_spec_boolean ("reorderable",
563                                                          _("Reorderable"),
564                                                          _("View is reorderable"),
565                                                          FALSE,
566                                                          G_PARAM_READWRITE));
567
568   g_object_class_install_property (o_class,
569                                    PROP_RULES_HINT,
570                                    g_param_spec_boolean ("rules_hint",
571                                                          _("Rules Hint"),
572                                                          _("Set a hint to the theme engine to draw rows in alternating colors"),
573                                                          FALSE,
574                                                          G_PARAM_READWRITE));
575
576     g_object_class_install_property (o_class,
577                                      PROP_ENABLE_SEARCH,
578                                      g_param_spec_boolean ("enable_search",
579                                                            _("Enable Search"),
580                                                            _("View allows user to search through columns interactively"),
581                                                            TRUE,
582                                                            G_PARAM_READWRITE));
583
584     g_object_class_install_property (o_class,
585                                      PROP_SEARCH_COLUMN,
586                                      g_param_spec_int ("search_column",
587                                                        _("Search Column"),
588                                                        _("Model column to search through when searching through code"),
589                                                        -1,
590                                                        G_MAXINT,
591                                                        0,
592                                                        G_PARAM_READWRITE));
593
594   /* Style properties */
595 #define _TREE_VIEW_EXPANDER_SIZE 10
596 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
597 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
598     
599   gtk_widget_class_install_style_property (widget_class,
600                                            g_param_spec_int ("expander_size",
601                                                              _("Expander Size"),
602                                                              _("Size of the expander arrow."),
603                                                              0,
604                                                              G_MAXINT,
605                                                              _TREE_VIEW_EXPANDER_SIZE,
606                                                              G_PARAM_READABLE));
607
608   gtk_widget_class_install_style_property (widget_class,
609                                            g_param_spec_int ("vertical_separator",
610                                                              _("Vertical Separator Width"),
611                                                              _("Vertical space between cells.  Must be an even number."),
612                                                              0,
613                                                              G_MAXINT,
614                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
615                                                              G_PARAM_READABLE));
616
617   gtk_widget_class_install_style_property (widget_class,
618                                            g_param_spec_int ("horizontal_separator",
619                                                              _("Horizontal Separator Width"),
620                                                              _("Horizontal space between cells.  Must be an even number."),
621                                                              0,
622                                                              G_MAXINT,
623                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
624                                                              G_PARAM_READABLE));
625
626   gtk_widget_class_install_style_property (widget_class,
627                                            g_param_spec_boolean ("allow_rules",
628                                                                  _("Allow Rules"),
629                                                                  _("Allow drawing of alternating color rows."),
630                                                                  TRUE,
631                                                                  G_PARAM_READABLE));
632
633   gtk_widget_class_install_style_property (widget_class,
634                                            g_param_spec_boolean ("indent_expanders",
635                                                                  _("Indent Expanders"),
636                                                                  _("Make the expanders indented."),
637                                                                  TRUE,
638                                                                  G_PARAM_READABLE));
639   /* Signals */
640   widget_class->set_scroll_adjustments_signal =
641     gtk_signal_new ("set_scroll_adjustments",
642                     GTK_RUN_LAST,
643                     GTK_CLASS_TYPE (object_class),
644                     GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
645                     _gtk_marshal_VOID__OBJECT_OBJECT,
646                     GTK_TYPE_NONE, 2,
647                     GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
648
649   tree_view_signals[ROW_ACTIVATED] =
650     gtk_signal_new ("row_activated",
651                     GTK_RUN_LAST | GTK_RUN_ACTION,
652                     GTK_CLASS_TYPE (object_class),
653                     GTK_SIGNAL_OFFSET (GtkTreeViewClass, row_activated),
654                     _gtk_marshal_VOID__BOXED_OBJECT,
655                     GTK_TYPE_NONE, 2,
656                     GTK_TYPE_TREE_PATH,
657                     GTK_TYPE_TREE_VIEW_COLUMN);
658
659   tree_view_signals[TEST_EXPAND_ROW] =
660     g_signal_new ("test_expand_row",
661                   G_TYPE_FROM_CLASS (object_class),
662                   G_SIGNAL_RUN_LAST,
663                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
664                   _gtk_boolean_handled_accumulator, NULL,
665                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
666                   G_TYPE_BOOLEAN, 2,
667                   GTK_TYPE_TREE_ITER,
668                   GTK_TYPE_TREE_PATH);
669
670   tree_view_signals[TEST_COLLAPSE_ROW] =
671     g_signal_new ("test_collapse_row",
672                   G_TYPE_FROM_CLASS (object_class),
673                   G_SIGNAL_RUN_LAST,
674                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
675                   _gtk_boolean_handled_accumulator, NULL,
676                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
677                   G_TYPE_BOOLEAN, 2,
678                   GTK_TYPE_TREE_ITER,
679                   GTK_TYPE_TREE_PATH);
680
681   tree_view_signals[ROW_EXPANDED] =
682     g_signal_new ("row_expanded",
683                   G_TYPE_FROM_CLASS (object_class),
684                   G_SIGNAL_RUN_LAST,
685                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
686                   NULL, NULL,
687                   _gtk_marshal_VOID__BOXED_BOXED,
688                   GTK_TYPE_NONE, 2,
689                   GTK_TYPE_TREE_ITER,
690                   GTK_TYPE_TREE_PATH);
691
692   tree_view_signals[ROW_COLLAPSED] =
693     g_signal_new ("row_collapsed",
694                   G_TYPE_FROM_CLASS (object_class),
695                   G_SIGNAL_RUN_LAST,
696                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
697                   NULL, NULL,
698                   _gtk_marshal_VOID__BOXED_BOXED,
699                   GTK_TYPE_NONE, 2,
700                   GTK_TYPE_TREE_ITER,
701                   GTK_TYPE_TREE_PATH);
702
703   tree_view_signals[COLUMNS_CHANGED] =
704     g_signal_new ("columns_changed",
705                   G_TYPE_FROM_CLASS (object_class),
706                   G_SIGNAL_RUN_LAST,
707                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
708                   NULL, NULL,
709                   _gtk_marshal_NONE__NONE,
710                   G_TYPE_NONE, 0);
711
712   tree_view_signals[CURSOR_CHANGED] =
713     g_signal_new ("cursor_changed",
714                   G_TYPE_FROM_CLASS (object_class),
715                   G_SIGNAL_RUN_LAST,
716                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
717                   NULL, NULL,
718                   _gtk_marshal_NONE__NONE,
719                   G_TYPE_NONE, 0);
720
721   tree_view_signals[MOVE_CURSOR] =
722     g_signal_new ("move_cursor",
723                   G_TYPE_FROM_CLASS (object_class),
724                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
725                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
726                   NULL, NULL,
727                   _gtk_marshal_BOOLEAN__ENUM_INT,
728                   GTK_TYPE_BOOL, 2, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT);
729
730   tree_view_signals[SELECT_ALL] =
731     g_signal_new ("select_all",
732                   G_TYPE_FROM_CLASS (object_class),
733                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
734                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
735                   NULL, NULL,
736                   _gtk_marshal_NONE__NONE,
737                   GTK_TYPE_NONE, 0);
738
739   tree_view_signals[UNSELECT_ALL] =
740     g_signal_new ("unselect_all",
741                   G_TYPE_FROM_CLASS (object_class),
742                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
743                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
744                   NULL, NULL,
745                   _gtk_marshal_NONE__NONE,
746                   GTK_TYPE_NONE, 0);
747
748   tree_view_signals[SELECT_CURSOR_ROW] =
749     g_signal_new ("select_cursor_row",
750                   G_TYPE_FROM_CLASS (object_class),
751                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
752                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
753                   NULL, NULL,
754                   _gtk_marshal_VOID__BOOLEAN,
755                   GTK_TYPE_NONE, 1,
756                   G_TYPE_BOOLEAN);
757
758   tree_view_signals[TOGGLE_CURSOR_ROW] =
759     g_signal_new ("toggle_cursor_row",
760                   G_TYPE_FROM_CLASS (object_class),
761                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
762                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
763                   NULL, NULL,
764                   _gtk_marshal_NONE__NONE,
765                   GTK_TYPE_NONE, 0);
766
767   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
768     g_signal_new ("expand_collapse_cursor_row",
769                   G_TYPE_FROM_CLASS (object_class),
770                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
771                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
772                   NULL, NULL,
773                   _gtk_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN,
774                   GTK_TYPE_NONE, 3, GTK_TYPE_BOOL, GTK_TYPE_BOOL, GTK_TYPE_BOOL);
775
776   tree_view_signals[SELECT_CURSOR_PARENT] =
777     g_signal_new ("select_cursor_parent",
778                   G_TYPE_FROM_CLASS (object_class),
779                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
780                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
781                   NULL, NULL,
782                   _gtk_marshal_NONE__NONE,
783                   GTK_TYPE_NONE, 0);
784
785   tree_view_signals[START_INTERACTIVE_SEARCH] =
786     g_signal_new ("start_interactive_search",
787                   G_TYPE_FROM_CLASS (object_class),
788                   G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
789                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
790                   NULL, NULL,
791                   _gtk_marshal_NONE__NONE,
792                   GTK_TYPE_NONE, 0);
793
794   /* Key bindings */
795   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0,
796                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
797
798   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0,
799                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
800
801   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
802                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
803
804   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
805                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
806
807   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0,
808                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
809
810   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0,
811                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
812
813   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0,
814                                   GTK_MOVEMENT_PAGES, -1);
815
816   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0,
817                                   GTK_MOVEMENT_PAGES, 1);
818
819   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move_cursor", 2,
820                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
821                                 GTK_TYPE_INT, 1);
822
823   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move_cursor", 2,
824                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
825                                 GTK_TYPE_INT, -1);
826
827   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK, "move_cursor", 2,
828                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
829                                 GTK_TYPE_INT, 1);
830
831   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK, "move_cursor", 2,
832                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
833                                 GTK_TYPE_INT, -1);
834
835   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK|GDK_SHIFT_MASK, "move_cursor", 2,
836                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
837                                 GTK_TYPE_INT, 1);
838
839   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK|GDK_SHIFT_MASK, "move_cursor", 2,
840                                 GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
841                                 GTK_TYPE_INT, -1);
842
843   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_row", 0);
844
845   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
846   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select_all", 0);
847
848   gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect_all", 0);
849   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect_all", 0);
850
851   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select_cursor_row", 1,
852                                 GTK_TYPE_BOOL, TRUE);
853
854   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 1,
855                                 GTK_TYPE_BOOL, TRUE);
856
857   /* expand and collapse rows */
858   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3,
859                                 GTK_TYPE_BOOL, FALSE,
860                                 GTK_TYPE_BOOL, TRUE,
861                                 GTK_TYPE_BOOL, FALSE);
862   /* Not doable on US keyboards */
863   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
864                                 GTK_TYPE_BOOL, FALSE,
865                                 GTK_TYPE_BOOL, TRUE,
866                                 GTK_TYPE_BOOL, TRUE);
867   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand_collapse_cursor_row", 3,
868                                 GTK_TYPE_BOOL, FALSE,
869                                 GTK_TYPE_BOOL, TRUE,
870                                 GTK_TYPE_BOOL, FALSE);
871   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
872                                 GTK_TYPE_BOOL, FALSE,
873                                 GTK_TYPE_BOOL, TRUE,
874                                 GTK_TYPE_BOOL, TRUE);
875   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
876                                 GTK_TYPE_BOOL, FALSE,
877                                 GTK_TYPE_BOOL, TRUE,
878                                 GTK_TYPE_BOOL, TRUE);
879   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
880                                 GTK_TYPE_BOOL, TRUE,
881                                 GTK_TYPE_BOOL, TRUE,
882                                 GTK_TYPE_BOOL, TRUE);
883
884   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand_collapse_cursor_row", 3,
885                                 GTK_TYPE_BOOL, FALSE,
886                                 GTK_TYPE_BOOL, FALSE,
887                                 GTK_TYPE_BOOL, FALSE);
888   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
889                                 GTK_TYPE_BOOL, FALSE,
890                                 GTK_TYPE_BOOL, FALSE,
891                                 GTK_TYPE_BOOL, TRUE);
892   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand_collapse_cursor_row", 3,
893                                 GTK_TYPE_BOOL, FALSE,
894                                 GTK_TYPE_BOOL, FALSE,
895                                 GTK_TYPE_BOOL, FALSE);
896   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
897                                 GTK_TYPE_BOOL, FALSE,
898                                 GTK_TYPE_BOOL, FALSE,
899                                 GTK_TYPE_BOOL, TRUE);
900   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
901                                 GTK_TYPE_BOOL, FALSE,
902                                 GTK_TYPE_BOOL, FALSE,
903                                 GTK_TYPE_BOOL, TRUE);
904
905   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
906
907   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start_interactive_search", 0);
908
909   gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start_interactive_search", 0);
910 }
911
912 static void
913 gtk_tree_view_init (GtkTreeView *tree_view)
914 {
915   tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
916   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
917
918   tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
919
920   /* We need some padding */
921   tree_view->priv->dy = 0;
922   tree_view->priv->n_columns = 0;
923   tree_view->priv->header_height = 1;
924   tree_view->priv->x_drag = 0;
925   tree_view->priv->drag_pos = -1;
926   tree_view->priv->header_has_focus = FALSE;
927   tree_view->priv->pressed_button = -1;
928   tree_view->priv->press_start_x = -1;
929   tree_view->priv->press_start_y = -1;
930   tree_view->priv->reorderable = FALSE;
931   tree_view->priv->presize_handler_timer = 0;
932   tree_view->priv->scroll_sync_timer = 0;
933   tree_view->priv->fixed_height_check = 0;
934   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
935   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
936   tree_view->priv->enable_search = TRUE;
937   tree_view->priv->search_column = -1;
938   tree_view->priv->search_dialog_position_func = gtk_tree_view_search_position_func;
939   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
940 }
941
942 \f
943
944 /* GObject Methods
945  */
946
947 static void
948 gtk_tree_view_set_property (GObject         *object,
949                             guint            prop_id,
950                             const GValue    *value,
951                             GParamSpec      *pspec)
952 {
953   GtkTreeView *tree_view;
954
955   tree_view = GTK_TREE_VIEW (object);
956
957   switch (prop_id)
958     {
959     case PROP_MODEL:
960       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
961       break;
962     case PROP_HADJUSTMENT:
963       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
964       break;
965     case PROP_VADJUSTMENT:
966       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
967       break;
968     case PROP_HEADERS_VISIBLE:
969       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
970       break;
971     case PROP_HEADERS_CLICKABLE:
972       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
973       break;
974     case PROP_EXPANDER_COLUMN:
975       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
976       break;
977     case PROP_REORDERABLE:
978       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
979       break;
980     case PROP_RULES_HINT:
981       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
982       break;
983     case PROP_ENABLE_SEARCH:
984       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
985       break;
986     case PROP_SEARCH_COLUMN:
987       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
988       break;
989     default:
990       break;
991     }
992 }
993
994 static void
995 gtk_tree_view_get_property (GObject    *object,
996                             guint       prop_id,
997                             GValue     *value,
998                             GParamSpec *pspec)
999 {
1000   GtkTreeView *tree_view;
1001
1002   tree_view = GTK_TREE_VIEW (object);
1003
1004   switch (prop_id)
1005     {
1006     case PROP_MODEL:
1007       g_value_set_object (value, tree_view->priv->model);
1008       break;
1009     case PROP_HADJUSTMENT:
1010       g_value_set_object (value, tree_view->priv->hadjustment);
1011       break;
1012     case PROP_VADJUSTMENT:
1013       g_value_set_object (value, tree_view->priv->vadjustment);
1014       break;
1015     case PROP_HEADERS_VISIBLE:
1016       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1017       break;
1018     case PROP_EXPANDER_COLUMN:
1019       g_value_set_object (value, tree_view->priv->expander_column);
1020       break;
1021     case PROP_REORDERABLE:
1022       g_value_set_boolean (value, tree_view->priv->reorderable);
1023       break;
1024     case PROP_RULES_HINT:
1025       g_value_set_boolean (value, tree_view->priv->has_rules);
1026       break;
1027     case PROP_ENABLE_SEARCH:
1028       g_value_set_boolean (value, tree_view->priv->enable_search);
1029       break;
1030     case PROP_SEARCH_COLUMN:
1031       g_value_set_int (value, tree_view->priv->search_column);
1032       break;
1033     default:
1034       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1035       break;
1036     }
1037 }
1038
1039 static void
1040 gtk_tree_view_finalize (GObject *object)
1041 {
1042   GtkTreeView *tree_view = (GtkTreeView *) object;
1043
1044   g_free (tree_view->priv);
1045
1046   if (G_OBJECT_CLASS (parent_class)->finalize)
1047     (* G_OBJECT_CLASS (parent_class)->finalize) (object);
1048 }
1049
1050 \f
1051
1052 /* GtkObject Methods
1053  */
1054
1055 static void
1056 gtk_tree_view_destroy (GtkObject *object)
1057 {
1058   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1059   GtkWidget *search_dialog;
1060   GList *list;
1061
1062   gtk_tree_view_stop_editing (tree_view, TRUE);
1063
1064   if (tree_view->priv->columns != NULL)
1065     {
1066       list = tree_view->priv->columns;
1067       while (list)
1068         {
1069           GtkTreeViewColumn *column;
1070           column = GTK_TREE_VIEW_COLUMN (list->data);
1071           list = list->next;
1072           gtk_tree_view_remove_column (tree_view, column);
1073         }
1074       tree_view->priv->columns = NULL;
1075     }
1076
1077   if (tree_view->priv->tree != NULL)
1078     {
1079       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1080       _gtk_rbtree_free (tree_view->priv->tree);
1081       tree_view->priv->tree = NULL;
1082     }
1083
1084   if (tree_view->priv->selection != NULL)
1085     {
1086       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1087       g_object_unref (tree_view->priv->selection);
1088       tree_view->priv->selection = NULL;
1089     }
1090
1091   if (tree_view->priv->scroll_to_path != NULL)
1092     {
1093       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1094       tree_view->priv->scroll_to_path = NULL;
1095     }
1096
1097   if (tree_view->priv->drag_dest_row != NULL)
1098     {
1099       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1100       tree_view->priv->drag_dest_row = NULL;
1101     }
1102
1103   if (tree_view->priv->last_button_press != NULL)
1104     {
1105       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
1106       tree_view->priv->last_button_press = NULL;
1107     }
1108
1109   if (tree_view->priv->last_button_press_2 != NULL)
1110     {
1111       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
1112       tree_view->priv->last_button_press_2 = NULL;
1113     }
1114
1115   if (tree_view->priv->top_row != NULL)
1116     {
1117       gtk_tree_row_reference_free (tree_view->priv->top_row);
1118       tree_view->priv->top_row = NULL;
1119     }
1120
1121   if (tree_view->priv->column_drop_func_data &&
1122       tree_view->priv->column_drop_func_data_destroy)
1123     {
1124       (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
1125       tree_view->priv->column_drop_func_data = NULL;
1126     }
1127
1128   if (tree_view->priv->destroy_count_destroy &&
1129       tree_view->priv->destroy_count_data)
1130     {
1131       (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
1132       tree_view->priv->destroy_count_data = NULL;
1133     }
1134
1135   gtk_tree_row_reference_free (tree_view->priv->cursor);
1136   tree_view->priv->cursor = NULL;
1137
1138   gtk_tree_row_reference_free (tree_view->priv->anchor);
1139   tree_view->priv->anchor = NULL;
1140
1141   /* destroy interactive search dialog */
1142   search_dialog = gtk_object_get_data (GTK_OBJECT (tree_view),
1143                                        GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
1144   if (search_dialog)
1145     gtk_tree_view_search_dialog_destroy (search_dialog,
1146                                          tree_view);
1147
1148   if (tree_view->priv->search_user_data)
1149     {
1150       (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
1151       tree_view->priv->search_user_data = NULL;
1152     }
1153
1154   gtk_tree_view_set_model (tree_view, NULL);
1155
1156   if (GTK_OBJECT_CLASS (parent_class)->destroy)
1157     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1158 }
1159
1160 \f
1161
1162 /* GtkWidget Methods
1163  */
1164
1165 /* GtkWidget::map helper */
1166 static void
1167 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1168 {
1169   GList *list;
1170
1171   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1172
1173   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1174     {
1175       GtkTreeViewColumn *column;
1176
1177       for (list = tree_view->priv->columns; list; list = list->next)
1178         {
1179           column = list->data;
1180           if (GTK_WIDGET_VISIBLE (column->button) &&
1181               !GTK_WIDGET_MAPPED (column->button))
1182             gtk_widget_map (column->button);
1183         }
1184       for (list = tree_view->priv->columns; list; list = list->next)
1185         {
1186           column = list->data;
1187           if (column->visible == FALSE)
1188             continue;
1189           if (column->resizable)
1190             {
1191               gdk_window_raise (column->window);
1192               gdk_window_show (column->window);
1193             }
1194           else
1195             gdk_window_hide (column->window);
1196         }
1197       gdk_window_show (tree_view->priv->header_window);
1198     }
1199 }
1200
1201 static void
1202 gtk_tree_view_map (GtkWidget *widget)
1203 {
1204   GList *tmp_list;
1205   GtkTreeView *tree_view;
1206
1207   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1208
1209   tree_view = GTK_TREE_VIEW (widget);
1210
1211   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1212
1213   tmp_list = tree_view->priv->children;
1214   while (tmp_list)
1215     {
1216       GtkTreeViewChild *child = tmp_list->data;
1217       tmp_list = tmp_list->next;
1218
1219       if (GTK_WIDGET_VISIBLE (child->widget))
1220         {
1221           if (!GTK_WIDGET_MAPPED (child->widget))
1222             gtk_widget_map (child->widget);
1223         }
1224     }
1225   gdk_window_show (tree_view->priv->bin_window);
1226
1227   gtk_tree_view_map_buttons (tree_view);
1228
1229   gdk_window_show (widget->window);
1230 }
1231
1232 static void
1233 gtk_tree_view_realize (GtkWidget *widget)
1234 {
1235   GList *tmp_list;
1236   GtkTreeView *tree_view;
1237   GdkGCValues values;
1238   GdkWindowAttr attributes;
1239   gint attributes_mask;
1240
1241   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1242
1243   tree_view = GTK_TREE_VIEW (widget);
1244
1245   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1246
1247   /* Make the main, clipping window */
1248   attributes.window_type = GDK_WINDOW_CHILD;
1249   attributes.x = widget->allocation.x;
1250   attributes.y = widget->allocation.y;
1251   attributes.width = widget->allocation.width;
1252   attributes.height = widget->allocation.height;
1253   attributes.wclass = GDK_INPUT_OUTPUT;
1254   attributes.visual = gtk_widget_get_visual (widget);
1255   attributes.colormap = gtk_widget_get_colormap (widget);
1256   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1257
1258   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1259
1260   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1261                                    &attributes, attributes_mask);
1262   gdk_window_set_user_data (widget->window, widget);
1263
1264   /* Make the window for the tree */
1265   attributes.x = 0;
1266   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1267   attributes.width = tree_view->priv->width;
1268   attributes.height = widget->allocation.height;
1269   attributes.event_mask = GDK_EXPOSURE_MASK |
1270     GDK_SCROLL_MASK |
1271     GDK_POINTER_MOTION_MASK |
1272     GDK_ENTER_NOTIFY_MASK |
1273     GDK_LEAVE_NOTIFY_MASK |
1274     GDK_BUTTON_PRESS_MASK |
1275     GDK_BUTTON_RELEASE_MASK |
1276     gtk_widget_get_events (widget);
1277
1278   tree_view->priv->bin_window = gdk_window_new (widget->window,
1279                                                 &attributes, attributes_mask);
1280   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1281
1282   /* Make the column header window */
1283   attributes.x = 0;
1284   attributes.y = 0;
1285   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1286   attributes.height = tree_view->priv->header_height;
1287   attributes.event_mask = (GDK_EXPOSURE_MASK |
1288                            GDK_SCROLL_MASK |
1289                            GDK_BUTTON_PRESS_MASK |
1290                            GDK_BUTTON_RELEASE_MASK |
1291                            GDK_KEY_PRESS_MASK |
1292                            GDK_KEY_RELEASE_MASK) |
1293     gtk_widget_get_events (widget);
1294
1295   tree_view->priv->header_window = gdk_window_new (widget->window,
1296                                                    &attributes, attributes_mask);
1297   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1298
1299
1300   values.foreground = (widget->style->white.pixel==0 ?
1301                        widget->style->black:widget->style->white);
1302   values.function = GDK_XOR;
1303   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1304
1305   /* Add them all up. */
1306   widget->style = gtk_style_attach (widget->style, widget->window);
1307   gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1308   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1309   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1310
1311   tmp_list = tree_view->priv->children;
1312   while (tmp_list)
1313     {
1314       GtkTreeViewChild *child = tmp_list->data;
1315       tmp_list = tmp_list->next;
1316
1317       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1318     }
1319
1320   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1321     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1322
1323   install_presize_handler (tree_view); 
1324 }
1325
1326 static void
1327 gtk_tree_view_unrealize (GtkWidget *widget)
1328 {
1329   GtkTreeView *tree_view;
1330   GList *list;
1331
1332   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1333
1334   tree_view = GTK_TREE_VIEW (widget);
1335
1336   if (tree_view->priv->scroll_timeout != 0)
1337     {
1338       gtk_timeout_remove (tree_view->priv->scroll_timeout);
1339       tree_view->priv->scroll_timeout = 0;
1340     }
1341
1342   if (tree_view->priv->open_dest_timeout != 0)
1343     {
1344       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
1345       tree_view->priv->open_dest_timeout = 0;
1346     }
1347
1348   if (tree_view->priv->expand_collapse_timeout != 0)
1349     {
1350       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
1351       tree_view->priv->expand_collapse_timeout = 0;
1352     }
1353   
1354   if (tree_view->priv->presize_handler_timer != 0)
1355     {
1356       gtk_timeout_remove (tree_view->priv->presize_handler_timer);
1357       tree_view->priv->presize_handler_timer = 0;
1358     }
1359
1360   if (tree_view->priv->validate_rows_timer != 0)
1361     {
1362       gtk_timeout_remove (tree_view->priv->validate_rows_timer);
1363       tree_view->priv->validate_rows_timer = 0;
1364     }
1365
1366   if (tree_view->priv->scroll_sync_timer != 0)
1367     {
1368       gtk_timeout_remove (tree_view->priv->scroll_sync_timer);
1369       tree_view->priv->scroll_sync_timer = 0;
1370     }
1371
1372   for (list = tree_view->priv->columns; list; list = list->next)
1373     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1374
1375   gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
1376   gdk_window_destroy (tree_view->priv->bin_window);
1377   tree_view->priv->bin_window = NULL;
1378
1379   gdk_window_set_user_data (tree_view->priv->header_window, NULL);
1380   gdk_window_destroy (tree_view->priv->header_window);
1381   tree_view->priv->header_window = NULL;
1382
1383   if (tree_view->priv->drag_window)
1384     {
1385       gdk_window_set_user_data (tree_view->priv->drag_window, NULL);
1386       gdk_window_destroy (tree_view->priv->drag_window);
1387       tree_view->priv->drag_window = NULL;
1388     }
1389
1390   if (tree_view->priv->drag_highlight_window)
1391     {
1392       gdk_window_set_user_data (tree_view->priv->drag_highlight_window, NULL);
1393       gdk_window_destroy (tree_view->priv->drag_highlight_window);
1394       tree_view->priv->drag_highlight_window = NULL;
1395     }
1396
1397   /* GtkWidget::unrealize destroys children and widget->window */
1398   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1399     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1400 }
1401
1402 /* GtkWidget::size_request helper */
1403 static void
1404 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1405 {
1406   GList *list;
1407
1408   tree_view->priv->header_height = 0;
1409
1410   if (tree_view->priv->model)
1411     {
1412       for (list = tree_view->priv->columns; list; list = list->next)
1413         {
1414           GtkRequisition requisition;
1415           GtkTreeViewColumn *column = list->data;
1416
1417           if (column->button == NULL)
1418             continue;
1419
1420           column = list->data;
1421           
1422           gtk_widget_size_request (column->button, &requisition);
1423           column->button_request = requisition.width;
1424           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1425         }
1426     }
1427 }
1428
1429
1430 static void
1431 gtk_tree_view_update_size (GtkTreeView *tree_view)
1432 {
1433   GList *list;
1434   GtkTreeViewColumn *column;
1435   gint i;
1436
1437   if (tree_view->priv->model == NULL)
1438     {
1439       tree_view->priv->width = 0;
1440       tree_view->priv->height = 0;
1441       return;
1442     }
1443
1444   tree_view->priv->width = 0;
1445   /* keep this in sync with size_allocate below */
1446   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1447     {
1448       gint real_requested_width = 0;
1449       column = list->data;
1450       if (!column->visible)
1451         continue;
1452
1453       if (column->use_resized_width)
1454         {
1455           real_requested_width = column->resized_width;
1456         }
1457       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1458         {
1459           real_requested_width = column->fixed_width;
1460         }
1461       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1462         {
1463           real_requested_width = MAX (column->requested_width, column->button_request);
1464         }
1465       else
1466         {
1467           real_requested_width = column->requested_width;
1468         }
1469
1470       if (column->min_width != -1)
1471         real_requested_width = MAX (real_requested_width, column->min_width);
1472       if (column->max_width != -1)
1473         real_requested_width = MIN (real_requested_width, column->max_width);
1474
1475       tree_view->priv->width += real_requested_width;
1476     }
1477
1478   if (tree_view->priv->tree == NULL)
1479     tree_view->priv->height = 0;
1480   else
1481     tree_view->priv->height = tree_view->priv->tree->root->offset;
1482 }
1483
1484 static void
1485 gtk_tree_view_size_request (GtkWidget      *widget,
1486                             GtkRequisition *requisition)
1487 {
1488   GtkTreeView *tree_view;
1489   GList *tmp_list;
1490
1491   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1492
1493   tree_view = GTK_TREE_VIEW (widget);
1494
1495   /* we validate 50 rows initially just to make sure we have some size */
1496   /* in practice, with a lot of static lists, this should get a good width */
1497   do_validate_rows (tree_view);
1498   gtk_tree_view_size_request_columns (tree_view);
1499   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
1500
1501   requisition->width = tree_view->priv->width;
1502   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
1503
1504   tmp_list = tree_view->priv->children;
1505
1506   while (tmp_list)
1507     {
1508       GtkTreeViewChild *child = tmp_list->data;
1509       GtkRequisition child_requisition;
1510
1511       tmp_list = tmp_list->next;
1512
1513       if (GTK_WIDGET_VISIBLE (child->widget))
1514         gtk_widget_size_request (child->widget, &child_requisition);
1515     }
1516 }
1517
1518 /* GtkWidget::size_allocate helper */
1519 static void
1520 gtk_tree_view_size_allocate_columns (GtkWidget *widget)
1521 {
1522   GtkTreeView *tree_view;
1523   GList *list, *last_column;
1524   GtkTreeViewColumn *column;
1525   GtkAllocation allocation;
1526   gint width = 0;
1527
1528   tree_view = GTK_TREE_VIEW (widget);
1529
1530   for (last_column = g_list_last (tree_view->priv->columns);
1531        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
1532        last_column = last_column->prev)
1533     ;
1534   if (last_column == NULL)
1535     return;
1536
1537   allocation.y = 0;
1538   allocation.height = tree_view->priv->header_height;
1539
1540   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
1541     {
1542       gint real_requested_width = 0;
1543       column = list->data;
1544       if (!column->visible)
1545         continue;
1546
1547       /* We need to handle the dragged button specially.
1548        */
1549       if (column == tree_view->priv->drag_column)
1550         {
1551           GtkAllocation drag_allocation;
1552           gdk_window_get_size (tree_view->priv->drag_window,
1553                                &(drag_allocation.width), &(drag_allocation.height));
1554           drag_allocation.x = 0;
1555           drag_allocation.y = 0;
1556           gtk_widget_size_allocate (tree_view->priv->drag_column->button, &drag_allocation);
1557           width += drag_allocation.width;
1558           continue;
1559         }
1560
1561       if (column->use_resized_width)
1562         {
1563           real_requested_width = column->resized_width;
1564         }
1565       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1566         {
1567           real_requested_width = column->fixed_width;
1568         }
1569       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1570         {
1571           real_requested_width = MAX (column->requested_width, column->button_request);
1572         }
1573       else
1574         {
1575           real_requested_width = column->requested_width;
1576           if (real_requested_width < 0)
1577             real_requested_width = 0;
1578         }
1579
1580       if (column->min_width != -1)
1581         real_requested_width = MAX (real_requested_width, column->min_width);
1582       if (column->max_width != -1)
1583         real_requested_width = MIN (real_requested_width, column->max_width);
1584
1585       allocation.x = width;
1586       column->width = real_requested_width;
1587       if (list == last_column &&
1588           width + real_requested_width < widget->allocation.width)
1589         {
1590           column->width += (widget->allocation.width - column->width - width);
1591         }
1592       g_object_notify (G_OBJECT (column), "width");
1593       allocation.width = column->width;
1594       width += column->width;
1595       gtk_widget_size_allocate (column->button, &allocation);
1596       if (column->window)
1597         gdk_window_move_resize (column->window,
1598                                 allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
1599                                 allocation.y,
1600                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
1601     }
1602 }
1603
1604 static void
1605 gtk_tree_view_size_allocate (GtkWidget     *widget,
1606                              GtkAllocation *allocation)
1607 {
1608   GList *tmp_list;
1609   GtkTreeView *tree_view;
1610
1611   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1612
1613   widget->allocation = *allocation;
1614
1615   tree_view = GTK_TREE_VIEW (widget);
1616
1617   tmp_list = tree_view->priv->children;
1618
1619   while (tmp_list)
1620     {
1621       GtkAllocation allocation;
1622
1623       GtkTreeViewChild *child = tmp_list->data;
1624       tmp_list = tmp_list->next;
1625
1626       /* totally ignore our childs requisition */
1627       allocation.x = child->x;
1628       allocation.y = child->y;
1629       allocation.width = child->width;
1630       allocation.height = child->height;
1631       gtk_widget_size_allocate (child->widget, &allocation);
1632     }
1633
1634
1635   tree_view->priv->hadjustment->page_size = allocation->width;
1636   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
1637   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
1638   tree_view->priv->hadjustment->lower = 0;
1639   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
1640
1641   if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
1642     tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
1643   gtk_adjustment_changed (tree_view->priv->hadjustment);
1644
1645   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
1646   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
1647   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
1648   tree_view->priv->vadjustment->lower = 0;
1649   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
1650
1651   if (tree_view->priv->vadjustment->value + allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view) > tree_view->priv->height)
1652     gtk_adjustment_set_value (tree_view->priv->vadjustment,
1653                               MAX (tree_view->priv->height - tree_view->priv->vadjustment->page_size, 0));
1654   gtk_adjustment_changed (tree_view->priv->vadjustment);
1655   
1656   if (GTK_WIDGET_REALIZED (widget))
1657     {
1658       gdk_window_move_resize (widget->window,
1659                               allocation->x, allocation->y,
1660                               allocation->width, allocation->height);
1661       gdk_window_move_resize (tree_view->priv->header_window,
1662                               - (gint) tree_view->priv->hadjustment->value,
1663                               0,
1664                               MAX (tree_view->priv->width, allocation->width),
1665                               tree_view->priv->header_height);
1666       gdk_window_move_resize (tree_view->priv->bin_window,
1667                               - (gint) tree_view->priv->hadjustment->value,
1668                               TREE_VIEW_HEADER_HEIGHT (tree_view),
1669                               MAX (tree_view->priv->width, allocation->width),
1670                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
1671     }
1672
1673   gtk_tree_view_size_allocate_columns (widget);
1674 }
1675
1676 static gboolean
1677 gtk_tree_view_button_press (GtkWidget      *widget,
1678                             GdkEventButton *event)
1679 {
1680   GtkTreeView *tree_view;
1681   GList *list;
1682   GtkTreeViewColumn *column = NULL;
1683   gint i;
1684   GdkRectangle background_area;
1685   GdkRectangle cell_area;
1686   gint vertical_separator;
1687   gint horizontal_separator;
1688
1689   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1690   g_return_val_if_fail (event != NULL, FALSE);
1691
1692   tree_view = GTK_TREE_VIEW (widget);
1693   gtk_tree_view_stop_editing (tree_view, FALSE);
1694   gtk_widget_style_get (widget,
1695                         "vertical_separator", &vertical_separator,
1696                         "horizontal_separator", &horizontal_separator,
1697                         NULL);
1698
1699   if (event->window == tree_view->priv->bin_window &&
1700       tree_view->priv->tree != NULL)
1701     {
1702       GtkRBNode *node;
1703       GtkRBTree *tree;
1704       GtkTreePath *path;
1705       gchar *path_string;
1706       gint depth;
1707       gint new_y;
1708       gint y_offset;
1709       gint dval;
1710       gint pre_val, aft_val;
1711       GtkTreeViewColumn *column = NULL;
1712       gint column_handled_click = FALSE;
1713       gboolean emit_row_activated = FALSE;
1714
1715       if (!GTK_WIDGET_HAS_FOCUS (widget))
1716         gtk_widget_grab_focus (widget);
1717       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1718
1719       /* are we in an arrow? */
1720       if (tree_view->priv->prelight_node &&
1721           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1722         {
1723           if (event->button == 1)
1724             {
1725               gtk_grab_add (widget);
1726               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1727               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1728               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1729                                         tree_view->priv->prelight_tree,
1730                                         tree_view->priv->prelight_node,
1731                                         event->x,
1732                                         event->y);
1733             }
1734           return TRUE;
1735         }
1736
1737       /* find the node that was clicked */
1738       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
1739       if (new_y < 0)
1740         new_y = 0;
1741       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
1742
1743       if (node == NULL)
1744         /* We clicked in dead space */
1745         return TRUE;
1746
1747       /* Get the path and the node */
1748       path = _gtk_tree_view_find_path (tree_view, tree, node);
1749       depth = gtk_tree_path_get_depth (path);
1750       background_area.y = y_offset + event->y;
1751       background_area.height = MAX (GTK_RBNODE_GET_HEIGHT (node),
1752                                     tree_view->priv->expander_size);
1753       background_area.x = 0;
1754
1755       /* Let the column have a chance at selecting it. */
1756       for (list = tree_view->priv->columns; list; list = list->next)
1757         {
1758           column = list->data;
1759
1760           if (!column->visible)
1761             continue;
1762
1763           background_area.width = column->width;
1764           if ((background_area.x > (gint) event->x) ||
1765               (background_area.x + background_area.width <= (gint) event->x))
1766             {
1767               background_area.x += background_area.width;
1768               continue;
1769             }
1770
1771           /* we found the focus column */
1772           cell_area = background_area;
1773           cell_area.width -= horizontal_separator;
1774           cell_area.height -= vertical_separator;
1775           cell_area.x += horizontal_separator/2;
1776           cell_area.y += vertical_separator/2;
1777           if (gtk_tree_view_is_expander_column (tree_view, column) &&
1778               TREE_VIEW_DRAW_EXPANDERS(tree_view))
1779             {
1780               cell_area.x += depth * tree_view->priv->expander_size;
1781               cell_area.width -= depth * tree_view->priv->expander_size;
1782             }
1783           break;
1784         }
1785
1786       if (column == NULL)
1787         return FALSE;
1788
1789       /* decide if we edit */
1790       if (event->type == GDK_BUTTON_PRESS &&
1791           !(event->state & gtk_accelerator_get_default_mod_mask ()))
1792         {
1793           GtkTreePath *anchor;
1794           GtkTreeIter iter;
1795
1796           if (tree_view->priv->anchor)
1797             {
1798               anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
1799               gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
1800               gtk_tree_view_column_cell_set_cell_data (column,
1801                                                        tree_view->priv->model,
1802                                                        &iter,
1803                                                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
1804                                                        node->children?TRUE:FALSE);
1805             }
1806           else
1807             anchor = NULL;
1808
1809           if ((anchor && !gtk_tree_path_compare (anchor, path))
1810               || !_gtk_tree_view_column_has_editable_cell (column))
1811             {
1812               GtkCellEditable *cell_editable = NULL;
1813
1814               /* FIXME: get the right flags */
1815               guint flags = 0;
1816
1817               path_string = gtk_tree_path_to_string (path);
1818
1819               if (_gtk_tree_view_column_cell_event (column,
1820                                                     &cell_editable,
1821                                                     (GdkEvent *)event,
1822                                                     path_string,
1823                                                     &background_area,
1824                                                     &cell_area, flags))
1825                 {
1826                   if (cell_editable != NULL)
1827                     {
1828                       gint left, right;
1829                       GdkRectangle area;
1830
1831                       area = cell_area;
1832                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_editable_cell (column), &left, &right);
1833
1834                       area.x += left;
1835                       area.width -= right + left;
1836
1837                       gtk_tree_view_real_start_editing (tree_view,
1838                                                         column,
1839                                                         path,
1840                                                         cell_editable,
1841                                                         &area,
1842                                                         (GdkEvent *)event,
1843                                                         flags);
1844                       gtk_tree_path_free (path);
1845                       gtk_tree_path_free (anchor);
1846                       return TRUE;
1847                     }
1848                   column_handled_click = TRUE;
1849                 }
1850               g_free (path_string);
1851             }
1852           if (anchor)
1853             gtk_tree_path_free (anchor);
1854         }
1855
1856       /* select */
1857       pre_val = tree_view->priv->vadjustment->value;
1858
1859       tree_view->priv->focus_column = column;
1860       if (event->state & GDK_CONTROL_MASK)
1861         {
1862           gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
1863           gtk_tree_view_real_toggle_cursor_row (tree_view);
1864         }
1865       else if (event->state & GDK_SHIFT_MASK)
1866         {
1867           gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
1868           gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
1869         }
1870       else
1871         {
1872           gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
1873         }
1874
1875       /* the treeview may have been scrolled because of _set_cursor,
1876        * correct here
1877        */
1878
1879       aft_val = tree_view->priv->vadjustment->value;
1880       dval = pre_val - aft_val;
1881
1882       cell_area.y += dval;
1883       background_area.y += dval;
1884
1885       /* Save press to possibly begin a drag
1886        */
1887       if (!column_handled_click &&
1888           tree_view->priv->pressed_button < 0)
1889         {
1890           tree_view->priv->pressed_button = event->button;
1891           tree_view->priv->press_start_x = event->x;
1892           tree_view->priv->press_start_y = event->y;
1893         }
1894
1895       if (event->button == 1 && event->type == GDK_2BUTTON_PRESS &&
1896           tree_view->priv->last_button_press)
1897         {
1898           GtkTreePath *lsc;
1899
1900           lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
1901
1902           if (tree_view->priv->last_button_press)
1903             gtk_tree_row_reference_free (tree_view->priv->last_button_press);
1904           if (tree_view->priv->last_button_press_2)
1905             gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
1906           tree_view->priv->last_button_press = NULL;
1907           tree_view->priv->last_button_press_2 = NULL;
1908
1909           if (lsc)
1910             {
1911               if (!gtk_tree_path_compare (lsc, path))
1912                 emit_row_activated = TRUE;
1913               gtk_tree_path_free (lsc);
1914             }
1915         }
1916       else if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1917         {
1918           if (tree_view->priv->last_button_press)
1919             gtk_tree_row_reference_free (tree_view->priv->last_button_press);
1920           tree_view->priv->last_button_press = tree_view->priv->last_button_press_2;
1921           tree_view->priv->last_button_press_2 = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
1922         }
1923
1924       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1925
1926       if (emit_row_activated)
1927         {
1928           gtk_grab_remove (widget);
1929           gtk_tree_view_row_activated (tree_view, path, column);
1930         }
1931
1932       gtk_tree_path_free (path);
1933
1934       return TRUE;
1935     }
1936
1937   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
1938    */
1939   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
1940     {
1941       column = list->data;
1942       if (event->window == column->window &&
1943           column->resizable &&
1944           column->window)
1945         {
1946           gpointer drag_data;
1947
1948           if (event->type == GDK_2BUTTON_PRESS &&
1949               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1950             {
1951               _gtk_tree_view_column_autosize (tree_view, column);
1952               break;
1953             }
1954
1955           if (gdk_pointer_grab (column->window, FALSE,
1956                                 GDK_POINTER_MOTION_HINT_MASK |
1957                                 GDK_BUTTON1_MOTION_MASK |
1958                                 GDK_BUTTON_RELEASE_MASK,
1959                                 NULL, NULL, event->time))
1960             return FALSE;
1961
1962           gtk_grab_add (widget);
1963           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1964           column->resized_width = column->width;
1965           column->use_resized_width = TRUE;
1966
1967           /* block attached dnd signal handler */
1968           drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1969           if (drag_data)
1970             gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1971
1972           if (!GTK_WIDGET_HAS_FOCUS (widget))
1973             gtk_widget_grab_focus (widget);
1974
1975           tree_view->priv->drag_pos = i;
1976           tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1977           break;
1978         }
1979     }
1980   return TRUE;
1981 }
1982
1983 /* GtkWidget::button_release_event helper */
1984 static gboolean
1985 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
1986                                           GdkEventButton *event)
1987 {
1988   GtkTreeView *tree_view;
1989
1990   tree_view = GTK_TREE_VIEW (widget);
1991
1992   gdk_pointer_ungrab (GDK_CURRENT_TIME);
1993   gdk_keyboard_ungrab (GDK_CURRENT_TIME);
1994
1995   /* Move the button back */
1996   g_object_ref (tree_view->priv->drag_column->button);
1997   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
1998   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
1999   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2000   g_object_unref (tree_view->priv->drag_column->button);
2001   gtk_widget_queue_resize (widget);
2002   if (tree_view->priv->drag_column->resizable)
2003     {
2004       gdk_window_raise (tree_view->priv->drag_column->window);
2005       gdk_window_show (tree_view->priv->drag_column->window);
2006     }
2007   else
2008     gdk_window_hide (tree_view->priv->drag_column->window);
2009
2010   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2011
2012   if (tree_view->priv->cur_reorder &&
2013       tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2014     gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2015                                      tree_view->priv->cur_reorder->left_column);
2016   tree_view->priv->drag_column = NULL;
2017   gdk_window_hide (tree_view->priv->drag_window);
2018
2019   g_list_foreach (tree_view->priv->column_drag_info, (GFunc) g_free, NULL);
2020   g_list_free (tree_view->priv->column_drag_info);
2021   tree_view->priv->column_drag_info = NULL;
2022
2023   gdk_window_hide (tree_view->priv->drag_highlight_window);
2024
2025   /* Reset our flags */
2026   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
2027   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
2028
2029   return TRUE;
2030 }
2031
2032 /* GtkWidget::button_release_event helper */
2033 static gboolean
2034 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
2035                                             GdkEventButton *event)
2036 {
2037   GtkTreeView *tree_view;
2038   gpointer drag_data;
2039   gint x;
2040   gint i;
2041
2042   tree_view = GTK_TREE_VIEW (widget);
2043
2044   i = tree_view->priv->drag_pos;
2045   tree_view->priv->drag_pos = -1;
2046
2047       /* unblock attached dnd signal handler */
2048   drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
2049   if (drag_data)
2050     gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
2051
2052   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2053   gtk_widget_get_pointer (widget, &x, NULL);
2054   gtk_grab_remove (widget);
2055   gdk_pointer_ungrab (event->time);
2056
2057   return TRUE;
2058 }
2059
2060 static gboolean
2061 gtk_tree_view_button_release (GtkWidget      *widget,
2062                               GdkEventButton *event)
2063 {
2064   GtkTreeView *tree_view;
2065
2066   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2067   g_return_val_if_fail (event != NULL, FALSE);
2068
2069   tree_view = GTK_TREE_VIEW (widget);
2070
2071   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2072     return gtk_tree_view_button_release_drag_column (widget, event);
2073
2074   if (tree_view->priv->pressed_button == event->button)
2075     tree_view->priv->pressed_button = -1;
2076
2077   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
2078     return gtk_tree_view_button_release_column_resize (widget, event);
2079
2080   if (tree_view->priv->button_pressed_node == NULL)
2081     return FALSE;
2082
2083   if (event->button == 1)
2084     {
2085       gtk_grab_remove (widget);
2086       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
2087           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
2088         {
2089           GtkTreePath *path = NULL;
2090
2091           path = _gtk_tree_view_find_path (tree_view,
2092                                            tree_view->priv->button_pressed_tree,
2093                                            tree_view->priv->button_pressed_node);
2094           /* Actually activate the node */
2095           if (tree_view->priv->button_pressed_node->children == NULL)
2096             gtk_tree_view_real_expand_row (tree_view, path,
2097                                            tree_view->priv->button_pressed_tree,
2098                                            tree_view->priv->button_pressed_node,
2099                                            FALSE, TRUE);
2100           else
2101             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
2102                                              tree_view->priv->button_pressed_tree,
2103                                              tree_view->priv->button_pressed_node, TRUE);
2104           gtk_tree_path_free (path);
2105         }
2106
2107       tree_view->priv->button_pressed_tree = NULL;
2108       tree_view->priv->button_pressed_node = NULL;
2109     }
2110
2111   return TRUE;
2112 }
2113
2114
2115 /* GtkWidget::motion_event function set.
2116  */
2117
2118 static gboolean
2119 coords_are_over_arrow (GtkTreeView *tree_view,
2120                        GtkRBTree   *tree,
2121                        GtkRBNode   *node,
2122                        /* these are in window coords */
2123                        gint         x,
2124                        gint         y)
2125 {
2126   GdkRectangle arrow;
2127   gint x2;
2128
2129   if (!GTK_WIDGET_REALIZED (tree_view))
2130     return FALSE;
2131
2132   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
2133     return FALSE;
2134
2135   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
2136
2137   arrow.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
2138
2139   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
2140
2141   arrow.width = x2 - arrow.x;
2142
2143   return (x >= arrow.x &&
2144           x < (arrow.x + arrow.width) &&
2145           y >= arrow.y &&
2146           y < (arrow.y + arrow.height));
2147 }
2148
2149 static void
2150 do_unprelight (GtkTreeView *tree_view,
2151                /* these are in tree window coords */
2152                gint x,
2153                gint y)
2154 {
2155   if (tree_view->priv->prelight_node == NULL)
2156     return;
2157
2158   GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
2159
2160   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2161       !coords_are_over_arrow (tree_view,
2162                               tree_view->priv->prelight_tree,
2163                               tree_view->priv->prelight_node,
2164                               x,
2165                               y))
2166     /* We need to unprelight the old arrow. */
2167     {
2168       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
2169
2170       gtk_tree_view_draw_arrow (tree_view,
2171                                 tree_view->priv->prelight_tree,
2172                                 tree_view->priv->prelight_node,
2173                                 x,
2174                                 y);
2175
2176     }
2177
2178   tree_view->priv->prelight_node = NULL;
2179   tree_view->priv->prelight_tree = NULL;
2180 }
2181
2182 static void
2183 do_prelight (GtkTreeView *tree_view,
2184              GtkRBTree   *tree,
2185              GtkRBNode   *node,
2186              /* these are in tree_window coords */
2187              gint         x,
2188              gint         y)
2189 {
2190   if (coords_are_over_arrow (tree_view, tree, node, x, y))
2191     {
2192       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
2193     }
2194
2195   tree_view->priv->prelight_node = node;
2196   tree_view->priv->prelight_tree = tree;
2197
2198   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
2199 }
2200
2201 static void
2202 ensure_unprelighted (GtkTreeView *tree_view)
2203 {
2204   do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
2205   g_assert (tree_view->priv->prelight_node == NULL);
2206 }
2207
2208
2209
2210
2211 /* Our motion arrow is either a box (in the case of the original spot)
2212  * or an arrow.  It is expander_size wide.
2213  */
2214 /*
2215  * 11111111111111
2216  * 01111111111110
2217  * 00111111111100
2218  * 00011111111000
2219  * 00001111110000
2220  * 00000111100000
2221  * 00000111100000
2222  * 00000111100000
2223  * ~ ~ ~ ~ ~ ~ ~
2224  * 00000111100000
2225  * 00000111100000
2226  * 00000111100000
2227  * 00001111110000
2228  * 00011111111000
2229  * 00111111111100
2230  * 01111111111110
2231  * 11111111111111
2232  */
2233
2234 static void
2235 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
2236 {
2237   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
2238   GtkWidget *widget = GTK_WIDGET (tree_view);
2239   GdkBitmap *mask = NULL;
2240   gint x;
2241   gint y;
2242   gint width;
2243   gint height;
2244   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
2245   GdkWindowAttr attributes;
2246   guint attributes_mask;
2247
2248   if (!reorder ||
2249       reorder->left_column == tree_view->priv->drag_column ||
2250       reorder->right_column == tree_view->priv->drag_column)
2251     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
2252   else if (reorder->left_column || reorder->right_column)
2253     {
2254       GdkRectangle visible_rect;
2255       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
2256       if (reorder->left_column)
2257         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
2258       else
2259         x = reorder->right_column->button->allocation.x;
2260
2261       if (x < visible_rect.x)
2262         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
2263       else if (x > visible_rect.x + visible_rect.width)
2264         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
2265       else
2266         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
2267     }
2268
2269   /* We want to draw the rectangle over the initial location. */
2270   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
2271     {
2272       GdkGC *gc;
2273       GdkColor col;
2274
2275       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
2276         {
2277
2278           if (tree_view->priv->drag_highlight_window)
2279             gdk_window_destroy (tree_view->priv->drag_highlight_window);
2280
2281           attributes.window_type = GDK_WINDOW_CHILD;
2282           attributes.wclass = GDK_INPUT_OUTPUT;
2283           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
2284           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
2285           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2286           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2287           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
2288           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
2289
2290           width = tree_view->priv->drag_column->button->allocation.width;
2291           height = tree_view->priv->drag_column->button->allocation.height;
2292           gdk_window_move_resize (tree_view->priv->drag_highlight_window,
2293                                   tree_view->priv->drag_column_x, 0, width, height);
2294
2295           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
2296           gc = gdk_gc_new (mask);
2297           col.pixel = 1;
2298           gdk_gc_set_foreground (gc, &col);
2299           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2300           col.pixel = 0;
2301           gdk_gc_set_foreground(gc, &col);
2302           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
2303           gdk_gc_destroy (gc);
2304
2305           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2306                                          mask, 0, 0);
2307           if (mask) gdk_pixmap_unref (mask);
2308           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
2309         }
2310     }
2311   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
2312     {
2313       gint i, j = 1;
2314       GdkGC *gc;
2315       GdkColor col;
2316
2317       width = tree_view->priv->expander_size;
2318
2319       /* Get x, y, width, height of arrow */
2320       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
2321       if (reorder->left_column)
2322         {
2323           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
2324           height = reorder->left_column->button->allocation.height;
2325         }
2326       else
2327         {
2328           x += reorder->right_column->button->allocation.x - width/2;
2329           height = reorder->right_column->button->allocation.height;
2330         }
2331       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
2332       height += tree_view->priv->expander_size;
2333
2334       /* Create the new window */
2335       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
2336         {
2337           if (tree_view->priv->drag_highlight_window)
2338             gdk_window_destroy (tree_view->priv->drag_highlight_window);
2339
2340           attributes.window_type = GDK_WINDOW_TEMP;
2341           attributes.wclass = GDK_INPUT_OUTPUT;
2342           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
2343           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
2344           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2345           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2346           attributes.width = width;
2347           attributes.height = height;
2348           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
2349           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
2350
2351           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
2352           gc = gdk_gc_new (mask);
2353           col.pixel = 1;
2354           gdk_gc_set_foreground (gc, &col);
2355           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2356
2357           /* Draw the 2 arrows as per above */
2358           col.pixel = 0;
2359           gdk_gc_set_foreground (gc, &col);
2360           for (i = 0; i < width; i ++)
2361             {
2362               if (i == (width/2 - 1))
2363                 continue;
2364               gdk_draw_line (mask, gc, i, j, i, height - j);
2365               if (i < (width/2 - 1))
2366                 j++;
2367               else
2368                 j--;
2369             }
2370           gdk_gc_destroy (gc);
2371           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2372                                          mask, 0, 0);
2373           if (mask) gdk_pixmap_unref (mask);
2374         }
2375
2376       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
2377       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2378     }
2379   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
2380            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2381     {
2382       gint i, j = 1;
2383       GdkGC *gc;
2384       GdkColor col;
2385
2386       width = tree_view->priv->expander_size;
2387
2388       /* Get x, y, width, height of arrow */
2389       width = width/2; /* remember, the arrow only takes half the available width */
2390       gdk_window_get_origin (widget->window, &x, &y);
2391       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2392         x += widget->allocation.width - width;
2393
2394       if (reorder->left_column)
2395         height = reorder->left_column->button->allocation.height;
2396       else
2397         height = reorder->right_column->button->allocation.height;
2398
2399       y -= tree_view->priv->expander_size;
2400       height += 2*tree_view->priv->expander_size;
2401
2402       /* Create the new window */
2403       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
2404           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
2405         {
2406           if (tree_view->priv->drag_highlight_window)
2407             gdk_window_destroy (tree_view->priv->drag_highlight_window);
2408
2409           attributes.window_type = GDK_WINDOW_TEMP;
2410           attributes.wclass = GDK_INPUT_OUTPUT;
2411           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
2412           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
2413           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2414           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2415           attributes.width = width;
2416           attributes.height = height;
2417           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
2418           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
2419
2420           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
2421           gc = gdk_gc_new (mask);
2422           col.pixel = 1;
2423           gdk_gc_set_foreground (gc, &col);
2424           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
2425
2426           /* Draw the 2 arrows as per above */
2427           col.pixel = 0;
2428           gdk_gc_set_foreground (gc, &col);
2429           j = tree_view->priv->expander_size;
2430           for (i = 0; i < width; i ++)
2431             {
2432               gint k;
2433               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
2434                 k = width - i - 1;
2435               else
2436                 k = i;
2437               gdk_draw_line (mask, gc, k, j, k, height - j);
2438               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
2439               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
2440               j--;
2441             }
2442           gdk_gc_destroy (gc);
2443           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
2444                                          mask, 0, 0);
2445           if (mask) gdk_pixmap_unref (mask);
2446         }
2447
2448       tree_view->priv->drag_column_window_state = arrow_type;
2449       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
2450    }
2451   else
2452     {
2453       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
2454       gdk_window_hide (tree_view->priv->drag_highlight_window);
2455       return;
2456     }
2457
2458   gdk_window_show (tree_view->priv->drag_highlight_window);
2459   gdk_window_raise (tree_view->priv->drag_highlight_window);
2460 }
2461
2462 static gboolean
2463 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
2464                                     GdkEventMotion *event)
2465 {
2466   gint x;
2467   gint new_width;
2468   GtkTreeViewColumn *column;
2469   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2470
2471   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
2472
2473   if (event->is_hint || event->window != widget->window)
2474     gtk_widget_get_pointer (widget, &x, NULL);
2475   else
2476     x = event->x;
2477
2478   if (tree_view->priv->hadjustment)
2479     x += tree_view->priv->hadjustment->value;
2480
2481   new_width = gtk_tree_view_new_column_width (tree_view,
2482                                               tree_view->priv->drag_pos, &x);
2483   if (x != tree_view->priv->x_drag &&
2484       (new_width != column->fixed_width));
2485     {
2486       column->resized_width = new_width;
2487       gtk_widget_queue_resize (widget);
2488     }
2489
2490   return FALSE;
2491 }
2492
2493
2494 static void
2495 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
2496 {
2497   GtkTreeViewColumnReorder *reorder = NULL;
2498   GList *list;
2499   gint mouse_x;
2500
2501   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
2502
2503   for (list = tree_view->priv->column_drag_info; list; list = list->next)
2504     {
2505       reorder = (GtkTreeViewColumnReorder *) list->data;
2506       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
2507         break;
2508       reorder = NULL;
2509     }
2510
2511   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
2512       return;*/
2513
2514   tree_view->priv->cur_reorder = reorder;
2515   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
2516 }
2517
2518 static void
2519 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
2520 {
2521   GdkRectangle visible_rect;
2522   gint y;
2523   gint offset;
2524   gfloat value;
2525
2526   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
2527   y += tree_view->priv->dy;
2528
2529   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
2530
2531   /* see if we are near the edge. */
2532   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
2533   if (offset > 0)
2534     {
2535       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
2536       if (offset < 0)
2537         return;
2538     }
2539
2540   value = CLAMP (tree_view->priv->vadjustment->value + offset, 0.0,
2541                  tree_view->priv->vadjustment->upper - tree_view->priv->vadjustment->page_size);
2542   gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
2543 }
2544
2545 static gboolean
2546 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
2547 {
2548   GdkRectangle visible_rect;
2549   gint x;
2550   gint offset;
2551   gfloat value;
2552
2553   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
2554
2555   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
2556
2557   /* See if we are near the edge. */
2558   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
2559   if (offset > 0)
2560     {
2561       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
2562       if (offset < 0)
2563         return TRUE;
2564     }
2565   offset = offset/3;
2566
2567   value = CLAMP (tree_view->priv->hadjustment->value + offset,
2568                  0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
2569   gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
2570
2571   return TRUE;
2572
2573 }
2574
2575 static gboolean
2576 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
2577                                   GdkEventMotion *event)
2578 {
2579   GtkTreeView *tree_view = (GtkTreeView *) widget;
2580   GtkTreeViewColumn *column = tree_view->priv->drag_column;
2581   gint x, y;
2582
2583   /* Sanity Check */
2584   if ((column == NULL) ||
2585       (event->window != tree_view->priv->drag_window))
2586     return FALSE;
2587
2588   /* Handle moving the header */
2589   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
2590   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
2591              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
2592   gdk_window_move (tree_view->priv->drag_window, x, y);
2593
2594   /* autoscroll, if needed */
2595   gtk_tree_view_horizontal_autoscroll (tree_view);
2596   /* Update the current reorder position and arrow; */
2597   gtk_tree_view_update_current_reorder (tree_view);
2598
2599   return TRUE;
2600 }
2601
2602 static gboolean
2603 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
2604                                  GdkEventMotion *event)
2605 {
2606   GtkTreeView *tree_view;
2607   GtkRBTree *tree;
2608   GtkRBNode *node;
2609   gint new_y;
2610   GtkRBTree *old_prelight_tree;
2611   GtkRBNode *old_prelight_node;
2612   gboolean old_arrow_prelit;
2613
2614   tree_view = (GtkTreeView *) widget;
2615
2616   if (tree_view->priv->tree == NULL)
2617     return FALSE;
2618
2619   gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
2620
2621   old_prelight_tree = tree_view->priv->prelight_tree;
2622   old_prelight_node = tree_view->priv->prelight_node;
2623   old_arrow_prelit = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
2624
2625   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2626   if (new_y < 0)
2627     new_y = 0;
2628   do_unprelight (tree_view, event->x, event->y);
2629   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2630
2631   if (tree == NULL)
2632     return TRUE;
2633
2634   /* If we are currently pressing down a button, we don't want to prelight anything else. */
2635   if ((tree_view->priv->button_pressed_node != NULL) &&
2636       (tree_view->priv->button_pressed_node != node))
2637     return TRUE;
2638
2639
2640   do_prelight (tree_view, tree, node, event->x, event->y);
2641
2642   if (old_prelight_node != tree_view->priv->prelight_node)
2643     {
2644       if (old_prelight_node)
2645         {
2646           _gtk_tree_view_queue_draw_node (tree_view,
2647                                           old_prelight_tree,
2648                                           old_prelight_node,
2649                                           NULL);
2650         }
2651       if (tree_view->priv->prelight_node)
2652         {
2653           _gtk_tree_view_queue_draw_node (tree_view,
2654                                           tree_view->priv->prelight_tree,
2655                                           tree_view->priv->prelight_node,
2656                                           NULL);
2657         }
2658     }
2659   else if (old_arrow_prelit != GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
2660     {
2661       if (tree_view->priv->prelight_node)
2662         {
2663           _gtk_tree_view_queue_draw_node (tree_view,
2664                                          tree_view->priv->prelight_tree,
2665                                          tree_view->priv->prelight_node,
2666                                          NULL);
2667         }
2668     }
2669   return TRUE;
2670 }
2671
2672 static gboolean
2673 gtk_tree_view_motion (GtkWidget      *widget,
2674                       GdkEventMotion *event)
2675 {
2676   GtkTreeView *tree_view;
2677
2678   tree_view = (GtkTreeView *) widget;
2679
2680   /* Resizing a column */
2681   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
2682     return gtk_tree_view_motion_resize_column (widget, event);
2683
2684   /* Drag column */
2685   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2686     return gtk_tree_view_motion_drag_column (widget, event);
2687
2688   /* Sanity check it */
2689   if (event->window == tree_view->priv->bin_window)
2690     return gtk_tree_view_motion_bin_window (widget, event);
2691
2692   return FALSE;
2693 }
2694
2695 /* Warning: Very scary function.
2696  * Modify at your own risk
2697  *
2698  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
2699  * FIXME: It's not...
2700  */
2701 static gboolean
2702 gtk_tree_view_bin_expose (GtkWidget      *widget,
2703                           GdkEventExpose *event)
2704 {
2705   GtkTreeView *tree_view;
2706   GtkTreePath *path;
2707   GtkRBTree *tree;
2708   GList *list;
2709   GtkRBNode *node;
2710   GtkRBNode *cursor = NULL;
2711   GtkRBTree *cursor_tree = NULL;
2712   GtkRBNode *drag_highlight = NULL;
2713   GtkRBTree *drag_highlight_tree = NULL;
2714   GtkTreeIter iter;
2715   gint new_y;
2716   gint y_offset, x_offset, cell_offset;
2717   gint max_height;
2718   gint depth;
2719   GdkRectangle background_area;
2720   GdkRectangle cell_area;
2721   guint flags;
2722   gint highlight_x;
2723   gint bin_window_width;
2724   GtkTreePath *cursor_path;
2725   GtkTreePath *drag_dest_path;
2726   GList *last_column;
2727   gint vertical_separator;
2728   gint horizontal_separator;
2729   gboolean allow_rules;
2730
2731   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2732
2733   tree_view = GTK_TREE_VIEW (widget);
2734
2735   gtk_widget_style_get (widget,
2736                         "horizontal_separator", &horizontal_separator,
2737                         "vertical_separator", &vertical_separator,
2738                         "allow_rules", &allow_rules,
2739                         NULL);
2740
2741   if (tree_view->priv->tree == NULL)
2742     return TRUE;
2743
2744   /* clip event->area to the visible area */
2745   if (event->area.height < 0)
2746     return TRUE;
2747
2748   validate_visible_area (tree_view);
2749
2750   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
2751
2752   if (new_y < 0)
2753     new_y = 0;
2754   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2755
2756   if (node == NULL)
2757     return TRUE;
2758
2759   /* find the path for the node */
2760   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
2761                                    tree,
2762                                    node);
2763   gtk_tree_model_get_iter (tree_view->priv->model,
2764                            &iter,
2765                            path);
2766   depth = gtk_tree_path_get_depth (path);
2767   gtk_tree_path_free (path);
2768
2769   cursor_path = NULL;
2770   drag_dest_path = NULL;
2771
2772   if (tree_view->priv->cursor)
2773     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
2774
2775   if (cursor_path)
2776     _gtk_tree_view_find_node (tree_view, cursor_path,
2777                               &cursor_tree, &cursor);
2778
2779   if (tree_view->priv->drag_dest_row)
2780     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
2781
2782   if (drag_dest_path)
2783     _gtk_tree_view_find_node (tree_view, drag_dest_path,
2784                               &drag_highlight_tree, &drag_highlight);
2785
2786   gdk_drawable_get_size (tree_view->priv->bin_window,
2787                          &bin_window_width, NULL);
2788
2789   for (last_column = g_list_last (tree_view->priv->columns);
2790        last_column &&
2791          !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
2792          GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
2793        last_column = last_column->prev)
2794     ;
2795
2796   /* Actually process the expose event.  To do this, we want to
2797    * start at the first node of the event, and walk the tree in
2798    * order, drawing each successive node.
2799    */
2800
2801   do
2802     {
2803       gboolean parity;
2804
2805       max_height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
2806
2807       x_offset = -event->area.x;
2808       cell_offset = 0;
2809       highlight_x = 0; /* should match x coord of first cell */
2810
2811       background_area.y = y_offset + event->area.y;
2812       background_area.height = max_height;
2813
2814       flags = 0;
2815
2816       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
2817         flags |= GTK_CELL_RENDERER_PRELIT;
2818
2819       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
2820         flags |= GTK_CELL_RENDERER_SELECTED;
2821
2822       parity = _gtk_rbtree_node_find_parity (tree, node);
2823
2824       for (list = tree_view->priv->columns; list; list = list->next)
2825         {
2826           GtkTreeViewColumn *column = list->data;
2827           const gchar *detail = NULL;
2828           GtkStateType state;
2829
2830           if (!column->visible)
2831             continue;
2832
2833           if (cell_offset > event->area.x + event->area.width ||
2834               cell_offset + column->width < event->area.x)
2835             {
2836               cell_offset += column->width;
2837               continue;
2838             }
2839
2840           if (column->show_sort_indicator)
2841             flags |= GTK_CELL_RENDERER_SORTED;
2842           else
2843             flags &= ~GTK_CELL_RENDERER_SORTED;
2844
2845           gtk_tree_view_column_cell_set_cell_data (column,
2846                                                    tree_view->priv->model,
2847                                                    &iter,
2848                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2849                                                    node->children?TRUE:FALSE);
2850
2851
2852           background_area.x = cell_offset;
2853           background_area.width = column->width;
2854
2855           cell_area = background_area;
2856           cell_area.y += vertical_separator / 2;
2857           cell_area.x += horizontal_separator / 2;
2858           cell_area.height -= vertical_separator;
2859           cell_area.width -= horizontal_separator;
2860
2861           /* Select the detail for drawing the cell.  relevant
2862            * factors are parity, sortedness, and whether to
2863            * display rules.
2864            */
2865           if (allow_rules && tree_view->priv->has_rules)
2866             {
2867               if (flags & GTK_CELL_RENDERER_SORTED)
2868                 {
2869                   if (parity)
2870                     detail = "cell_odd_ruled_sorted";
2871                   else
2872                     detail = "cell_even_ruled_sorted";
2873                 }
2874               else
2875                 {
2876                   if (parity)
2877                     detail = "cell_odd_ruled";
2878                   else
2879                     detail = "cell_even_ruled";
2880                 }
2881             }
2882           else
2883             {
2884               if (flags & GTK_CELL_RENDERER_SORTED)
2885                 {
2886                   if (parity)
2887                     detail = "cell_odd_sorted";
2888                   else
2889                     detail = "cell_even_sorted";
2890                 }
2891               else
2892                 {
2893                   if (parity)
2894                     detail = "cell_odd";
2895                   else
2896                     detail = "cell_even";
2897                 }
2898             }
2899
2900           g_assert (detail);
2901
2902           if (flags & GTK_CELL_RENDERER_SELECTED)
2903             state = GTK_STATE_SELECTED;
2904           else
2905             state = GTK_STATE_NORMAL;
2906
2907           /* Draw background */
2908           gtk_paint_flat_box (widget->style,
2909                               event->window,
2910                               state,
2911                               GTK_SHADOW_NONE,
2912                               &event->area,
2913                               widget,
2914                               detail,
2915                               background_area.x,
2916                               background_area.y,
2917                               background_area.width,
2918                               background_area.height);
2919
2920           if (gtk_tree_view_is_expander_column (tree_view, column) &&
2921               TREE_VIEW_DRAW_EXPANDERS(tree_view))
2922             {
2923               cell_area.x += depth * tree_view->priv->expander_size;
2924               cell_area.width -= depth * tree_view->priv->expander_size;
2925
2926               /* If we have an expander column, the highlight underline
2927                * starts with that column, so that it indicates which
2928                * level of the tree we're dropping at.
2929                */
2930               highlight_x = cell_area.x;
2931               _gtk_tree_view_column_cell_render (column,
2932                                                  event->window,
2933                                                  &background_area,
2934                                                  &cell_area,
2935                                                  &event->area,
2936                                                  flags);
2937               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
2938                 {
2939                   gint x, y;
2940                   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
2941                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2942                                             tree,
2943                                             node,
2944                                             x, y);
2945                 }
2946             }
2947           else
2948             {
2949               _gtk_tree_view_column_cell_render (column,
2950                                                  event->window,
2951                                                  &background_area,
2952                                                  &cell_area,
2953                                                  &event->area,
2954                                                  flags);
2955             }
2956           if (node == cursor &&
2957               ((column == tree_view->priv->focus_column &&
2958                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
2959                 GTK_WIDGET_HAS_FOCUS (widget)) ||
2960                (column == tree_view->priv->edited_column)))
2961             {
2962               _gtk_tree_view_column_cell_draw_focus (column,
2963                                                      event->window,
2964                                                      &background_area,
2965                                                      &cell_area,
2966                                                      &event->area,
2967                                                      flags);
2968             }
2969           cell_offset += column->width;
2970         }
2971
2972
2973       if (node == drag_highlight)
2974         {
2975           /* Draw indicator for the drop
2976            */
2977           gint highlight_y = -1;
2978           GtkRBTree *tree = NULL;
2979           GtkRBNode *node = NULL;
2980           gint width;
2981           gint focus_line_width;
2982
2983           switch (tree_view->priv->drag_dest_pos)
2984             {
2985             case GTK_TREE_VIEW_DROP_BEFORE:
2986               highlight_y = background_area.y - 1;
2987               if (highlight_y < 0)
2988                       highlight_y = 0;
2989               break;
2990
2991             case GTK_TREE_VIEW_DROP_AFTER:
2992               highlight_y = background_area.y + background_area.height - 1;
2993               break;
2994
2995             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
2996             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
2997               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
2998
2999               if (tree == NULL)
3000                 break;
3001               gdk_drawable_get_size (tree_view->priv->bin_window,
3002                                      &width, NULL);
3003               gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
3004               gtk_paint_focus (widget->style,
3005                                tree_view->priv->bin_window,
3006                                GTK_WIDGET_STATE (widget),
3007                                NULL,
3008                                widget,
3009                                "treeview-drop-indicator",
3010                                0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
3011                                - focus_line_width / 2,
3012                                width, MAX(BACKGROUND_HEIGHT (node),
3013                                           tree_view->priv->expander_size)
3014                                - focus_line_width + 1);
3015               break;
3016             }
3017
3018           if (highlight_y >= 0)
3019             {
3020               gdk_draw_line (event->window,
3021                              widget->style->black_gc,
3022                              highlight_x,
3023                              highlight_y,
3024                              bin_window_width - highlight_x,
3025                              highlight_y);
3026             }
3027         }
3028
3029       y_offset += max_height;
3030       if (node->children)
3031         {
3032           GtkTreeIter parent = iter;
3033           gboolean has_child;
3034
3035           tree = node->children;
3036           node = tree->root;
3037
3038           g_assert (node != tree->nil);
3039
3040           while (node->left != tree->nil)
3041             node = node->left;
3042           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
3043                                                     &iter,
3044                                                     &parent);
3045           depth++;
3046
3047           /* Sanity Check! */
3048           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
3049         }
3050       else
3051         {
3052           gboolean done = FALSE;
3053           do
3054             {
3055               node = _gtk_rbtree_next (tree, node);
3056               if (node != NULL)
3057                 {
3058                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
3059                   done = TRUE;
3060
3061                   /* Sanity Check! */
3062                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
3063                 }
3064               else
3065                 {
3066                   GtkTreeIter parent_iter = iter;
3067                   gboolean has_parent;
3068
3069                   node = tree->parent_node;
3070                   tree = tree->parent_tree;
3071                   if (tree == NULL)
3072                     /* we should go to done to free some memory */
3073                     goto done;
3074                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
3075                                                            &iter,
3076                                                            &parent_iter);
3077                   depth--;
3078
3079                   /* Sanity check */
3080                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
3081                 }
3082             }
3083           while (!done);
3084         }
3085     }
3086   while (y_offset < event->area.height);
3087
3088  done:
3089   if (cursor_path)
3090     gtk_tree_path_free (cursor_path);
3091
3092   if (drag_dest_path)
3093     gtk_tree_path_free (drag_dest_path);
3094
3095   return FALSE;
3096 }
3097
3098 static gboolean
3099 gtk_tree_view_expose (GtkWidget      *widget,
3100                       GdkEventExpose *event)
3101 {
3102   GtkTreeView *tree_view;
3103
3104   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3105
3106   tree_view = GTK_TREE_VIEW (widget);
3107
3108   if (event->window == tree_view->priv->bin_window)
3109     return gtk_tree_view_bin_expose (widget, event);
3110   else if (event->window == tree_view->priv->header_window)
3111     {
3112       GList *list;
3113       
3114       for (list = tree_view->priv->columns; list != NULL; list = list->next)
3115         {
3116           GtkTreeViewColumn *column = list->data;
3117
3118           if (column == tree_view->priv->drag_column)
3119             continue;
3120
3121           if (column->visible)
3122             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
3123                                             column->button,
3124                                             event);
3125         }
3126     }
3127   else if (event->window == tree_view->priv->drag_window)
3128     {
3129       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
3130                                       tree_view->priv->drag_column->button,
3131                                       event);
3132     }
3133   return TRUE;
3134 }
3135
3136 enum
3137 {
3138   DROP_HOME,
3139   DROP_RIGHT,
3140   DROP_LEFT,
3141   DROP_END
3142 };
3143
3144 /* returns 0x1 when no column has been found -- yes it's hackish */
3145 static GtkTreeViewColumn *
3146 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
3147                                GtkTreeViewColumn *column,
3148                                gint               drop_position)
3149 {
3150   GtkTreeViewColumn *left_column = NULL;
3151   GtkTreeViewColumn *cur_column = NULL;
3152   GList *tmp_list;
3153
3154   if (!column->reorderable)
3155     return (GtkTreeViewColumn *)0x1;
3156
3157   switch (drop_position)
3158     {
3159       case DROP_HOME:
3160         /* find first column where we can drop */
3161         tmp_list = tree_view->priv->columns;
3162         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
3163           return (GtkTreeViewColumn *)0x1;
3164
3165         while (tmp_list)
3166           {
3167             g_assert (tmp_list);
3168
3169             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3170             tmp_list = tmp_list->next;
3171
3172             if (left_column && left_column->visible == FALSE)
3173               continue;
3174
3175             if (!tree_view->priv->column_drop_func)
3176               return left_column;
3177
3178             if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
3179               {
3180                 left_column = cur_column;
3181                 continue;
3182               }
3183
3184             return cur_column;
3185           }
3186
3187         if (!tree_view->priv->column_drop_func)
3188           return left_column;
3189
3190         if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
3191           return left_column;
3192         else
3193           return (GtkTreeViewColumn *)0x1;
3194         break;
3195
3196       case DROP_RIGHT:
3197         /* find first column after column where we can drop */
3198         tmp_list = tree_view->priv->columns;
3199
3200         for (; tmp_list; tmp_list = tmp_list->next)
3201           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
3202             break;
3203
3204         if (!tmp_list || !tmp_list->next)
3205           return (GtkTreeViewColumn *)0x1;
3206
3207         tmp_list = tmp_list->next;
3208         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3209         tmp_list = tmp_list->next;
3210
3211         while (tmp_list)
3212           {
3213             g_assert (tmp_list);
3214
3215             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3216             tmp_list = tmp_list->next;
3217
3218             if (left_column && left_column->visible == FALSE)
3219               {
3220                 left_column = cur_column;
3221                 if (tmp_list)
3222                   tmp_list = tmp_list->next;
3223                 continue;
3224               }
3225
3226             if (!tree_view->priv->column_drop_func)
3227               return left_column;
3228
3229             if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
3230               {
3231                 left_column = cur_column;
3232                 continue;
3233               }
3234
3235             return cur_column;
3236           }
3237
3238         if (!tree_view->priv->column_drop_func)
3239           return left_column;
3240
3241         if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
3242           return left_column;
3243         else
3244           return (GtkTreeViewColumn *)0x1;
3245         break;
3246
3247       case DROP_LEFT:
3248         /* find first column before column where we can drop */
3249         tmp_list = tree_view->priv->columns;
3250
3251         for (; tmp_list; tmp_list = tmp_list->next)
3252           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
3253             break;
3254
3255         if (!tmp_list || !tmp_list->prev)
3256           return (GtkTreeViewColumn *)0x1;
3257
3258         tmp_list = tmp_list->prev;
3259         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3260         tmp_list = tmp_list->prev;
3261
3262         while (tmp_list)
3263           {
3264             g_assert (tmp_list);
3265
3266             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3267
3268             if (left_column && !left_column->visible)
3269               {
3270                 /*if (!tmp_list->prev)
3271                   return (GtkTreeViewColumn *)0x1;
3272                   */
3273 /*
3274                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
3275                 tmp_list = tmp_list->prev->prev;
3276                 continue;*/
3277
3278                 cur_column = left_column;
3279                 if (tmp_list)
3280                   tmp_list = tmp_list->prev;
3281                 continue;
3282               }
3283
3284             if (!tree_view->priv->column_drop_func)
3285               return left_column;
3286
3287             if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
3288               return left_column;
3289
3290             cur_column = left_column;
3291             tmp_list = tmp_list->prev;
3292           }
3293
3294         if (!tree_view->priv->column_drop_func)
3295           return NULL;
3296
3297         if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
3298           return NULL;
3299         else
3300           return (GtkTreeViewColumn *)0x1;
3301         break;
3302
3303       case DROP_END:
3304         /* same as DROP_HOME case, but doing it backwards */
3305         tmp_list = g_list_last (tree_view->priv->columns);
3306         cur_column = NULL;
3307
3308         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
3309           return (GtkTreeViewColumn *)0x1;
3310
3311         while (tmp_list)
3312           {
3313             g_assert (tmp_list);
3314
3315             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
3316
3317             if (left_column && !left_column->visible)
3318               {
3319                 cur_column = left_column;
3320                 tmp_list = tmp_list->prev;
3321               }
3322
3323             if (!tree_view->priv->column_drop_func)
3324               return left_column;
3325
3326             if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
3327               return left_column;
3328
3329             cur_column = left_column;
3330             tmp_list = tmp_list->prev;
3331           }
3332
3333         if (!tree_view->priv->column_drop_func)
3334           return NULL;
3335
3336         if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
3337           return NULL;
3338         else
3339           return (GtkTreeViewColumn *)0x1;
3340         break;
3341     }
3342
3343   return (GtkTreeViewColumn *)0x1;
3344 }
3345
3346 static gboolean
3347 gtk_tree_view_key_press (GtkWidget   *widget,
3348                          GdkEventKey *event)
3349 {
3350   GtkTreeView *tree_view = (GtkTreeView *) widget;
3351   GList *list;
3352
3353   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3354     {
3355       if (event->keyval == GDK_Escape)
3356         {
3357           tree_view->priv->cur_reorder = NULL;
3358           gtk_tree_view_button_release_drag_column (widget, NULL);
3359         }
3360       return TRUE;
3361     }
3362
3363   /* FIXME: this is prolly broken when we go bidi */
3364   if (tree_view->priv->columns && (event->state & GDK_SHIFT_MASK)
3365       && (event->keyval == GDK_Left || event->keyval == GDK_Right))
3366     {
3367       list = tree_view->priv->columns;
3368       while (list)
3369         {
3370           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
3371           if (GTK_WIDGET_HAS_FOCUS (column->button))
3372             {
3373               if (!column->resizable)
3374                 return TRUE;
3375
3376               if (event->keyval == GDK_Left)
3377                 {
3378                   column->resized_width = MAX (column->resized_width,
3379                                                column->width);
3380                   column->resized_width -= 2;
3381                   if (column->resized_width < 0)
3382                     column->resized_width = 0;
3383
3384                   if (column->min_width == -1)
3385                     column->resized_width = MAX (column->button->requisition.width, column->resized_width);
3386                   else
3387                     column->resized_width = MAX (column->min_width, column->resized_width);
3388
3389                   if (column->max_width != -1)
3390                     column->resized_width = MIN (column->resized_width, column->max_width);
3391
3392                   column->use_resized_width = TRUE;
3393                   gtk_widget_queue_resize (widget);
3394                   return TRUE;
3395                 }
3396               else if (event->keyval == GDK_Right)
3397                 {
3398                   column->resized_width = MAX (column->resized_width,
3399                                                column->width);
3400                   column->resized_width += 2;
3401
3402                   if (column->max_width != -1)
3403                     column->resized_width = MIN (column->resized_width, column->max_width);
3404
3405                   column->use_resized_width = TRUE;
3406                   gtk_widget_queue_resize (widget);
3407                   return TRUE;
3408                 }
3409             }
3410           list = list->next;
3411         }
3412     }
3413
3414   /* FIXME: broken when we go bidi? */
3415   if (tree_view->priv->columns && (event->state & GDK_CONTROL_MASK) &&
3416       (event->keyval == GDK_Left || event->keyval == GDK_Right
3417        || event->keyval == GDK_Home || event->keyval == GDK_End))
3418     {
3419       list = tree_view->priv->columns;
3420       while (list)
3421         {
3422           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
3423           if (GTK_WIDGET_HAS_FOCUS (column->button))
3424             {
3425               if (event->keyval == GDK_Left)
3426                 {
3427                   GtkTreeViewColumn *col;
3428                   col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
3429                   if (col != (GtkTreeViewColumn *)0x1)
3430                     gtk_tree_view_move_column_after (tree_view, column, col);
3431                   return TRUE;
3432                 }
3433               else if (event->keyval == GDK_Right)
3434                 {
3435                   GtkTreeViewColumn *col;
3436                   col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
3437                   if (col != (GtkTreeViewColumn *)0x1)
3438                     gtk_tree_view_move_column_after (tree_view, column, col);
3439                   return TRUE;
3440                 }
3441               else if (event->keyval == GDK_Home)
3442                 {
3443                   GtkTreeViewColumn *col;
3444                   col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
3445                   if (col != (GtkTreeViewColumn *)0x1)
3446                     gtk_tree_view_move_column_after (tree_view, column, col);
3447                   return TRUE;
3448                 }
3449               else if (event->keyval == GDK_End)
3450                 {
3451                   GtkTreeViewColumn *col;
3452                   col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
3453                   if (col != (GtkTreeViewColumn *)0x1)
3454                     gtk_tree_view_move_column_after (tree_view, column, col);
3455                   return TRUE;
3456                 }
3457             }
3458           list = list->next;
3459         }
3460     }
3461
3462   /* FIXME: this is prolly broken when we go bidi */
3463   if (tree_view->priv->columns &&
3464       (event->keyval == GDK_Left || event->keyval == GDK_Right))
3465     {
3466       gint width = 0;
3467       list = tree_view->priv->columns;
3468       while (list)
3469         {
3470           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
3471           if (GTK_WIDGET_HAS_FOCUS (column->button))
3472             {
3473               if (event->keyval == GDK_Left && list->prev)
3474                 {
3475                   GList *tmp;
3476
3477                   for (tmp = list->prev; tmp; tmp = tmp->prev)
3478                     if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
3479                       break;
3480
3481                   if (!tmp)
3482                     return FALSE;
3483
3484                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
3485                   gtk_widget_grab_focus (tree_view->priv->focus_column->button);
3486                   width -= tree_view->priv->focus_column->width;
3487                   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));
3488                   return TRUE;
3489                 }
3490               else if (event->keyval == GDK_Right && list->next)
3491                 {
3492                   GList *tmp;
3493
3494                   for (tmp = list->next; tmp; tmp = tmp->next)
3495                     if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
3496                       break;
3497
3498                   if (!tmp)
3499                     return FALSE;
3500
3501                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
3502
3503                   gtk_widget_grab_focus (tree_view->priv->focus_column->button);
3504                   width += tree_view->priv->focus_column->width;
3505                   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));
3506                   return TRUE;
3507                 }
3508             }
3509           width += GTK_TREE_VIEW_COLUMN (list->data)->width;
3510           list = list->next;
3511         }
3512     }
3513
3514   return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
3515 }
3516
3517 /* FIXME Is this function necessary? Can I get an enter_notify event
3518  * w/o either an expose event or a mouse motion event?
3519  */
3520 static gboolean
3521 gtk_tree_view_enter_notify (GtkWidget        *widget,
3522                             GdkEventCrossing *event)
3523 {
3524   GtkTreeView *tree_view;
3525   GtkRBTree *tree;
3526   GtkRBNode *node;
3527   gint new_y;
3528
3529   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3530
3531   tree_view = GTK_TREE_VIEW (widget);
3532
3533   /* Sanity check it */
3534   if (event->window != tree_view->priv->bin_window)
3535     return FALSE;
3536
3537   if (tree_view->priv->tree == NULL)
3538     return FALSE;
3539
3540   if ((tree_view->priv->button_pressed_node != NULL) &&
3541       (tree_view->priv->button_pressed_node != node))
3542     return TRUE;
3543
3544   /* find the node internally */
3545   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
3546   if (new_y < 0)
3547     new_y = 0;
3548   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
3549
3550   if (node == NULL)
3551     return FALSE;
3552
3553   do_prelight (tree_view, tree, node, event->x, event->y);
3554
3555   if (tree_view->priv->prelight_node)
3556     _gtk_tree_view_queue_draw_node (tree_view,
3557                                    tree_view->priv->prelight_tree,
3558                                    tree_view->priv->prelight_node,
3559                                    NULL);
3560
3561   return TRUE;
3562 }
3563
3564 static gboolean
3565 gtk_tree_view_leave_notify (GtkWidget        *widget,
3566                             GdkEventCrossing *event)
3567 {
3568   GtkTreeView *tree_view;
3569
3570   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3571
3572   if (event->mode == GDK_CROSSING_GRAB)
3573     return TRUE;
3574   tree_view = GTK_TREE_VIEW (widget);
3575
3576   if (tree_view->priv->prelight_node)
3577     _gtk_tree_view_queue_draw_node (tree_view,
3578                                    tree_view->priv->prelight_tree,
3579                                    tree_view->priv->prelight_node,
3580                                    NULL);
3581
3582   ensure_unprelighted (tree_view);
3583
3584 return TRUE;
3585 }
3586
3587
3588 static gint
3589 gtk_tree_view_focus_out (GtkWidget     *widget,
3590                          GdkEventFocus *event)
3591 {
3592   GtkWidget   *search_dialog;
3593
3594   gtk_widget_queue_draw (widget);
3595
3596   /* destroy interactive search dialog */
3597   search_dialog = gtk_object_get_data (GTK_OBJECT (widget),
3598                                        GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
3599   if (search_dialog)
3600     gtk_tree_view_search_dialog_destroy (search_dialog, GTK_TREE_VIEW (widget));
3601
3602   return FALSE;
3603 }
3604
3605
3606 /* Incremental Reflow
3607  */
3608
3609 /* Returns TRUE if it updated the size
3610  */
3611 static gboolean
3612 validate_row (GtkTreeView *tree_view,
3613               GtkRBTree   *tree,
3614               GtkRBNode   *node,
3615               GtkTreeIter *iter,
3616               GtkTreePath *path)
3617 {
3618   GtkTreeViewColumn *column;
3619   GList *list;
3620   gint height = 0;
3621   gint horizontal_separator;
3622   gint depth = gtk_tree_path_get_depth (path);
3623   gboolean retval = FALSE;
3624
3625   /* double check the row needs validating */
3626   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
3627       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3628     return FALSE;
3629
3630   gtk_widget_style_get (GTK_WIDGET (tree_view),
3631                         "horizontal_separator", &horizontal_separator,
3632                         NULL);
3633
3634   for (list = tree_view->priv->columns; list; list = list->next)
3635     {
3636       gint tmp_width;
3637       gint tmp_height;
3638
3639       column = list->data;
3640
3641       if (! column->visible)
3642         continue;
3643
3644       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
3645         continue;
3646
3647       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
3648                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3649                                                node->children?TRUE:FALSE);
3650       gtk_tree_view_column_cell_get_size (column,
3651                                           NULL, NULL, NULL,
3652                                           &tmp_width, &tmp_height);
3653       height = MAX (height, tmp_height);
3654       height = MAX (height, tree_view->priv->expander_size);
3655
3656       if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3657         {
3658           tmp_width = tmp_width + horizontal_separator + depth * (tree_view->priv->expander_size);
3659         }
3660       else
3661         tmp_width = tmp_width + horizontal_separator;
3662
3663       if (tmp_width > column->requested_width)
3664         {
3665           retval = TRUE;
3666           column->requested_width = tmp_width;
3667         }
3668     }
3669
3670   if (height != GTK_RBNODE_GET_HEIGHT (node))
3671     {
3672       retval = TRUE;
3673       _gtk_rbtree_node_set_height (tree, node, height);
3674     }
3675   _gtk_rbtree_node_mark_valid (tree, node);
3676
3677   return retval;
3678 }
3679
3680
3681 static void
3682 validate_visible_area (GtkTreeView *tree_view)
3683 {
3684   GtkTreePath *path = NULL;
3685   GtkTreePath *above_path = NULL;
3686   GtkTreeIter iter;
3687   GtkRBTree *tree = NULL;
3688   GtkRBNode *node = NULL;
3689   gboolean need_redraw = FALSE;
3690   gboolean size_changed = FALSE;
3691   gboolean modify_dy = FALSE;
3692   gint total_height;
3693   gint area_above = 0;
3694   gint area_below = 0;
3695
3696   if (tree_view->priv->tree == NULL)
3697     return;
3698
3699   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
3700       tree_view->priv->scroll_to_path == NULL)
3701       return;
3702
3703   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
3704
3705   /* First, we check to see if we need to scroll anywhere
3706    */
3707   if (tree_view->priv->scroll_to_path)
3708     {
3709       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
3710       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
3711         {
3712           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3713           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
3714               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3715             {
3716               need_redraw = TRUE;
3717               if (validate_row (tree_view, tree, node, &iter, path))
3718                 size_changed = TRUE;
3719             }
3720           if (tree_view->priv->scroll_to_use_align)
3721             {
3722               gint height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
3723               area_above = (total_height - height) *
3724                 tree_view->priv->scroll_to_row_align;
3725               area_below = total_height - area_above - height;
3726               area_above = MAX (area_above, 0);
3727               area_below = MAX (area_below, 0);
3728             }
3729           else
3730             {
3731               /* FIXME: */
3732               g_warning ("non use_align not implemented yet");
3733               gtk_tree_path_free (path);
3734               path = NULL;
3735             }
3736         }
3737       else
3738         /* the scroll to isn't valid; ignore it.
3739          */
3740         {
3741           if (tree_view->priv->scroll_to_path && !path)
3742             {
3743               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
3744               tree_view->priv->scroll_to_path = NULL;
3745             }
3746           if (path)
3747             gtk_tree_path_free (path);
3748           path = NULL;
3749         }      
3750     }
3751
3752   /* We didn't have a scroll_to set, so we just handle things normally
3753    */
3754   if (path == NULL)
3755     {
3756       gint offset;
3757
3758       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
3759                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
3760                                         &tree, &node);
3761       if (node == NULL)
3762         {
3763           /* In this case, nothing has been validated */
3764           path = gtk_tree_path_new_first ();
3765           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
3766         }
3767       else
3768         {
3769           path = _gtk_tree_view_find_path (tree_view, tree, node);
3770           total_height += offset;
3771         }
3772
3773       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3774
3775       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
3776           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3777         {
3778           need_redraw = TRUE;
3779           if (validate_row (tree_view, tree, node, &iter, path))
3780             size_changed = TRUE;
3781         }
3782       area_above = 0;
3783       area_below = total_height - MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
3784     }
3785
3786   above_path = gtk_tree_path_copy (path);
3787
3788   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
3789    * backwards is much slower then forward, as there is no iter_prev function.
3790    * We go forwards first in case we run out of tree.  Then we go backwards to
3791    * fill out the top.
3792    */
3793   while (node && area_below > 0)
3794     {
3795       if (node->children)
3796         {
3797           GtkTreeIter parent = iter;
3798           gboolean has_child;
3799
3800           tree = node->children;
3801           node = tree->root;
3802
3803           g_assert (node != tree->nil);
3804
3805           while (node->left != tree->nil)
3806             node = node->left;
3807           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
3808                                                     &iter,
3809                                                     &parent);
3810           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
3811           gtk_tree_path_down (path);
3812         }
3813       else
3814         {
3815           gboolean done = FALSE;
3816           do
3817             {
3818               node = _gtk_rbtree_next (tree, node);
3819               if (node != NULL)
3820                 {
3821                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
3822                   done = TRUE;
3823                   gtk_tree_path_next (path);
3824
3825                   /* Sanity Check! */
3826                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
3827                 }
3828               else
3829                 {
3830                   GtkTreeIter parent_iter = iter;
3831                   gboolean has_parent;
3832
3833                   node = tree->parent_node;
3834                   tree = tree->parent_tree;
3835                   if (tree == NULL)
3836                     break;
3837                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
3838                                                            &iter,
3839                                                            &parent_iter);
3840                   gtk_tree_path_up (path);
3841
3842                   /* Sanity check */
3843                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
3844                 }
3845             }
3846           while (!done);
3847         }
3848       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
3849           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3850         {
3851           need_redraw = TRUE;
3852           if (validate_row (tree_view, tree, node, &iter, path))
3853             size_changed = TRUE;
3854         }
3855       if (node)
3856         area_below -= MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
3857     }
3858   gtk_tree_path_free (path);
3859
3860   /* If we ran out of tree, and have extra area_below left, we need to remove it
3861    * from the area_above */
3862   if (area_below > 0)
3863     area_above += area_below;
3864
3865   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
3866
3867   /* We walk backwards */
3868   while (area_above > 0)
3869     {
3870       _gtk_rbtree_prev_full (tree, node, &tree, &node);
3871       if (! gtk_tree_path_prev (above_path) && node != NULL)
3872         {
3873           gtk_tree_path_free (above_path);
3874           above_path = _gtk_tree_view_find_path (tree_view, tree, node);
3875         }
3876       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
3877
3878       if (node == NULL)
3879         break;
3880
3881       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
3882           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3883         {
3884           need_redraw = TRUE;
3885           if (validate_row (tree_view, tree, node, &iter, above_path))
3886             size_changed = TRUE;
3887         }
3888       area_above -= MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
3889       modify_dy = TRUE;
3890     }
3891
3892   /* if we walk backwards at all, then we need to reset our dy. */
3893   if (modify_dy)
3894     {
3895       gint dy;
3896       if (node != NULL)
3897         {
3898           dy = _gtk_rbtree_node_find_offset (tree, node) - area_above;
3899         }
3900       else
3901         {
3902           dy = 0;
3903         }
3904       gtk_adjustment_set_value (tree_view->priv->vadjustment, dy);
3905       need_redraw = TRUE;
3906     }
3907
3908   if (tree_view->priv->scroll_to_path)
3909     {
3910       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
3911       tree_view->priv->scroll_to_path = NULL;
3912     }
3913
3914   if (above_path)
3915     gtk_tree_path_free (above_path);
3916
3917   if (tree_view->priv->scroll_to_column)
3918     {
3919       tree_view->priv->scroll_to_column = NULL;
3920     }
3921   if (size_changed)
3922     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3923   if (need_redraw)
3924     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3925 }
3926
3927
3928 /* Our strategy for finding nodes to validate is a little convoluted.  We find
3929  * the left-most uninvalidated node.  We then try walking right, validating
3930  * nodes.  Once we find a valid node, we repeat the previous process of finding
3931  * the first invalid node.
3932  */
3933
3934 static gboolean
3935 do_validate_rows (GtkTreeView *tree_view)
3936 {
3937   GtkRBTree *tree = NULL;
3938   GtkRBNode *node = NULL;
3939   gboolean validated_area = FALSE;
3940   gint retval = TRUE;
3941   GtkTreePath *path = NULL;
3942   GtkTreeIter iter;
3943   gint i = 0;
3944
3945   gint prev_height = -1;
3946   gboolean fixed_height = TRUE;
3947
3948   g_assert (tree_view);
3949
3950   if (tree_view->priv->tree == NULL)
3951     {
3952       tree_view->priv->validate_rows_timer = 0;
3953       return FALSE;
3954     }
3955   do
3956     {
3957       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
3958         {
3959           retval = FALSE;
3960           goto done;
3961         }
3962
3963       if (path != NULL)
3964         {
3965           node = _gtk_rbtree_next (tree, node);
3966           if (node != NULL)
3967             {
3968               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
3969               gtk_tree_path_next (path);
3970             }
3971           else
3972             {
3973               gtk_tree_path_free (path);
3974               path = NULL;
3975             }
3976         }
3977
3978       if (path == NULL)
3979         {
3980           tree = tree_view->priv->tree;
3981           node = tree_view->priv->tree->root;
3982
3983           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
3984
3985           do
3986             {
3987               if (node->left != tree->nil &&
3988                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
3989                 {
3990                   node = node->left;
3991                 }
3992               else if (node->right != tree->nil &&
3993                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
3994                 {
3995                   node = node->right;
3996                 }
3997               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
3998                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
3999                 {
4000                   break;
4001                 }
4002               else if (node->children != NULL)
4003                 {
4004                   tree = node->children;
4005                   node = tree->root;
4006                 }
4007               else
4008                 /* RBTree corruption!  All bad */
4009                 g_assert_not_reached ();
4010             }
4011           while (TRUE);
4012           path = _gtk_tree_view_find_path (tree_view, tree, node);
4013           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
4014         }
4015       validated_area = validate_row (tree_view, tree, node, &iter, path) | validated_area;
4016
4017       if (!tree_view->priv->fixed_height_check)
4018         {
4019           gint height;
4020
4021           height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
4022           if (prev_height < 0)
4023             prev_height = height;
4024           else if (prev_height != height)
4025             fixed_height = FALSE;
4026         }
4027
4028       i++;
4029     }
4030   while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
4031
4032   if (!tree_view->priv->fixed_height_check)
4033    {
4034      if (fixed_height)
4035        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height);
4036
4037      tree_view->priv->fixed_height_check = 1;
4038    }
4039   
4040  done:
4041   if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
4042     gtk_tree_view_top_row_to_dy (tree_view);
4043   else
4044     gtk_tree_view_dy_to_top_row (tree_view);
4045
4046   if (path) gtk_tree_path_free (path);
4047   if (validated_area)
4048     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4049   if (! retval)
4050     tree_view->priv->validate_rows_timer = 0;
4051
4052   return retval;
4053 }
4054
4055 static gboolean
4056 validate_rows_handler (GtkTreeView *tree_view)
4057 {
4058   gboolean retval;
4059
4060   GDK_THREADS_ENTER ();
4061
4062   retval = do_validate_rows (tree_view);
4063   
4064   GDK_THREADS_LEAVE ();
4065
4066   return retval;
4067 }
4068
4069 static gboolean
4070 do_presize_handler (GtkTreeView *tree_view)
4071 {
4072   if (tree_view->priv->mark_rows_col_dirty)
4073     {
4074       if (tree_view->priv->tree)
4075         _gtk_rbtree_column_invalid (tree_view->priv->tree);
4076       tree_view->priv->mark_rows_col_dirty = FALSE;
4077     }
4078   validate_visible_area (tree_view);
4079   tree_view->priv->presize_handler_timer = 0;
4080                    
4081   return FALSE;
4082 }
4083
4084 static gboolean
4085 presize_handler_callback (gpointer data)
4086 {
4087   GDK_THREADS_ENTER ();
4088
4089   do_presize_handler (GTK_TREE_VIEW (data));
4090                    
4091   GDK_THREADS_LEAVE ();
4092
4093   return FALSE;
4094 }
4095
4096 static void
4097 install_presize_handler (GtkTreeView *tree_view)
4098 {
4099   if (! GTK_WIDGET_REALIZED (tree_view))
4100     return;
4101
4102   if (! tree_view->priv->presize_handler_timer)
4103     {
4104       tree_view->priv->presize_handler_timer =
4105         g_idle_add_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
4106     }
4107   if (! tree_view->priv->validate_rows_timer)
4108     {
4109       tree_view->priv->validate_rows_timer =
4110         g_idle_add_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
4111     }
4112 }
4113
4114 static gboolean
4115 scroll_sync_handler (GtkTreeView *tree_view)
4116 {
4117
4118   GDK_THREADS_ENTER ();
4119
4120   if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
4121     gtk_tree_view_top_row_to_dy (tree_view);
4122   else
4123     gtk_tree_view_dy_to_top_row (tree_view);
4124
4125   tree_view->priv->scroll_sync_timer = 0;
4126
4127   GDK_THREADS_LEAVE ();
4128
4129   return FALSE;
4130 }
4131
4132 static void
4133 install_scroll_sync_handler (GtkTreeView *tree_view)
4134 {
4135   if (! GTK_WIDGET_REALIZED (tree_view))
4136     return;
4137
4138   if (!tree_view->priv->scroll_sync_timer)
4139     {
4140       tree_view->priv->scroll_sync_timer =
4141         g_idle_add_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
4142     }
4143 }
4144
4145 /* Always call this iff dy is in the visible range.  If the tree is empty, then
4146  * it's set to be NULL, and top_row_dy is 0;
4147  */
4148 static void
4149 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
4150 {
4151   GtkTreePath *path;
4152   GtkRBTree *tree;
4153   GtkRBNode *node;
4154
4155   gtk_tree_row_reference_free (tree_view->priv->top_row);
4156   if (tree_view->priv->tree == NULL)
4157     tree = NULL;
4158   else
4159     tree_view->priv->top_row_dy = _gtk_rbtree_find_offset (tree_view->priv->tree,
4160                                                            tree_view->priv->dy,
4161                                                            &tree, &node);
4162   if (tree == NULL)
4163     {
4164       tree_view->priv->top_row = NULL;
4165       tree_view->priv->top_row_dy = 0;
4166       return;
4167     }
4168       
4169   path = _gtk_tree_view_find_path (tree_view, tree, node);
4170   tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
4171   gtk_tree_path_free (path);
4172 }
4173
4174 static void
4175 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
4176 {
4177   GtkTreePath *path;
4178   GtkRBTree *tree;
4179   GtkRBNode *node;
4180
4181   if (tree_view->priv->top_row)
4182     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
4183   else
4184     path = NULL;
4185
4186   if (!path)
4187     tree = NULL;
4188   else
4189     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
4190
4191   if (path)
4192     gtk_tree_path_free (path);
4193
4194   if (tree == NULL)
4195     {
4196       /* keep dy and set new toprow */
4197       gtk_tree_row_reference_free (tree_view->priv->top_row);
4198       tree_view->priv->top_row = NULL;
4199       tree_view->priv->top_row_dy = 0;
4200       /* DO NOT install the idle handler */
4201       gtk_tree_view_dy_to_top_row (tree_view);
4202       return;
4203     }
4204
4205   if (MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size)
4206       < tree_view->priv->top_row_dy)
4207     {
4208       /* new top row -- do NOT install the idle handler */
4209       gtk_tree_view_dy_to_top_row (tree_view);
4210       return;
4211     }
4212
4213   tree_view->priv->dy = _gtk_rbtree_node_find_offset (tree, node);
4214   tree_view->priv->dy += tree_view->priv->top_row_dy;
4215   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4216                             tree_view->priv->dy);
4217 }
4218
4219 void
4220 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
4221 {
4222   tree_view->priv->mark_rows_col_dirty = TRUE;
4223
4224   install_presize_handler (tree_view);
4225 }
4226
4227 /*
4228  * This function works synchronously (due to the while (do_validate_rows...)
4229  * loop).
4230  *
4231  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
4232  * here. You now need to check that yourself.
4233  */
4234 void
4235 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
4236                                 GtkTreeViewColumn *column)
4237 {
4238   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
4239   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
4240
4241   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
4242
4243   do_presize_handler (tree_view);
4244   while (do_validate_rows (tree_view));
4245
4246   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
4247 }
4248
4249 /* Drag-and-drop */
4250
4251 static void
4252 set_source_row (GdkDragContext *context,
4253                 GtkTreeModel   *model,
4254                 GtkTreePath    *source_row)
4255 {
4256   g_object_set_data_full (G_OBJECT (context),
4257                           "gtk-tree-view-source-row",
4258                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
4259                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
4260 }
4261
4262 static GtkTreePath*
4263 get_source_row (GdkDragContext *context)
4264 {
4265   GtkTreeRowReference *ref =
4266     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
4267
4268   if (ref)
4269     return gtk_tree_row_reference_get_path (ref);
4270   else
4271     return NULL;
4272 }
4273
4274
4275 static void
4276 set_dest_row (GdkDragContext *context,
4277               GtkTreeModel   *model,
4278               GtkTreePath    *dest_row)
4279 {
4280   g_object_set_data_full (G_OBJECT (context),
4281                           "gtk-tree-view-dest-row",
4282                           dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
4283                           (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
4284 }
4285
4286 static GtkTreePath*
4287 get_dest_row (GdkDragContext *context)
4288 {
4289   GtkTreeRowReference *ref =
4290     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
4291
4292   if (ref)
4293     return gtk_tree_row_reference_get_path (ref);
4294   else
4295     return NULL;
4296 }
4297
4298 /* Get/set whether drag_motion requested the drag data and
4299  * drag_data_received should thus not actually insert the data,
4300  * since the data doesn't result from a drop.
4301  */
4302 static void
4303 set_status_pending (GdkDragContext *context,
4304                     GdkDragAction   suggested_action)
4305 {
4306   g_object_set_data (G_OBJECT (context),
4307                      "gtk-tree-view-status-pending",
4308                      GINT_TO_POINTER (suggested_action));
4309 }
4310
4311 static GdkDragAction
4312 get_status_pending (GdkDragContext *context)
4313 {
4314   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
4315                                              "gtk-tree-view-status-pending"));
4316 }
4317
4318 static TreeViewDragInfo*
4319 get_info (GtkTreeView *tree_view)
4320 {
4321   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
4322 }
4323
4324 static void
4325 clear_source_info (TreeViewDragInfo *di)
4326 {
4327   if (di->source_target_list)
4328     gtk_target_list_unref (di->source_target_list);
4329
4330   di->source_target_list = NULL;
4331 }
4332
4333 static void
4334 clear_dest_info (TreeViewDragInfo *di)
4335 {
4336   if (di->dest_target_list)
4337     gtk_target_list_unref (di->dest_target_list);
4338
4339   di->dest_target_list = NULL;
4340 }
4341
4342 static void
4343 destroy_info (TreeViewDragInfo *di)
4344 {
4345   clear_source_info (di);
4346   clear_dest_info (di);
4347   g_free (di);
4348 }
4349
4350 static TreeViewDragInfo*
4351 ensure_info (GtkTreeView *tree_view)
4352 {
4353   TreeViewDragInfo *di;
4354
4355   di = get_info (tree_view);
4356
4357   if (di == NULL)
4358     {
4359       di = g_new0 (TreeViewDragInfo, 1);
4360
4361       g_object_set_data_full (G_OBJECT (tree_view),
4362                               "gtk-tree-view-drag-info",
4363                               di,
4364                               (GDestroyNotify) destroy_info);
4365     }
4366
4367   return di;
4368 }
4369
4370 static void
4371 remove_info (GtkTreeView *tree_view)
4372 {
4373   g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
4374 }
4375
4376 #if 0
4377 static gint
4378 drag_scan_timeout (gpointer data)
4379 {
4380   GtkTreeView *tree_view;
4381   gint x, y;
4382   GdkModifierType state;
4383   GtkTreePath *path = NULL;
4384   GtkTreeViewColumn *column = NULL;
4385   GdkRectangle visible_rect;
4386
4387   GDK_THREADS_ENTER ();
4388
4389   tree_view = GTK_TREE_VIEW (data);
4390
4391   gdk_window_get_pointer (tree_view->priv->bin_window,
4392                           &x, &y, &state);
4393
4394   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4395
4396   /* See if we are near the edge. */
4397   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
4398       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
4399       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
4400       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
4401     {
4402       gtk_tree_view_get_path_at_pos (tree_view,
4403                                      tree_view->priv->bin_window,
4404                                      x, y,
4405                                      &path,
4406                                      &column,
4407                                      NULL,
4408                                      NULL);
4409
4410       if (path != NULL)
4411         {
4412           gtk_tree_view_scroll_to_cell (tree_view,
4413                                         path,
4414                                         column,
4415                                         TRUE,
4416                                         0.5, 0.5);
4417
4418           gtk_tree_path_free (path);
4419         }
4420     }
4421
4422   GDK_THREADS_LEAVE ();
4423
4424   return TRUE;
4425 }
4426 #endif /* 0 */
4427
4428 static void
4429 remove_scroll_timeout (GtkTreeView *tree_view)
4430 {
4431   if (tree_view->priv->scroll_timeout != 0)
4432     {
4433       gtk_timeout_remove (tree_view->priv->scroll_timeout);
4434       tree_view->priv->scroll_timeout = 0;
4435     }
4436 }
4437 static gboolean
4438 check_model_dnd (GtkTreeModel *model,
4439                  GType         required_iface,
4440                  const gchar  *signal)
4441 {
4442   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
4443     {
4444       g_warning ("You must override the default '%s' handler "
4445                  "on GtkTreeView when using models that don't support "
4446                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
4447                  "is to connect to '%s' and call "
4448                  "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
4449                  "the default handler from running. Look at the source code "
4450                  "for the default handler in gtktreeview.c to get an idea what "
4451                  "your handler should do. (gtktreeview.c is in the GTK source "
4452                  "code.) If you're using GTK from a language other than C, "
4453                  "there may be a more natural way to override default handlers, e.g. via derivation.",
4454                  signal, g_type_name (required_iface), signal);
4455       return FALSE;
4456     }
4457   else
4458     return TRUE;
4459 }
4460
4461 static void
4462 remove_open_timeout (GtkTreeView *tree_view)
4463 {
4464   if (tree_view->priv->open_dest_timeout != 0)
4465     {
4466       gtk_timeout_remove (tree_view->priv->open_dest_timeout);
4467       tree_view->priv->open_dest_timeout = 0;
4468     }
4469 }
4470
4471
4472 static gint
4473 open_row_timeout (gpointer data)
4474 {
4475   GtkTreeView *tree_view = data;
4476   GtkTreePath *dest_path = NULL;
4477   GtkTreeViewDropPosition pos;
4478   gboolean result = FALSE;
4479
4480   GDK_THREADS_ENTER ();
4481
4482   gtk_tree_view_get_drag_dest_row (tree_view,
4483                                    &dest_path,
4484                                    &pos);
4485
4486   if (dest_path &&
4487       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
4488        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
4489     {
4490       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
4491       tree_view->priv->open_dest_timeout = 0;
4492
4493       gtk_tree_path_free (dest_path);
4494     }
4495   else
4496     {
4497       if (dest_path)
4498         gtk_tree_path_free (dest_path);
4499
4500       result = TRUE;
4501     }
4502
4503   GDK_THREADS_LEAVE ();
4504
4505   return result;
4506 }
4507
4508 static gint
4509 scroll_row_timeout (gpointer data)
4510 {
4511   GtkTreeView *tree_view = data;
4512
4513   GDK_THREADS_ENTER ();
4514
4515   gtk_tree_view_vertical_autoscroll (tree_view);
4516
4517   GDK_THREADS_LEAVE ();
4518
4519   return TRUE;
4520 }
4521
4522 /* Returns TRUE if event should not be propagated to parent widgets */
4523 static gboolean
4524 set_destination_row (GtkTreeView    *tree_view,
4525                      GdkDragContext *context,
4526                      gint            x,
4527                      gint            y,
4528                      GdkDragAction  *suggested_action,
4529                      GdkAtom        *target)
4530 {
4531   GtkTreePath *path = NULL;
4532   GtkTreeViewDropPosition pos;
4533   GtkTreeViewDropPosition old_pos;
4534   TreeViewDragInfo *di;
4535   GtkWidget *widget;
4536   GtkTreePath *old_dest_path = NULL;
4537
4538   *suggested_action = 0;
4539   *target = GDK_NONE;
4540
4541   widget = GTK_WIDGET (tree_view);
4542
4543   di = get_info (tree_view);
4544
4545   if (di == NULL)
4546     {
4547       /* someone unset us as a drag dest, note that if
4548        * we return FALSE drag_leave isn't called
4549        */
4550
4551       gtk_tree_view_set_drag_dest_row (tree_view,
4552                                        NULL,
4553                                        GTK_TREE_VIEW_DROP_BEFORE);
4554
4555       remove_scroll_timeout (GTK_TREE_VIEW (widget));
4556       remove_open_timeout (GTK_TREE_VIEW (widget));
4557
4558       return FALSE; /* no longer a drop site */
4559     }
4560
4561   *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
4562   if (*target == GDK_NONE)
4563     {
4564       return FALSE;
4565     }
4566
4567   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
4568                                           x, y,
4569                                           &path,
4570                                           &pos))
4571     {
4572       /* can't drop here */
4573       remove_open_timeout (tree_view);
4574
4575       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4576                                        NULL,
4577                                        GTK_TREE_VIEW_DROP_BEFORE);
4578
4579       if (path)
4580         gtk_tree_path_free (path);
4581
4582       /* don't propagate to parent though */
4583       return TRUE;
4584     }
4585
4586   g_assert (path);
4587
4588   /* If we left the current row's "open" zone, unset the timeout for
4589    * opening the row
4590    */
4591   gtk_tree_view_get_drag_dest_row (tree_view,
4592                                    &old_dest_path,
4593                                    &old_pos);
4594
4595   if (old_dest_path &&
4596       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
4597        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
4598          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
4599     remove_open_timeout (tree_view);
4600
4601   if (old_dest_path)
4602     gtk_tree_path_free (old_dest_path);
4603
4604   if (TRUE /* FIXME if the location droppable predicate */)
4605     {
4606       GtkWidget *source_widget;
4607
4608       *suggested_action = context->suggested_action;
4609
4610       source_widget = gtk_drag_get_source_widget (context);
4611
4612       if (source_widget == widget)
4613         {
4614           /* Default to MOVE, unless the user has
4615            * pressed ctrl or alt to affect available actions
4616            */
4617           if ((context->actions & GDK_ACTION_MOVE) != 0)
4618             *suggested_action = GDK_ACTION_MOVE;
4619         }
4620
4621       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4622                                        path, pos);
4623     }
4624   else
4625     {
4626       /* can't drop here */
4627       remove_open_timeout (tree_view);
4628
4629       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4630                                        NULL,
4631                                        GTK_TREE_VIEW_DROP_BEFORE);
4632     }
4633
4634   if (path)
4635     gtk_tree_path_free (path);
4636
4637   return TRUE;
4638 }
4639 static GtkTreePath*
4640 get_logical_dest_row (GtkTreeView *tree_view)
4641
4642 {
4643   /* adjust path to point to the row the drop goes in front of */
4644   GtkTreePath *path = NULL;
4645   GtkTreeViewDropPosition pos;
4646
4647   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
4648
4649   if (path == NULL)
4650     return NULL;
4651
4652   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
4653     ; /* do nothing */
4654   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
4655            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
4656     {
4657       /* get first child, drop before it */
4658       gtk_tree_path_down (path);
4659     }
4660   else
4661     {
4662       GtkTreeIter iter;
4663       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
4664
4665       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
4666
4667       gtk_tree_model_get_iter (model, &iter, path);
4668
4669       if (!gtk_tree_model_iter_next (model, &iter))
4670         g_object_set_data (G_OBJECT (model), "gtk-tree-model-drop-append",
4671                            GINT_TO_POINTER (1));
4672       else
4673         {
4674           g_object_set_data (G_OBJECT (model), "gtk-tree-model-drop-append",
4675                              NULL);
4676           gtk_tree_path_next (path);
4677         }
4678     }
4679
4680   return path;
4681 }
4682
4683 static gboolean
4684 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
4685                                         GdkEventMotion   *event)
4686 {
4687   GdkDragContext *context;
4688   TreeViewDragInfo *di;
4689   GtkTreePath *path = NULL;
4690   gint button;
4691   gint cell_x, cell_y;
4692   GtkTreeModel *model;
4693   gboolean retval = FALSE;
4694
4695   di = get_info (tree_view);
4696
4697   if (di == NULL)
4698     goto out;
4699
4700   if (tree_view->priv->pressed_button < 0)
4701     goto out;
4702
4703   if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
4704                                  tree_view->priv->press_start_x,
4705                                  tree_view->priv->press_start_y,
4706                                  event->x, event->y))
4707     goto out;
4708
4709   model = gtk_tree_view_get_model (tree_view);
4710
4711   if (model == NULL)
4712     goto out;
4713
4714   button = tree_view->priv->pressed_button;
4715   tree_view->priv->pressed_button = -1;
4716
4717   gtk_tree_view_get_path_at_pos (tree_view,
4718                                  tree_view->priv->press_start_x,
4719                                  tree_view->priv->press_start_y,
4720                                  &path,
4721                                  NULL,
4722                                  &cell_x,
4723                                  &cell_y);
4724
4725   if (path == NULL)
4726     goto out;
4727
4728   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
4729       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
4730                                            path))
4731     goto out;
4732
4733   /* FIXME Check whether we're a start button, if not return FALSE and
4734    * free path
4735    */
4736
4737   /* Now we can begin the drag */
4738
4739   retval = TRUE;
4740
4741   context = gtk_drag_begin (GTK_WIDGET (tree_view),
4742                             di->source_target_list,
4743                             di->source_actions,
4744                             button,
4745                             (GdkEvent*)event);
4746
4747   gtk_drag_set_icon_default (context);
4748
4749   {
4750     GdkPixmap *row_pix;
4751
4752     row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
4753                                                   path);
4754
4755     gtk_drag_set_icon_pixmap (context,
4756                               gdk_drawable_get_colormap (row_pix),
4757                               row_pix,
4758                               NULL,
4759                               /* the + 1 is for the black border in the icon */
4760                               tree_view->priv->press_start_x + 1,
4761                               cell_y + 1);
4762
4763     gdk_pixmap_unref (row_pix);
4764   }
4765
4766   set_source_row (context, model, path);
4767
4768  out:
4769   if (path)
4770     gtk_tree_path_free (path);
4771
4772   return retval;
4773 }
4774
4775
4776 static void
4777 gtk_tree_view_drag_begin (GtkWidget      *widget,
4778                           GdkDragContext *context)
4779 {
4780   /* do nothing */
4781 }
4782
4783 static void
4784 gtk_tree_view_drag_end (GtkWidget      *widget,
4785                         GdkDragContext *context)
4786 {
4787   /* do nothing */
4788 }
4789
4790 /* Default signal implementations for the drag signals */
4791 static void
4792 gtk_tree_view_drag_data_get (GtkWidget        *widget,
4793                              GdkDragContext   *context,
4794                              GtkSelectionData *selection_data,
4795                              guint             info,
4796                              guint             time)
4797 {
4798   GtkTreeView *tree_view;
4799   GtkTreeModel *model;
4800   TreeViewDragInfo *di;
4801   GtkTreePath *source_row;
4802
4803   tree_view = GTK_TREE_VIEW (widget);
4804
4805   model = gtk_tree_view_get_model (tree_view);
4806
4807   if (model == NULL)
4808     return;
4809
4810   di = get_info (GTK_TREE_VIEW (widget));
4811
4812   if (di == NULL)
4813     return;
4814
4815   source_row = get_source_row (context);
4816
4817   if (source_row == NULL)
4818     return;
4819
4820   /* We can implement the GTK_TREE_MODEL_ROW target generically for
4821    * any model; for DragSource models there are some other targets
4822    * we also support.
4823    */
4824
4825   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
4826       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
4827                                           source_row,
4828                                           selection_data))
4829     goto done;
4830
4831   /* If drag_data_get does nothing, try providing row data. */
4832   if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
4833     {
4834       gtk_tree_set_row_drag_data (selection_data,
4835                                   model,
4836                                   source_row);
4837     }
4838
4839  done:
4840   gtk_tree_path_free (source_row);
4841 }
4842
4843
4844 static void
4845 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
4846                                 GdkDragContext *context)
4847 {
4848   TreeViewDragInfo *di;
4849   GtkTreeModel *model;
4850   GtkTreeView *tree_view;
4851   GtkTreePath *source_row;
4852
4853   tree_view = GTK_TREE_VIEW (widget);
4854   model = gtk_tree_view_get_model (tree_view);
4855
4856   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
4857     return;
4858
4859   di = get_info (tree_view);
4860
4861   if (di == NULL)
4862     return;
4863
4864   source_row = get_source_row (context);
4865
4866   if (source_row == NULL)
4867     return;
4868
4869   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
4870                                          source_row);
4871
4872   gtk_tree_path_free (source_row);
4873
4874   set_source_row (context, NULL, NULL);
4875 }
4876
4877 static void
4878 gtk_tree_view_drag_leave (GtkWidget      *widget,
4879                           GdkDragContext *context,
4880                           guint             time)
4881 {
4882   TreeViewDragInfo *di;
4883
4884   di = get_info (GTK_TREE_VIEW (widget));
4885
4886   /* unset any highlight row */
4887   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
4888                                    NULL,
4889                                    GTK_TREE_VIEW_DROP_BEFORE);
4890
4891   remove_scroll_timeout (GTK_TREE_VIEW (widget));
4892   remove_open_timeout (GTK_TREE_VIEW (widget));
4893 }
4894
4895
4896 static gboolean
4897 gtk_tree_view_drag_motion (GtkWidget        *widget,
4898                            GdkDragContext   *context,
4899                            gint              x,
4900                            gint              y,
4901                            guint             time)
4902 {
4903   GtkTreePath *path = NULL;
4904   GtkTreeViewDropPosition pos;
4905   GtkTreeView *tree_view;
4906   GdkDragAction suggested_action = 0;
4907   GdkAtom target;
4908
4909   tree_view = GTK_TREE_VIEW (widget);
4910
4911   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
4912     return FALSE;
4913
4914   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
4915
4916   if (path == NULL)
4917     {
4918       /* Can't drop here. */
4919       gdk_drag_status (context, 0, time);
4920     }
4921   else
4922     {
4923       if (tree_view->priv->open_dest_timeout == 0 &&
4924           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
4925            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
4926         {
4927           tree_view->priv->open_dest_timeout =
4928             gtk_timeout_add (500, open_row_timeout, tree_view);
4929         }
4930       else if (tree_view->priv->scroll_timeout == 0)
4931         {
4932           tree_view->priv->scroll_timeout =
4933             gtk_timeout_add (150, scroll_row_timeout, tree_view);
4934         }
4935
4936       if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
4937         {
4938           /* Request data so we can use the source row when
4939            * determining whether to accept the drop
4940            */
4941           set_status_pending (context, suggested_action);
4942           gtk_drag_get_data (widget, context, target, time);
4943         }
4944       else
4945         {
4946           set_status_pending (context, 0);
4947           gdk_drag_status (context, suggested_action, time);
4948         }
4949     }
4950
4951   if (path)
4952     gtk_tree_path_free (path);
4953
4954   return TRUE;
4955 }
4956
4957
4958 static gboolean
4959 gtk_tree_view_drag_drop (GtkWidget        *widget,
4960                          GdkDragContext   *context,
4961                          gint              x,
4962                          gint              y,
4963                          guint             time)
4964 {
4965   GtkTreeView *tree_view;
4966   GtkTreePath *path;
4967   GdkDragAction suggested_action = 0;
4968   GdkAtom target = GDK_NONE;
4969   TreeViewDragInfo *di;
4970   GtkTreeModel *model;
4971
4972   tree_view = GTK_TREE_VIEW (widget);
4973
4974   model = gtk_tree_view_get_model (tree_view);
4975
4976   remove_scroll_timeout (GTK_TREE_VIEW (widget));
4977   remove_open_timeout (GTK_TREE_VIEW (widget));
4978
4979   di = get_info (tree_view);
4980
4981   if (di == NULL)
4982     return FALSE;
4983
4984   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
4985     return FALSE;
4986
4987   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
4988     return FALSE;
4989
4990   path = get_logical_dest_row (tree_view);
4991
4992   if (target != GDK_NONE && path != NULL)
4993     {
4994       /* in case a motion had requested drag data, change things so we
4995        * treat drag data receives as a drop.
4996        */
4997       set_status_pending (context, 0);
4998
4999       set_dest_row (context, model, path);
5000     }
5001
5002   if (path)
5003     gtk_tree_path_free (path);
5004
5005   /* Unset this thing */
5006   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
5007                                    NULL,
5008                                    GTK_TREE_VIEW_DROP_BEFORE);
5009
5010   if (target != GDK_NONE)
5011     {
5012       gtk_drag_get_data (widget, context, target, time);
5013       return TRUE;
5014     }
5015   else
5016     return FALSE;
5017 }
5018
5019 static void
5020 gtk_tree_view_drag_data_received (GtkWidget        *widget,
5021                                   GdkDragContext   *context,
5022                                   gint              x,
5023                                   gint              y,
5024                                   GtkSelectionData *selection_data,
5025                                   guint             info,
5026                                   guint             time)
5027 {
5028   GtkTreePath *path;
5029   TreeViewDragInfo *di;
5030   gboolean accepted = FALSE;
5031   GtkTreeModel *model;
5032   GtkTreeView *tree_view;
5033   GtkTreePath *dest_row;
5034   GdkDragAction suggested_action;
5035
5036   tree_view = GTK_TREE_VIEW (widget);
5037
5038   model = gtk_tree_view_get_model (tree_view);
5039
5040   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
5041     return;
5042
5043   di = get_info (tree_view);
5044
5045   if (di == NULL)
5046     return;
5047
5048   suggested_action = get_status_pending (context);
5049
5050   if (suggested_action)
5051     {
5052       /* We are getting this data due to a request in drag_motion,
5053        * rather than due to a request in drag_drop, so we are just
5054        * supposed to call drag_status, not actually paste in the
5055        * data.
5056        */
5057       path = get_logical_dest_row (tree_view);
5058
5059       if (path == NULL)
5060         suggested_action = 0;
5061
5062       if (suggested_action)
5063         {
5064           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
5065                                                      path,
5066                                                      selection_data))
5067             suggested_action = 0;
5068         }
5069
5070       gdk_drag_status (context, suggested_action, time);
5071
5072       if (path)
5073         gtk_tree_path_free (path);
5074
5075       /* If you can't drop, remove user drop indicator until the next motion */
5076       if (suggested_action == 0)
5077         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
5078                                          NULL,
5079                                          GTK_TREE_VIEW_DROP_BEFORE);
5080
5081       return;
5082     }
5083
5084   dest_row = get_dest_row (context);
5085
5086   if (dest_row == NULL)
5087     return;
5088
5089   if (selection_data->length >= 0)
5090     {
5091       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
5092                                                  dest_row,
5093                                                  selection_data))
5094         accepted = TRUE;
5095     }
5096
5097   gtk_drag_finish (context,
5098                    accepted,
5099                    (context->action == GDK_ACTION_MOVE),
5100                    time);
5101
5102   gtk_tree_path_free (dest_row);
5103
5104   /* drop dest_row */
5105   set_dest_row (context, NULL, NULL);
5106 }
5107
5108
5109
5110 /* GtkContainer Methods
5111  */
5112
5113
5114 static void
5115 gtk_tree_view_remove (GtkContainer *container,
5116                       GtkWidget    *widget)
5117 {
5118   GtkTreeView *tree_view;
5119   GtkTreeViewChild *child = NULL;
5120   GList *tmp_list;
5121
5122   g_return_if_fail (GTK_IS_TREE_VIEW (container));
5123
5124   tree_view = GTK_TREE_VIEW (container);
5125
5126   tmp_list = tree_view->priv->children;
5127   while (tmp_list)
5128     {
5129       child = tmp_list->data;
5130       if (child->widget == widget)
5131         {
5132           gtk_widget_unparent (widget);
5133
5134           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
5135           g_list_free_1 (tmp_list);
5136           g_free (child);
5137           return;
5138         }
5139
5140       tmp_list = tmp_list->next;
5141     }
5142
5143   tmp_list = tree_view->priv->columns;
5144
5145   while (tmp_list)
5146     {
5147       GtkTreeViewColumn *column;
5148       column = tmp_list->data;
5149       if (column->button == widget)
5150         {
5151           gtk_widget_unparent (widget);
5152           return;
5153         }
5154       tmp_list = tmp_list->next;
5155     }
5156 }
5157
5158 static void
5159 gtk_tree_view_forall (GtkContainer *container,
5160                       gboolean      include_internals,
5161                       GtkCallback   callback,
5162                       gpointer      callback_data)
5163 {
5164   GtkTreeView *tree_view;
5165   GtkTreeViewChild *child = NULL;
5166   GtkTreeViewColumn *column;
5167   GList *tmp_list;
5168
5169   g_return_if_fail (GTK_IS_TREE_VIEW (container));
5170   g_return_if_fail (callback != NULL);
5171
5172   tree_view = GTK_TREE_VIEW (container);
5173
5174   tmp_list = tree_view->priv->children;
5175   while (tmp_list)
5176     {
5177       child = tmp_list->data;
5178       tmp_list = tmp_list->next;
5179
5180       (* callback) (child->widget, callback_data);
5181     }
5182   if (include_internals == FALSE)
5183     return;
5184
5185   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
5186     {
5187       column = tmp_list->data;
5188
5189       if (column->button)
5190         (* callback) (column->button, callback_data);
5191     }
5192 }
5193
5194 /* Returns TRUE if the focus is within the headers, after the focus operation is
5195  * done
5196  */
5197 static gboolean
5198 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
5199                             GtkDirectionType  dir)
5200 {
5201   GtkWidget *focus_child;
5202   GtkContainer *container;
5203
5204   GList *last_column, *first_column;
5205   GList *tmp_list;
5206
5207   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5208     return FALSE;
5209
5210   focus_child = GTK_CONTAINER (tree_view)->focus_child;
5211   container = GTK_CONTAINER (tree_view);
5212
5213   first_column = tree_view->priv->columns;
5214   while (first_column)
5215     {
5216       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
5217           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
5218           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
5219            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
5220         break;
5221       first_column = first_column->next;
5222     }
5223
5224   /* No headers are visible, or are focusable.  We can't focus in or out.
5225    */
5226   if (first_column == NULL)
5227     return FALSE;
5228
5229   last_column = g_list_last (tree_view->priv->columns);
5230   while (last_column)
5231     {
5232       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
5233           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
5234           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
5235            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
5236         break;
5237       last_column = last_column->prev;
5238     }
5239
5240
5241   switch (dir)
5242     {
5243     case GTK_DIR_TAB_BACKWARD:
5244     case GTK_DIR_TAB_FORWARD:
5245     case GTK_DIR_UP:
5246     case GTK_DIR_DOWN:
5247       if (focus_child == NULL)
5248         {
5249           if (tree_view->priv->focus_column != NULL)
5250             focus_child = tree_view->priv->focus_column->button;
5251           else
5252             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
5253           gtk_widget_grab_focus (focus_child);
5254           break;
5255         }
5256       return FALSE;
5257
5258     case GTK_DIR_LEFT:
5259     case GTK_DIR_RIGHT:
5260       if (focus_child == NULL)
5261         {
5262           if (tree_view->priv->focus_column != NULL)
5263             focus_child = tree_view->priv->focus_column->button;
5264           else if (dir == GTK_DIR_LEFT)
5265             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
5266           else
5267             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
5268           gtk_widget_grab_focus (focus_child);
5269           break;
5270         }
5271
5272       if (gtk_widget_child_focus (focus_child, dir))
5273         {
5274           /* The focus moves inside the button. */
5275           /* This is probably a great example of bad UI */
5276           break;
5277         }
5278
5279       /* We need to move the focus among the row of buttons. */
5280       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
5281         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
5282           break;
5283
5284       if (tmp_list == first_column && dir == GTK_DIR_LEFT)
5285         {
5286           focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
5287           gtk_widget_grab_focus (focus_child);
5288           break;
5289         }
5290       else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
5291         {
5292           focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
5293           gtk_widget_grab_focus (focus_child);
5294           break;
5295         }
5296
5297       while (tmp_list)
5298         {
5299           GtkTreeViewColumn *column;
5300
5301           if (dir == GTK_DIR_RIGHT)
5302             tmp_list = tmp_list->next;
5303           else
5304             tmp_list = tmp_list->prev;
5305
5306           if (tmp_list == NULL)
5307             {
5308               g_warning ("Internal button not found");
5309               break;
5310             }
5311           column = tmp_list->data;
5312           if (column->button &&
5313               column->visible &&
5314               GTK_WIDGET_CAN_FOCUS (column->button))
5315             {
5316               focus_child = column->button;
5317               gtk_widget_grab_focus (column->button);
5318               break;
5319             }
5320         }
5321       break;
5322     default:
5323       g_assert_not_reached ();
5324       break;
5325     }
5326
5327   /* if focus child is non-null, we assume it's been set to the current focus child
5328    */
5329   if (focus_child)
5330     {
5331       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
5332         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
5333           break;
5334
5335       tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5336
5337       /* If the following isn't true, then the view is smaller then the scrollpane.
5338        */
5339       if ((focus_child->allocation.x + focus_child->allocation.width) <=
5340           (tree_view->priv->hadjustment->upper))
5341         {
5342           /* Scroll to the button, if needed */
5343           if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
5344               (focus_child->allocation.x + focus_child->allocation.width))
5345             gtk_adjustment_set_value (tree_view->priv->hadjustment,
5346                                       focus_child->allocation.x + focus_child->allocation.width -
5347                                       tree_view->priv->hadjustment->page_size);
5348           else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
5349             gtk_adjustment_set_value (tree_view->priv->hadjustment,
5350                                       focus_child->allocation.x);
5351         }
5352     }
5353
5354   return (focus_child != NULL);
5355 }
5356
5357 static gint
5358 gtk_tree_view_focus (GtkWidget        *widget,
5359                      GtkDirectionType  direction)
5360 {
5361   GtkTreeView *tree_view;
5362   GtkWidget *focus_child;
5363   GtkContainer *container;
5364
5365   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
5366   g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
5367
5368   container = GTK_CONTAINER (widget);
5369   tree_view = GTK_TREE_VIEW (widget);
5370
5371   if (!GTK_WIDGET_IS_SENSITIVE (container))
5372     return FALSE;
5373
5374   focus_child = container->focus_child;
5375
5376   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
5377   /* Case 1.  Headers currently have focus. */
5378   if (focus_child)
5379     {
5380       switch (direction)
5381         {
5382         case GTK_DIR_LEFT:
5383         case GTK_DIR_RIGHT:
5384           gtk_tree_view_header_focus (tree_view, direction);
5385           return TRUE;
5386         case GTK_DIR_TAB_BACKWARD:
5387         case GTK_DIR_UP:
5388           return FALSE;
5389         case GTK_DIR_TAB_FORWARD:
5390         case GTK_DIR_DOWN:
5391           if (tree_view->priv->tree == NULL)
5392             return FALSE;
5393           gtk_widget_grab_focus (widget);
5394           return TRUE;
5395         }
5396     }
5397
5398   /* Case 2. We don't have focus at all. */
5399   if (!GTK_WIDGET_HAS_FOCUS (container))
5400     {
5401       if (tree_view->priv->tree == NULL &&
5402           (direction == GTK_DIR_TAB_BACKWARD ||
5403            direction == GTK_DIR_UP))
5404         return gtk_tree_view_header_focus (tree_view, direction);
5405       if (((direction == GTK_DIR_TAB_FORWARD) ||
5406            (direction == GTK_DIR_RIGHT) ||
5407            (direction == GTK_DIR_DOWN) ||
5408            (direction == GTK_DIR_LEFT)) &&
5409           gtk_tree_view_header_focus (tree_view, direction))
5410         return TRUE;
5411
5412       if (tree_view->priv->tree == NULL)
5413         return FALSE;
5414       gtk_widget_grab_focus (widget);
5415       return TRUE;
5416     }
5417
5418   /* Case 3. We have focus already. */
5419   if (tree_view->priv->tree == NULL)
5420     return gtk_tree_view_header_focus (tree_view, direction);
5421
5422   if (direction == GTK_DIR_TAB_BACKWARD)
5423     return (gtk_tree_view_header_focus (tree_view, direction));
5424   else if (direction == GTK_DIR_TAB_FORWARD)
5425     return FALSE;
5426
5427   /* Other directions caught by the keybindings */
5428   gtk_widget_grab_focus (widget);
5429   return TRUE;
5430 }
5431
5432 static void
5433 gtk_tree_view_grab_focus (GtkWidget *widget)
5434 {
5435   (* GTK_WIDGET_CLASS (parent_class)->grab_focus) (widget);
5436
5437   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
5438 }
5439
5440 static void
5441 gtk_tree_view_style_set (GtkWidget *widget,
5442                          GtkStyle *previous_style)
5443 {
5444   GtkTreeView *tree_view;
5445   GList *list;
5446   GtkTreeViewColumn *column;
5447
5448   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
5449
5450   tree_view = GTK_TREE_VIEW (widget);
5451
5452   gtk_widget_style_get (widget,
5453                         "expander_size", &tree_view->priv->expander_size,
5454                         NULL);
5455   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
5456
5457   for (list = tree_view->priv->columns; list; list = list->next)
5458     {
5459       column = list->data;
5460       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
5461     }
5462
5463   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
5464
5465   gtk_widget_queue_resize (widget);
5466 }
5467
5468
5469 static void
5470 gtk_tree_view_set_focus_child (GtkContainer *container,
5471                                GtkWidget    *child)
5472 {
5473   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
5474   GList *list;
5475
5476   for (list = tree_view->priv->columns; list; list = list->next)
5477     {
5478       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
5479         {
5480           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
5481           break;
5482         }
5483     }
5484
5485   (* parent_class->set_focus_child) (container, child);
5486 }
5487
5488 static void
5489 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
5490                                GtkAdjustment *hadj,
5491                                GtkAdjustment *vadj)
5492 {
5493   gboolean need_adjust = FALSE;
5494
5495   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5496
5497   if (hadj)
5498     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
5499   else
5500     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
5501   if (vadj)
5502     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
5503   else
5504     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
5505
5506   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
5507     {
5508       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
5509       gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
5510     }
5511
5512   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
5513     {
5514       gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
5515       gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
5516     }
5517
5518   if (tree_view->priv->hadjustment != hadj)
5519     {
5520       tree_view->priv->hadjustment = hadj;
5521       gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
5522       gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
5523
5524       gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
5525                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
5526                           tree_view);
5527       need_adjust = TRUE;
5528     }
5529
5530   if (tree_view->priv->vadjustment != vadj)
5531     {
5532       tree_view->priv->vadjustment = vadj;
5533       gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
5534       gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
5535
5536       gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
5537                           (GtkSignalFunc) gtk_tree_view_adjustment_changed,
5538                           tree_view);
5539       need_adjust = TRUE;
5540     }
5541
5542   if (need_adjust)
5543     gtk_tree_view_adjustment_changed (NULL, tree_view);
5544 }
5545
5546
5547 static gboolean
5548 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
5549                                 GtkMovementStep    step,
5550                                 gint               count)
5551 {
5552   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
5553   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
5554                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
5555                         step == GTK_MOVEMENT_DISPLAY_LINES ||
5556                         step == GTK_MOVEMENT_PAGES ||
5557                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
5558
5559   if (tree_view->priv->tree == NULL)
5560     return FALSE;
5561   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
5562     return FALSE;
5563
5564   gtk_tree_view_stop_editing (tree_view, FALSE);
5565   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
5566   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5567
5568   switch (step)
5569     {
5570       /* currently we make no distinction.  When we go bi-di, we need to */
5571     case GTK_MOVEMENT_LOGICAL_POSITIONS:
5572     case GTK_MOVEMENT_VISUAL_POSITIONS:
5573       gtk_tree_view_move_cursor_left_right (tree_view, count);
5574       break;
5575     case GTK_MOVEMENT_DISPLAY_LINES:
5576       gtk_tree_view_move_cursor_up_down (tree_view, count);
5577       break;
5578     case GTK_MOVEMENT_PAGES:
5579       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
5580       break;
5581     case GTK_MOVEMENT_BUFFER_ENDS:
5582       gtk_tree_view_move_cursor_start_end (tree_view, count);
5583       break;
5584     default:
5585       g_assert_not_reached ();
5586     }
5587
5588   return TRUE;
5589 }
5590
5591 static void
5592 gtk_tree_view_put (GtkTreeView *tree_view,
5593                    GtkWidget   *child_widget,
5594                    gint         x,
5595                    gint         y,
5596                    gint         width,
5597                    gint         height)
5598 {
5599   GtkTreeViewChild *child;
5600
5601   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5602   g_return_if_fail (GTK_IS_WIDGET (child_widget));
5603
5604   child = g_new (GtkTreeViewChild, 1);
5605
5606   child->widget = child_widget;
5607   child->x = x;
5608   child->y = y;
5609   child->width = width;
5610   child->height = height;
5611
5612   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
5613
5614   if (GTK_WIDGET_REALIZED (tree_view))
5615     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
5616
5617   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
5618 }
5619
5620 void
5621 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
5622                                   GtkWidget   *widget,
5623                                   gint         x,
5624                                   gint         y,
5625                                   gint         width,
5626                                   gint         height)
5627 {
5628   GtkTreeViewChild *child = NULL;
5629   GList *list;
5630   GdkRectangle allocation;
5631
5632   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
5633   g_return_if_fail (GTK_IS_WIDGET (widget));
5634
5635   for (list = tree_view->priv->children; list; list = list->next)
5636     {
5637       if (((GtkTreeViewChild *)list->data)->widget == widget)
5638         {
5639           child = list->data;
5640           break;
5641         }
5642     }
5643   if (child == NULL)
5644     return;
5645
5646   allocation.x = child->x = x;
5647   allocation.y = child->y = y;
5648   allocation.width = child->width = width;
5649   allocation.height = child->height = height;
5650
5651   if (GTK_WIDGET_REALIZED (widget))
5652     gtk_widget_size_allocate (widget, &allocation);
5653 }
5654
5655
5656 /* TreeModel Callbacks
5657  */
5658
5659 static void
5660 gtk_tree_view_row_changed (GtkTreeModel *model,
5661                            GtkTreePath  *path,
5662                            GtkTreeIter  *iter,
5663                            gpointer      data)
5664 {
5665   GtkTreeView *tree_view = (GtkTreeView *)data;
5666   GtkRBTree *tree;
5667   GtkRBNode *node;
5668   gboolean free_path = FALSE;
5669   gint vertical_separator;
5670   GList *list;
5671
5672   g_return_if_fail (path != NULL || iter != NULL);
5673
5674   if (!GTK_WIDGET_REALIZED (tree_view))
5675     /* We can just ignore ::changed signals if we aren't realized, as we don't care about sizes
5676      */
5677     return;
5678
5679   if (tree_view->priv->edited_column)
5680     gtk_tree_view_stop_editing (tree_view, TRUE);
5681
5682   gtk_widget_style_get (GTK_WIDGET (data), "vertical_separator", &vertical_separator, NULL);
5683
5684   if (path == NULL)
5685     {
5686       path = gtk_tree_model_get_path (model, iter);
5687       free_path = TRUE;
5688     }
5689   else if (iter == NULL)
5690     gtk_tree_model_get_iter (model, iter, path);
5691
5692   if (_gtk_tree_view_find_node (tree_view,
5693                                 path,
5694                                 &tree,
5695                                 &node))
5696     /* We aren't actually showing the node */
5697     goto done;
5698
5699   if (tree == NULL)
5700     goto done;
5701
5702   _gtk_rbtree_node_mark_invalid (tree, node);
5703   for (list = tree_view->priv->columns; list; list = list->next)
5704     {
5705       GtkTreeViewColumn *column;
5706
5707       column = list->data;
5708       if (! column->visible)
5709         continue;
5710
5711       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
5712         {
5713           _gtk_tree_view_column_cell_set_dirty (column, TRUE);
5714         }
5715     }
5716
5717  done:
5718   install_presize_handler (tree_view);
5719   if (free_path)
5720     gtk_tree_path_free (path);
5721 }
5722
5723 static void
5724 gtk_tree_view_row_inserted (GtkTreeModel *model,
5725                             GtkTreePath  *path,
5726                             GtkTreeIter  *iter,
5727                             gpointer      data)
5728 {
5729   GtkTreeView *tree_view = (GtkTreeView *) data;
5730   gint *indices;
5731   GtkRBTree *tmptree, *tree;
5732   GtkRBNode *tmpnode = NULL;
5733   gint depth;
5734   gint i = 0;
5735   gboolean free_path = FALSE;
5736
5737   g_return_if_fail (path != NULL || iter != NULL);
5738
5739   if (path == NULL)
5740     {
5741       path = gtk_tree_model_get_path (model, iter);
5742       free_path = TRUE;
5743     }
5744   else if (iter == NULL)
5745     gtk_tree_model_get_iter (model, iter, path);
5746
5747   if (tree_view->priv->tree == NULL)
5748     tree_view->priv->tree = _gtk_rbtree_new ();
5749
5750   tmptree = tree = tree_view->priv->tree;
5751
5752   /* Update all row-references */
5753   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
5754   depth = gtk_tree_path_get_depth (path);
5755   indices = gtk_tree_path_get_indices (path);
5756
5757   /* First, find the parent tree */
5758   while (i < depth - 1)
5759     {
5760       if (tmptree == NULL)
5761         {
5762           /* We aren't showing the node */
5763           goto done;
5764         }
5765
5766       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
5767       if (tmpnode == NULL)
5768         {
5769           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
5770                      "This possibly means that a GtkTreeModel inserted a child node\n" \
5771                      "before the parent was inserted.");
5772           goto done;
5773         }
5774       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
5775         {
5776           /* FIXME enforce correct behavior on model, probably */
5777           /* In theory, the model should have emitted has_child_toggled here.  We
5778            * try to catch it anyway, just to be safe, in case the model hasn't.
5779            */
5780           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
5781                                                            tree,
5782                                                            tmpnode);
5783           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
5784           gtk_tree_path_free (tmppath);
5785           goto done;
5786         }
5787
5788       tmptree = tmpnode->children;
5789       tree = tmptree;
5790       i++;
5791     }
5792
5793   if (tree == NULL)
5794     goto done;
5795
5796   /* ref the node */
5797   gtk_tree_model_ref_node (tree_view->priv->model, iter);
5798   if (indices[depth - 1] == 0)
5799     {
5800       tmpnode = _gtk_rbtree_find_count (tree, 1);
5801       _gtk_rbtree_insert_before (tree, tmpnode, 0, FALSE);
5802     }
5803   else
5804     {
5805       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
5806       _gtk_rbtree_insert_after (tree, tmpnode, 0, FALSE);
5807     }
5808
5809  done:
5810   install_presize_handler (tree_view);
5811   if (free_path)
5812     gtk_tree_path_free (path);
5813 }
5814
5815 static void
5816 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
5817                                      GtkTreePath  *path,
5818                                      GtkTreeIter  *iter,
5819                                      gpointer      data)
5820 {
5821   GtkTreeView *tree_view = (GtkTreeView *)data;
5822   GtkTreeIter real_iter;
5823   gboolean has_child;
5824   GtkRBTree *tree;
5825   GtkRBNode *node;
5826   gboolean free_path = FALSE;
5827
5828   g_return_if_fail (path != NULL || iter != NULL);
5829
5830   if (iter)
5831     real_iter = *iter;
5832
5833   if (path == NULL)
5834     {
5835       path = gtk_tree_model_get_path (model, iter);
5836       free_path = TRUE;
5837     }
5838   else if (iter == NULL)
5839     gtk_tree_model_get_iter (model, &real_iter, path);
5840
5841   if (_gtk_tree_view_find_node (tree_view,
5842                                 path,
5843                                 &tree,
5844                                 &node))
5845     /* We aren't actually showing the node */
5846     goto done;
5847
5848   if (tree == NULL)
5849     goto done;
5850
5851   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
5852   /* Sanity check.
5853    */
5854   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
5855     goto done;
5856
5857   if (has_child)
5858     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
5859   else
5860     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
5861
5862   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
5863     {
5864       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
5865       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
5866         {
5867           GList *list;
5868
5869           for (list = tree_view->priv->columns; list; list = list->next)
5870             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
5871               {
5872                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
5873                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
5874                 break;
5875               }
5876         }
5877       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5878     }
5879   else
5880     {
5881       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5882     }
5883
5884  done:
5885   if (free_path)
5886     gtk_tree_path_free (path);
5887 }
5888
5889 static void
5890 count_children_helper (GtkRBTree *tree,
5891                        GtkRBNode *node,
5892                        gpointer   data)
5893 {
5894   if (node->children)
5895     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
5896   (*((gint *)data))++;
5897 }
5898
5899 static void
5900 gtk_tree_view_row_deleted (GtkTreeModel *model,
5901                            GtkTreePath  *path,
5902                            gpointer      data)
5903 {
5904   GtkTreeView *tree_view = (GtkTreeView *)data;
5905   GtkRBTree *tree;
5906   GtkRBNode *node;
5907   GList *list;
5908   gint selection_changed;
5909
5910   g_return_if_fail (path != NULL);
5911
5912   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
5913
5914   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5915     return;
5916
5917   if (tree == NULL)
5918     return;
5919
5920   /* Change the selection */
5921   selection_changed = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
5922
5923   for (list = tree_view->priv->columns; list; list = list->next)
5924     if (((GtkTreeViewColumn *)list->data)->visible &&
5925         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
5926       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
5927
5928   /* Ensure we don't have a dangling pointer to a dead node */
5929   ensure_unprelighted (tree_view);
5930
5931   /* Cancel editting if we've started */
5932   gtk_tree_view_stop_editing (tree_view, TRUE);
5933
5934   /* If we have a node expanded/collapsed timeout, remove it */
5935   if (tree_view->priv->expand_collapse_timeout != 0)
5936     {
5937       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
5938       tree_view->priv->expand_collapse_timeout = 0;
5939
5940       /* Reset node */
5941       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
5942       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
5943       tree_view->priv->expanded_collapsed_node = NULL;
5944     }
5945
5946   if (tree_view->priv->destroy_count_func)
5947     {
5948       gint child_count = 0;
5949       if (node->children)
5950         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
5951       (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
5952     }
5953
5954   if (tree->root->count == 1)
5955     {
5956       if (tree_view->priv->tree == tree)
5957         tree_view->priv->tree = NULL;
5958
5959       _gtk_rbtree_remove (tree);
5960     }
5961   else
5962     {
5963       _gtk_rbtree_remove_node (tree, node);
5964     }
5965
5966   install_scroll_sync_handler (tree_view);
5967
5968   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
5969
5970   if (selection_changed)
5971     g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
5972 }
5973
5974
5975 static void
5976 gtk_tree_view_rows_reordered (GtkTreeModel *model,
5977                               GtkTreePath  *parent,
5978                               GtkTreeIter  *iter,
5979                               gint         *new_order,
5980                               gpointer      data)
5981 {
5982   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
5983   GtkRBTree *tree;
5984   GtkRBNode *node;
5985   gint len;
5986
5987   len = gtk_tree_model_iter_n_children (model, iter);
5988
5989   if (len < 2)
5990     return;
5991
5992   gtk_tree_row_reference_reordered (G_OBJECT (data),
5993                                     parent,
5994                                     iter,
5995                                     new_order);
5996
5997   if (_gtk_tree_view_find_node (tree_view,
5998                                 parent,
5999                                 &tree,
6000                                 &node))
6001     return;
6002
6003   /* We need to special case the parent path */
6004   if (tree == NULL)
6005     tree = tree_view->priv->tree;
6006   else
6007     tree = node->children;
6008
6009   if (tree == NULL)
6010     return;
6011
6012   /* we need to be unprelighted */
6013   ensure_unprelighted (tree_view);
6014   
6015   _gtk_rbtree_reorder (tree, new_order, len);
6016
6017   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6018
6019   gtk_tree_view_dy_to_top_row (tree_view);
6020 }
6021
6022
6023 /* Internal tree functions
6024  */
6025
6026
6027 static void
6028 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
6029                                      GtkRBTree         *tree,
6030                                      GtkTreeViewColumn *column,
6031                                      gint              *x1,
6032                                      gint              *x2)
6033 {
6034   GtkTreeViewColumn *tmp_column = NULL;
6035   gint total_width;
6036   GList *list;
6037
6038   if (x1)
6039     *x1 = 0;
6040
6041   if (x2)
6042     *x2 = 0;
6043
6044   total_width = 0;
6045   for (list = tree_view->priv->columns; list; list = list->next)
6046     {
6047       tmp_column = list->data;
6048
6049       if (tmp_column == column)
6050         break;
6051
6052       if (tmp_column->visible)
6053         total_width += tmp_column->width;
6054     }
6055
6056   if (tmp_column != column)
6057     {
6058       g_warning (G_STRLOC": passed-in column isn't in the tree");
6059       return;
6060     }
6061
6062   if (x1)
6063     *x1 = total_width;
6064
6065   if (x2)
6066     {
6067       if (column->visible)
6068         *x2 = total_width + column->width;
6069       else
6070         *x2 = total_width; /* width of 0 */
6071     }
6072 }
6073 static void
6074 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
6075                                 GtkRBTree   *tree,
6076                                 gint        *x1,
6077                                 gint        *x2)
6078 {
6079   gint x_offset = 0;
6080   GList *list;
6081   GtkTreeViewColumn *tmp_column = NULL;
6082   gint total_width;
6083   gboolean indent_expanders;
6084
6085   total_width = 0;
6086   for (list = tree_view->priv->columns; list; list = list->next)
6087     {
6088       tmp_column = list->data;
6089
6090       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
6091         {
6092           x_offset = total_width;
6093           break;
6094         }
6095
6096       if (tmp_column->visible)
6097         total_width += tmp_column->width;
6098     }
6099
6100   gtk_widget_style_get (GTK_WIDGET (tree_view),
6101                         "indent_expanders", &indent_expanders,
6102                         NULL);
6103
6104   if (indent_expanders)
6105     x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
6106
6107   if (x1)
6108     *x1 = x_offset;
6109
6110   if (tmp_column && tmp_column->visible)
6111     {
6112       /* +1 because x2 isn't included in the range. */
6113       if (x2)
6114         *x2 = x_offset + tree_view->priv->expander_size + 1;
6115     }
6116   else
6117     {
6118       /* return an empty range, the expander column is hidden */
6119       if (x2)
6120         *x2 = x_offset;
6121     }
6122 }
6123
6124 static void
6125 gtk_tree_view_build_tree (GtkTreeView *tree_view,
6126                           GtkRBTree   *tree,
6127                           GtkTreeIter *iter,
6128                           gint         depth,
6129                           gboolean     recurse)
6130 {
6131   GtkRBNode *temp = NULL;
6132
6133   do
6134     {
6135       gtk_tree_model_ref_node (tree_view->priv->model, iter);
6136       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
6137       if (recurse)
6138         {
6139           GtkTreeIter child;
6140
6141           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
6142             {
6143               temp->children = _gtk_rbtree_new ();
6144               temp->children->parent_tree = tree;
6145               temp->children->parent_node = temp;
6146               gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
6147             }
6148         }
6149       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
6150         {
6151           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
6152             temp->flags ^= GTK_RBNODE_IS_PARENT;
6153           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
6154         }
6155     }
6156   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
6157 }
6158
6159 /* If height is non-NULL, then we set it to be the new height.  if it's all
6160  * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
6161  */
6162 static gboolean
6163 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
6164                                    GtkTreeIter *iter,
6165                                    gint         depth,
6166                                    gint        *height,
6167                                    GtkRBNode   *node)
6168 {
6169   GtkTreeViewColumn *column;
6170   GList *list;
6171   gboolean retval = FALSE;
6172   gint tmpheight;
6173   gint horizontal_separator;
6174
6175   gtk_widget_style_get (GTK_WIDGET (tree_view),
6176                         "horizontal_separator", &horizontal_separator,
6177                         NULL);
6178
6179   if (height)
6180     *height = -1;
6181
6182   for (list = tree_view->priv->columns; list; list = list->next)
6183     {
6184       gint width;
6185       column = list->data;
6186       if (column->dirty == TRUE)
6187         continue;
6188       if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
6189         continue;
6190       if (!column->visible)
6191         continue;
6192
6193       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6194                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6195                                                node->children?TRUE:FALSE);
6196
6197       if (height)
6198         {
6199           gtk_tree_view_column_cell_get_size (column,
6200                                               NULL, NULL, NULL,
6201                                               &width, &tmpheight);
6202           *height = MAX (*height, tmpheight);
6203         }
6204       else
6205         {
6206           gtk_tree_view_column_cell_get_size (column,
6207                                               NULL, NULL, NULL,
6208                                               &width, NULL);
6209         }
6210
6211       if (gtk_tree_view_is_expander_column (tree_view, column) &&
6212           TREE_VIEW_DRAW_EXPANDERS (tree_view))
6213         {
6214           if (depth * tree_view->priv->expander_size + horizontal_separator + width > column->requested_width)
6215             {
6216               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
6217               retval = TRUE;
6218             }
6219         }
6220       else
6221         {
6222           if (horizontal_separator + width > column->requested_width)
6223             {
6224               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
6225               retval = TRUE;
6226             }
6227         }
6228     }
6229
6230   return retval;
6231 }
6232
6233 static void
6234 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
6235                               GtkRBTree   *tree,
6236                               GtkTreeIter *iter,
6237                               gint         depth)
6238 {
6239   GtkRBNode *temp = tree->root;
6240   GtkTreeViewColumn *column;
6241   GList *list;
6242   GtkTreeIter child;
6243   gboolean is_all_dirty;
6244
6245   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
6246
6247   while (temp->left != tree->nil)
6248     temp = temp->left;
6249
6250   do
6251     {
6252       TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
6253       is_all_dirty = TRUE;
6254       for (list = tree_view->priv->columns; list; list = list->next)
6255         {
6256           column = list->data;
6257           if (column->dirty == FALSE)
6258             {
6259               is_all_dirty = FALSE;
6260               break;
6261             }
6262         }
6263
6264       if (is_all_dirty)
6265         return;
6266
6267       gtk_tree_view_discover_dirty_iter (tree_view,
6268                                          iter,
6269                                          depth,
6270                                          NULL,
6271                                          temp);
6272       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
6273           temp->children != NULL)
6274         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
6275       temp = _gtk_rbtree_next (tree, temp);
6276     }
6277   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
6278 }
6279
6280
6281 /* Make sure the node is visible vertically */
6282 static void
6283 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
6284                                   GtkRBTree   *tree,
6285                                   GtkRBNode   *node)
6286 {
6287   GdkRectangle cell_rect;
6288   GdkRectangle vis_rect;
6289   gint dest_y;
6290
6291   /* We process updates because we want to clear old selected items when we scroll.
6292    * if this is removed, we get a "selection streak" at the bottom. */
6293   if (!GTK_WIDGET_REALIZED (tree_view))
6294     return;
6295
6296   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6297   cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, BACKGROUND_FIRST_PIXEL (tree_view, tree, node));
6298   cell_rect.height = BACKGROUND_HEIGHT (node);
6299   gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
6300
6301   dest_y = vis_rect.y;
6302
6303   if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
6304     dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
6305   if (cell_rect.y < vis_rect.y)
6306     dest_y = cell_rect.y;
6307
6308   gtk_tree_view_scroll_to_point (tree_view, -1, dest_y);
6309 }
6310
6311 static void
6312 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
6313                                     GtkTreeViewColumn *column)
6314 {
6315   if (column == NULL)
6316     return;
6317   if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
6318       (column->button->allocation.x + column->button->allocation.width))
6319     gtk_adjustment_set_value (tree_view->priv->hadjustment,
6320                               column->button->allocation.x + column->button->allocation.width -
6321                               tree_view->priv->hadjustment->page_size);
6322   else if (tree_view->priv->hadjustment->value > column->button->allocation.x)
6323     gtk_adjustment_set_value (tree_view->priv->hadjustment,
6324                               column->button->allocation.x);
6325 }
6326
6327 /* This function could be more efficient.  I'll optimize it if profiling seems
6328  * to imply that it is important */
6329 GtkTreePath *
6330 _gtk_tree_view_find_path (GtkTreeView *tree_view,
6331                           GtkRBTree   *tree,
6332                           GtkRBNode   *node)
6333 {
6334   GtkTreePath *path;
6335   GtkRBTree *tmp_tree;
6336   GtkRBNode *tmp_node, *last;
6337   gint count;
6338
6339   path = gtk_tree_path_new ();
6340
6341   g_return_val_if_fail (node != NULL, path);
6342   g_return_val_if_fail (node != tree->nil, path);
6343
6344   count = 1 + node->left->count;
6345
6346   last = node;
6347   tmp_node = node->parent;
6348   tmp_tree = tree;
6349   while (tmp_tree)
6350     {
6351       while (tmp_node != tmp_tree->nil)
6352         {
6353           if (tmp_node->right == last)
6354             count += 1 + tmp_node->left->count;
6355           last = tmp_node;
6356           tmp_node = tmp_node->parent;
6357         }
6358       gtk_tree_path_prepend_index (path, count - 1);
6359       last = tmp_tree->parent_node;
6360       tmp_tree = tmp_tree->parent_tree;
6361       if (last)
6362         {
6363           count = 1 + last->left->count;
6364           tmp_node = last->parent;
6365         }
6366     }
6367   return path;
6368 }
6369
6370 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
6371  * invalid (ie. points to a node that's not in the tree), *tree and *node are
6372  * both set to NULL.
6373  */
6374 gboolean
6375 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
6376                           GtkTreePath  *path,
6377                           GtkRBTree   **tree,
6378                           GtkRBNode   **node)
6379 {
6380   GtkRBNode *tmpnode = NULL;
6381   GtkRBTree *tmptree = tree_view->priv->tree;
6382   gint *indices = gtk_tree_path_get_indices (path);
6383   gint depth = gtk_tree_path_get_depth (path);
6384   gint i = 0;
6385
6386   *node = NULL;
6387   *tree = NULL;
6388
6389   if (depth == 0 || tmptree == NULL)
6390     return FALSE;
6391   do
6392     {
6393       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
6394       ++i;
6395       if (tmpnode == NULL)
6396         {
6397           *tree = NULL;
6398           *node = NULL;
6399           return FALSE;
6400         }
6401       if (i >= depth)
6402         {
6403           *tree = tmptree;
6404           *node = tmpnode;
6405           return FALSE;
6406         }
6407       *tree = tmptree;
6408       *node = tmpnode;
6409       tmptree = tmpnode->children;
6410       if (tmptree == NULL)
6411         return TRUE;
6412     }
6413   while (1);
6414 }
6415
6416 static gboolean
6417 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
6418                                   GtkTreeViewColumn *column)
6419 {
6420   GList *list;
6421
6422   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
6423     return FALSE;
6424
6425   if (tree_view->priv->expander_column != NULL)
6426     {
6427       if (tree_view->priv->expander_column == column)
6428         return TRUE;
6429       return FALSE;
6430     }
6431   else
6432     {
6433       for (list = tree_view->priv->columns; list; list = list->next)
6434         if (((GtkTreeViewColumn *)list->data)->visible)
6435           break;
6436       if (list && list->data == column)
6437         return TRUE;
6438     }
6439   return FALSE;
6440 }
6441
6442 static void
6443 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
6444                                 guint           keyval,
6445                                 guint           modmask,
6446                                 GtkMovementStep step,
6447                                 gint            count)
6448 {
6449   
6450   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
6451                                 "move_cursor", 2,
6452                                 GTK_TYPE_ENUM, step,
6453                                 GTK_TYPE_INT, count);
6454
6455   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
6456                                 "move_cursor", 2,
6457                                 GTK_TYPE_ENUM, step,
6458                                 GTK_TYPE_INT, count);
6459
6460   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
6461    return;
6462
6463   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
6464                                 "move_cursor", 2,
6465                                 GTK_TYPE_ENUM, step,
6466                                 GTK_TYPE_INT, count);
6467
6468   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
6469                                 "move_cursor", 2,
6470                                 GTK_TYPE_ENUM, step,
6471                                 GTK_TYPE_INT, count);
6472 }
6473
6474 static gint
6475 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
6476                                  GtkTreeIter  *iter,
6477                                  GtkRBTree    *tree,
6478                                  GtkRBNode    *node)
6479 {
6480   gint retval = FALSE;
6481   do
6482     {
6483       g_return_val_if_fail (node != NULL, FALSE);
6484
6485       if (node->children)
6486         {
6487           GtkTreeIter child;
6488           GtkRBTree *new_tree;
6489           GtkRBNode *new_node;
6490
6491           new_tree = node->children;
6492           new_node = new_tree->root;
6493
6494           while (new_node && new_node->left != new_tree->nil)
6495             new_node = new_node->left;
6496
6497           g_return_val_if_fail (gtk_tree_model_iter_children (model, &child, iter), FALSE);
6498           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
6499         }
6500
6501       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
6502         retval = TRUE;
6503       gtk_tree_model_unref_node (model, iter);
6504       node = _gtk_rbtree_next (tree, node);
6505     }
6506   while (gtk_tree_model_iter_next (model, iter));
6507
6508   return retval;
6509 }
6510
6511 static gint
6512 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
6513                                               GtkRBTree   *tree)
6514 {
6515   GtkTreeIter iter;
6516   GtkTreePath *path;
6517   GtkRBNode *node;
6518   gint retval;
6519
6520   if (!tree)
6521     return FALSE;
6522
6523   node = tree->root;
6524   while (node && node->left != tree->nil)
6525     node = node->left;
6526
6527   g_return_val_if_fail (node != NULL, FALSE);
6528   path = _gtk_tree_view_find_path (tree_view, tree, node);
6529   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
6530                            &iter, path);
6531   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
6532   gtk_tree_path_free (path);
6533
6534   return retval;
6535 }
6536
6537 static void
6538 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
6539                                     GtkTreeViewColumn *column)
6540 {
6541   GtkTreeViewColumn *left_column;
6542   GtkTreeViewColumn *cur_column = NULL;
6543   GtkTreeViewColumnReorder *reorder;
6544
6545   GList *tmp_list;
6546   gint left;
6547
6548   /* We want to precalculate the motion list such that we know what column slots
6549    * are available.
6550    */
6551   left_column = NULL;
6552
6553   /* First, identify all possible drop spots */
6554   tmp_list = tree_view->priv->columns;
6555
6556   while (tmp_list)
6557     {
6558       g_assert (tmp_list);
6559
6560       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
6561       tmp_list = tmp_list->next;
6562
6563       if (cur_column->visible == FALSE)
6564         continue;
6565
6566       /* If it's not the column moving and func tells us to skip over the column, we continue. */
6567       if (left_column != column && cur_column != column &&
6568           tree_view->priv->column_drop_func &&
6569           ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
6570         {
6571           left_column = cur_column;
6572           continue;
6573         }
6574       reorder = g_new (GtkTreeViewColumnReorder, 1);
6575       reorder->left_column = left_column;
6576       left_column = reorder->right_column = cur_column;
6577
6578       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
6579     }
6580
6581   /* Add the last one */
6582   if (tree_view->priv->column_drop_func == NULL ||
6583       ((left_column != column) &&
6584        (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data)))
6585     {
6586       reorder = g_new (GtkTreeViewColumnReorder, 1);
6587       reorder->left_column = left_column;
6588       reorder->right_column = NULL;
6589       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
6590     }
6591
6592   /* We quickly check to see if it even makes sense to reorder columns. */
6593   /* If there is nothing that can be moved, then we return */
6594
6595   if (tree_view->priv->column_drag_info == NULL)
6596     return;
6597
6598   /* We know there are always 2 slots possbile, as you can always return column. */
6599   /* If that's all there is, return */
6600   if (tree_view->priv->column_drag_info->next->next == NULL &&
6601       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
6602       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
6603     {
6604       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
6605         g_free (tmp_list->data);
6606       g_list_free (tree_view->priv->column_drag_info);
6607       tree_view->priv->column_drag_info = NULL;
6608       return;
6609     }
6610   /* We fill in the ranges for the columns, now that we've isolated them */
6611   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
6612
6613   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
6614     {
6615       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
6616
6617       reorder->left_align = left;
6618       if (tmp_list->next != NULL)
6619         {
6620           g_assert (tmp_list->next->data);
6621           left = reorder->right_align = (reorder->right_column->button->allocation.x +
6622                                          reorder->right_column->button->allocation.width +
6623                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
6624         }
6625       else
6626         {
6627           gint width;
6628
6629           gdk_window_get_size (tree_view->priv->header_window, &width, NULL);
6630           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
6631         }
6632     }
6633 }
6634
6635 void
6636 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
6637                                   GtkTreeViewColumn *column)
6638 {
6639   GdkEvent send_event;
6640   GtkAllocation allocation;
6641   gint x, y, width, height;
6642
6643   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
6644
6645   gtk_tree_view_set_column_drag_info (tree_view, column);
6646
6647   if (tree_view->priv->column_drag_info == NULL)
6648     return;
6649
6650   if (tree_view->priv->drag_window == NULL)
6651     {
6652       GdkWindowAttr attributes;
6653       guint attributes_mask;
6654
6655       attributes.window_type = GDK_WINDOW_CHILD;
6656       attributes.wclass = GDK_INPUT_OUTPUT;
6657       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
6658       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
6659       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
6660       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
6661
6662       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
6663                                                      &attributes,
6664                                                      attributes_mask);
6665       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
6666     }
6667
6668   gdk_pointer_ungrab (GDK_CURRENT_TIME);
6669   gdk_keyboard_ungrab (GDK_CURRENT_TIME);
6670
6671   gtk_grab_remove (column->button);
6672
6673   send_event.crossing.type = GDK_LEAVE_NOTIFY;
6674   send_event.crossing.send_event = TRUE;
6675   send_event.crossing.window = column->button->window;
6676   send_event.crossing.subwindow = NULL;
6677   send_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
6678   send_event.crossing.time = GDK_CURRENT_TIME;
6679
6680   gtk_propagate_event (column->button, &send_event);
6681
6682   send_event.button.type = GDK_BUTTON_RELEASE;
6683   send_event.button.window = GDK_ROOT_PARENT ();
6684   send_event.button.send_event = TRUE;
6685   send_event.button.time = GDK_CURRENT_TIME;
6686   send_event.button.x = -1;
6687   send_event.button.y = -1;
6688   send_event.button.axes = NULL;
6689   send_event.button.state = 0;
6690   send_event.button.button = 1;
6691   send_event.button.device = gdk_device_get_core_pointer ();
6692   send_event.button.x_root = 0;
6693   send_event.button.y_root = 0;
6694
6695   gtk_propagate_event (column->button, &send_event);
6696
6697   gdk_window_move_resize (tree_view->priv->drag_window,
6698                           column->button->allocation.x,
6699                           0,
6700                           column->button->allocation.width,
6701                           column->button->allocation.height);
6702
6703   /* Kids, don't try this at home */
6704   g_object_ref (column->button);
6705   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
6706   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
6707   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
6708   g_object_unref (column->button);
6709
6710   tree_view->priv->drag_column_x = column->button->allocation.x;
6711   allocation = column->button->allocation;
6712   allocation.x = 0;
6713   gtk_widget_size_allocate (column->button, &allocation);
6714   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
6715
6716   tree_view->priv->drag_column = column;
6717   gdk_window_show (tree_view->priv->drag_window);
6718
6719   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
6720   gdk_window_get_size (tree_view->priv->header_window, &width, &height);
6721
6722   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6723   while (gtk_events_pending ())
6724     gtk_main_iteration ();
6725
6726   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
6727   gdk_pointer_grab (tree_view->priv->drag_window,
6728                     FALSE,
6729                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
6730                     NULL, NULL, GDK_CURRENT_TIME);
6731   gdk_keyboard_grab (tree_view->priv->drag_window,
6732                      FALSE,
6733                      GDK_CURRENT_TIME);
6734
6735 }
6736
6737 static void
6738 gtk_tree_view_queue_draw_arrow (GtkTreeView      *tree_view,
6739                                 GtkRBTree        *tree,
6740                                 GtkRBNode        *node,
6741                                 GdkRectangle     *clip_rect)
6742 {
6743   GdkRectangle rect;
6744
6745   if (!GTK_WIDGET_REALIZED (tree_view))
6746     return;
6747
6748   rect.x = 0;
6749   rect.width = MAX (tree_view->priv->expander_size, GTK_WIDGET (tree_view)->allocation.width);
6750
6751   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
6752   rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
6753
6754   if (clip_rect)
6755     {
6756       GdkRectangle new_rect;
6757
6758       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
6759
6760       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
6761     }
6762   else
6763     {
6764       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
6765     }
6766 }
6767
6768 void
6769 _gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
6770                                 GtkRBTree    *tree,
6771                                 GtkRBNode    *node,
6772                                 GdkRectangle *clip_rect)
6773 {
6774   GdkRectangle rect;
6775
6776   if (!GTK_WIDGET_REALIZED (tree_view))
6777     return;
6778
6779   rect.x = 0;
6780   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
6781
6782   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
6783   rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
6784
6785   if (clip_rect)
6786     {
6787       GdkRectangle new_rect;
6788
6789       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
6790
6791       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
6792     }
6793   else
6794     {
6795       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
6796     }
6797 }
6798
6799 static void
6800 gtk_tree_view_queue_draw_path (GtkTreeView      *tree_view,
6801                                GtkTreePath      *path,
6802                                GdkRectangle     *clip_rect)
6803 {
6804   GtkRBTree *tree = NULL;
6805   GtkRBNode *node = NULL;
6806
6807   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6808
6809   if (tree)
6810     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
6811 }
6812
6813 /* x and y are the mouse position
6814  */
6815 static void
6816 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
6817                           GtkRBTree   *tree,
6818                           GtkRBNode   *node,
6819                           gint         x,
6820                           gint         y)
6821 {
6822   GdkRectangle area;
6823   GtkStateType state;
6824   GtkWidget *widget;
6825   gint x_offset = 0;
6826   gint vertical_separator;
6827   gint expander_size;
6828   GtkExpanderStyle expander_style;
6829
6830   gtk_widget_style_get (GTK_WIDGET (tree_view),
6831                         "vertical_separator", &vertical_separator,
6832                         NULL);
6833   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
6834
6835   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
6836     return;
6837
6838   widget = GTK_WIDGET (tree_view);
6839
6840   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, NULL);
6841
6842   area.x = x_offset;
6843   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
6844   area.width = expander_size + 2;
6845   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
6846
6847   if (node == tree_view->priv->button_pressed_node)
6848     {
6849       if (x >= area.x && x <= (area.x + area.width) &&
6850           y >= area.y && y <= (area.y + area.height))
6851         state = GTK_STATE_ACTIVE;
6852       else
6853         state = GTK_STATE_NORMAL;
6854     }
6855   else
6856     {
6857       if (node == tree_view->priv->prelight_node &&
6858           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
6859         state = GTK_STATE_PRELIGHT;
6860       else
6861         state = GTK_STATE_NORMAL;
6862     }
6863
6864   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
6865     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
6866   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
6867     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
6868   else if (node->children != NULL)
6869     expander_style = GTK_EXPANDER_EXPANDED;
6870   else
6871     expander_style = GTK_EXPANDER_COLLAPSED;
6872
6873   gtk_paint_expander (widget->style,
6874                       tree_view->priv->bin_window,
6875                       state,
6876                       &area,
6877                       widget,
6878                       "treeview",
6879                       area.x + area.width / 2,
6880                       area.y + area.height / 2,
6881                       expander_style);
6882 }
6883
6884 static void
6885 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
6886
6887 {
6888   GtkTreePath *cursor_path;
6889
6890   if ((tree_view->priv->tree == NULL) ||
6891       (! GTK_WIDGET_REALIZED (tree_view)))
6892     return;
6893
6894   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
6895
6896   cursor_path = NULL;
6897   if (tree_view->priv->cursor)
6898     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6899
6900   if (cursor_path == NULL)
6901     {
6902       cursor_path = gtk_tree_path_new_first ();
6903       gtk_tree_row_reference_free (tree_view->priv->cursor);
6904       tree_view->priv->cursor = NULL;
6905
6906       if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
6907         gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
6908       else
6909         gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
6910     }
6911   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
6912   gtk_tree_path_free (cursor_path);
6913
6914   if (tree_view->priv->focus_column == NULL)
6915     {
6916       GList *list;
6917       for (list = tree_view->priv->columns; list; list = list->next)
6918         {
6919           if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
6920             {
6921               tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
6922               break;
6923             }
6924         }
6925     }
6926 }
6927
6928 static void
6929 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
6930                                    gint         count)
6931 {
6932   GtkRBTree *cursor_tree = NULL;
6933   GtkRBNode *cursor_node = NULL;
6934   GtkRBTree *new_cursor_tree = NULL;
6935   GtkRBNode *new_cursor_node = NULL;
6936   GtkTreePath *cursor_path = NULL;
6937
6938   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
6939     return;
6940
6941   cursor_path = NULL;
6942   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
6943     /* FIXME: we lost the cursor; should we get the first? */
6944     return;
6945
6946   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6947   _gtk_tree_view_find_node (tree_view, cursor_path,
6948                             &cursor_tree, &cursor_node);
6949   gtk_tree_path_free (cursor_path);
6950
6951   if (cursor_tree == NULL)
6952     /* FIXME: we lost the cursor; should we get the first? */
6953     return;
6954   if (count == -1)
6955     _gtk_rbtree_prev_full (cursor_tree, cursor_node,
6956                            &new_cursor_tree, &new_cursor_node);
6957   else
6958     _gtk_rbtree_next_full (cursor_tree, cursor_node,
6959                            &new_cursor_tree, &new_cursor_node);
6960
6961   if (new_cursor_node)
6962     {
6963       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
6964       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
6965       gtk_tree_path_free (cursor_path);
6966     }
6967   else
6968     {
6969       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
6970     }
6971
6972   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6973 }
6974
6975 static void
6976 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
6977                                         gint         count)
6978 {
6979   GtkRBTree *cursor_tree = NULL;
6980   GtkRBNode *cursor_node = NULL;
6981   GtkTreePath *cursor_path = NULL;
6982   gint y;
6983   gint vertical_separator;
6984
6985   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
6986     return;
6987
6988   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
6989     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
6990   else
6991     /* This is sorta weird.  Focus in should give us a cursor */
6992     return;
6993
6994   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
6995   _gtk_tree_view_find_node (tree_view, cursor_path,
6996                             &cursor_tree, &cursor_node);
6997
6998   gtk_tree_path_free (cursor_path);
6999
7000   if (cursor_tree == NULL)
7001     /* FIXME: we lost the cursor.  Should we try to get one? */
7002     return;
7003   g_return_if_fail (cursor_node != NULL);
7004
7005   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
7006   y += count * tree_view->priv->vadjustment->page_size;
7007   if (count > 0)
7008     y -= MAX (GTK_RBNODE_GET_HEIGHT (cursor_node),
7009               tree_view->priv->expander_size);
7010   else if (count < 0)
7011     y += MAX (GTK_RBNODE_GET_HEIGHT (cursor_node),
7012               tree_view->priv->expander_size);
7013   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
7014
7015   if (y > tree_view->priv->height)
7016     y = tree_view->priv->height - 1;
7017
7018   _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
7019   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
7020   g_return_if_fail (cursor_path != NULL);
7021   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
7022   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
7023   gtk_tree_path_free (cursor_path);
7024 }
7025
7026 static void
7027 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
7028                                       gint         count)
7029 {
7030   GtkRBTree *cursor_tree = NULL;
7031   GtkRBNode *cursor_node = NULL;
7032   GtkTreePath *cursor_path = NULL;
7033   GtkTreeViewColumn *column;
7034   GtkTreeIter iter;
7035   GList *list;
7036   gboolean found_column = FALSE;
7037
7038   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
7039     return;
7040
7041   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
7042     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7043   else
7044     return;
7045
7046   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
7047   if (cursor_tree == NULL)
7048     return;
7049   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
7050     {
7051       gtk_tree_path_free (cursor_path);
7052       return;
7053     }
7054   gtk_tree_path_free (cursor_path);
7055
7056   list = tree_view->priv->columns;
7057   if (tree_view->priv->focus_column)
7058     {
7059       for (list = tree_view->priv->columns; list; list = list->next)
7060         {
7061           if (list->data == tree_view->priv->focus_column)
7062             break;
7063         }
7064     }
7065
7066   while (list)
7067     {
7068       column = list->data;
7069       if (column->visible == FALSE)
7070         goto loop_end;
7071
7072       gtk_tree_view_column_cell_set_cell_data (column,
7073                                                tree_view->priv->model,
7074                                                &iter,
7075                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
7076                                                cursor_node->children?TRUE:FALSE);
7077       if (_gtk_tree_view_column_cell_focus (column, count))
7078         {
7079           tree_view->priv->focus_column = column;
7080           found_column = TRUE;
7081           break;
7082         }
7083     loop_end:
7084       if (count == 1)
7085         list = list->next;
7086       else
7087         list = list->prev;
7088     }
7089
7090   if (found_column)
7091     {
7092       _gtk_tree_view_queue_draw_node (tree_view,
7093                                      cursor_tree,
7094                                      cursor_node,
7095                                      NULL);
7096       g_signal_emit (G_OBJECT (tree_view), tree_view_signals[CURSOR_CHANGED], 0);
7097     }
7098   gtk_tree_view_clamp_column_visible (tree_view, tree_view->priv->focus_column);
7099 }
7100
7101 static void
7102 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
7103                                      gint         count)
7104 {
7105   GtkRBTree *cursor_tree;
7106   GtkRBNode *cursor_node;
7107   GtkTreePath *path;
7108
7109   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
7110     return;
7111
7112   g_return_if_fail (tree_view->priv->tree != NULL);
7113
7114   if (count == -1)
7115     {
7116       cursor_tree = tree_view->priv->tree;
7117       cursor_node = cursor_tree->root;
7118       while (cursor_node && cursor_node->left != cursor_tree->nil)
7119         cursor_node = cursor_node->left;
7120     }
7121   else
7122     {
7123       cursor_tree = tree_view->priv->tree;
7124       cursor_node = cursor_tree->root;
7125       do
7126         {
7127           while (cursor_node && cursor_node->right != cursor_tree->nil)
7128             cursor_node = cursor_node->right;
7129           if (cursor_node->children == NULL)
7130             break;
7131
7132           cursor_tree = cursor_node->children;
7133           cursor_node = cursor_tree->root;
7134         }
7135       while (1);
7136     }
7137
7138   path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
7139   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
7140   gtk_tree_path_free (path);
7141 }
7142
7143 static void
7144 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
7145 {
7146   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
7147     return;
7148
7149   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
7150     return;
7151   gtk_tree_selection_select_all (tree_view->priv->selection);
7152 }
7153
7154 static void
7155 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
7156 {
7157   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
7158     return;
7159
7160   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
7161     return;
7162   gtk_tree_selection_unselect_all (tree_view->priv->selection);
7163 }
7164
7165 static void
7166 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
7167                                       gboolean     start_editing)
7168 {
7169   GtkRBTree *cursor_tree = NULL;
7170   GtkRBNode *cursor_node = NULL;
7171   GtkTreePath *cursor_path = NULL;
7172   GdkModifierType state = 0;
7173   cursor_path = NULL;
7174
7175   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
7176     return;
7177
7178   if (tree_view->priv->cursor)
7179     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7180
7181   if (cursor_path == NULL)
7182     return;
7183
7184   _gtk_tree_view_find_node (tree_view, cursor_path,
7185                             &cursor_tree, &cursor_node);
7186
7187   if (cursor_tree == NULL)
7188     {
7189       gtk_tree_path_free (cursor_path);
7190       return;
7191     }
7192
7193   gtk_get_current_event_state (&state);
7194
7195   if (! (state & GDK_SHIFT_MASK) &&
7196       start_editing &&
7197       tree_view->priv->focus_column)
7198     {
7199       if (gtk_tree_view_start_editing (tree_view, cursor_path))
7200         {
7201           gtk_tree_path_free (cursor_path);
7202           return;
7203         }
7204     }
7205   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
7206                                             cursor_node,
7207                                             cursor_tree,
7208                                             cursor_path,
7209                                             state,
7210                                             FALSE);
7211
7212   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
7213
7214   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
7215   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
7216
7217   if (! (state & GDK_SHIFT_MASK))
7218     gtk_tree_view_row_activated (tree_view, cursor_path, tree_view->priv->focus_column);
7219     
7220   gtk_tree_path_free (cursor_path);
7221 }
7222
7223 static void
7224 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
7225 {
7226   GtkRBTree *cursor_tree = NULL;
7227   GtkRBNode *cursor_node = NULL;
7228   GtkTreePath *cursor_path = NULL;
7229
7230   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
7231     return;
7232
7233   cursor_path = NULL;
7234   if (tree_view->priv->cursor)
7235     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7236
7237   if (cursor_path == NULL)
7238     return;
7239
7240   _gtk_tree_view_find_node (tree_view, cursor_path,
7241                             &cursor_tree, &cursor_node);
7242   if (cursor_tree == NULL)
7243     {
7244       gtk_tree_path_free (cursor_path);
7245       return;
7246     }
7247
7248   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
7249                                             cursor_node,
7250                                             cursor_tree,
7251                                             cursor_path,
7252                                             GDK_CONTROL_MASK,
7253                                             FALSE);
7254
7255   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
7256
7257   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
7258   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
7259   gtk_tree_path_free (cursor_path);
7260 }
7261
7262
7263
7264 static void
7265 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
7266                                                gboolean     logical,
7267                                                gboolean     expand,
7268                                                gboolean     open_all)
7269 {
7270   GtkTreePath *cursor_path = NULL;
7271   GtkRBTree *tree;
7272   GtkRBNode *node;
7273
7274   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
7275     return;
7276
7277   cursor_path = NULL;
7278   if (tree_view->priv->cursor)
7279     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7280
7281   if (cursor_path == NULL)
7282     return;
7283
7284   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
7285     return;
7286   
7287   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
7288   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
7289
7290   if (expand)
7291     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
7292   else
7293     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
7294
7295   gtk_tree_path_free (cursor_path);
7296 }
7297
7298 static void
7299 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
7300 {
7301   GtkRBTree *cursor_tree = NULL;
7302   GtkRBNode *cursor_node = NULL;
7303   GtkTreePath *cursor_path = NULL;
7304
7305   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
7306     return;
7307
7308   cursor_path = NULL;
7309   if (tree_view->priv->cursor)
7310     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
7311
7312   if (cursor_path == NULL)
7313     return;
7314
7315   _gtk_tree_view_find_node (tree_view, cursor_path,
7316                             &cursor_tree, &cursor_node);
7317   if (cursor_tree == NULL)
7318     {
7319       gtk_tree_path_free (cursor_path);
7320       return;
7321     }
7322
7323   if (cursor_tree->parent_node)
7324     {
7325       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
7326       cursor_node = cursor_tree->parent_node;
7327       cursor_tree = cursor_tree->parent_tree;
7328
7329       gtk_tree_path_up (cursor_path);
7330       gtk_tree_row_reference_free (tree_view->priv->cursor);
7331       tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
7332       _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
7333                                                 cursor_node,
7334                                                 cursor_tree,
7335                                                 cursor_path,
7336                                                 0,
7337                                                 FALSE);
7338     }
7339
7340   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
7341
7342   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
7343   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
7344   gtk_tree_path_free (cursor_path);
7345 }
7346
7347 static void
7348 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view)
7349 {
7350   GtkWidget *window;
7351   GtkWidget *entry;
7352   GtkWidget *search_dialog;
7353   GdkEventFocus focus_event;
7354
7355   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
7356     return;
7357
7358   if (tree_view->priv->enable_search == FALSE ||
7359       tree_view->priv->search_column < 0)
7360     return;
7361
7362   search_dialog = g_object_get_data (G_OBJECT (tree_view),
7363                                      GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
7364   if (search_dialog)
7365     return;
7366
7367   /* set up window */
7368   window = gtk_window_new (GTK_WINDOW_POPUP);
7369   gtk_window_set_title (GTK_WINDOW (window), "search dialog");
7370   gtk_container_set_border_width (GTK_CONTAINER (window), 3);
7371   gtk_window_set_modal (GTK_WINDOW (window), TRUE);
7372   g_signal_connect (G_OBJECT (window), "delete_event",
7373                     G_CALLBACK (gtk_tree_view_search_delete_event),
7374                     tree_view);
7375   g_signal_connect (G_OBJECT (window), "key_press_event",
7376                     G_CALLBACK (gtk_tree_view_search_key_press_event),
7377                     tree_view);
7378   g_signal_connect (G_OBJECT (window), "button_press_event",
7379                     G_CALLBACK (gtk_tree_view_search_button_press_event),
7380                     tree_view);
7381
7382   /* add entry */
7383   entry = gtk_entry_new ();
7384   gtk_widget_show (entry);
7385   g_signal_connect (G_OBJECT (entry), "changed",
7386                     G_CALLBACK (gtk_tree_view_search_init), tree_view);
7387   g_signal_connect (G_OBJECT (entry), "populate_popup",
7388                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
7389                     tree_view);
7390   gtk_container_add (GTK_CONTAINER (window), entry);
7391
7392   /* done, show it */
7393   tree_view->priv->search_dialog_position_func (tree_view, window);
7394   gtk_widget_show_all (window);
7395   gtk_widget_grab_focus (entry);
7396
7397   /* send focus-in event */
7398   focus_event.type = GDK_FOCUS_CHANGE;
7399   focus_event.in = TRUE;
7400   gtk_widget_event (entry, (GdkEvent *) &focus_event);
7401
7402   /* position window */
7403
7404   /* yes, we point to the entry's private text thing here, a bit evil */
7405   g_object_set_data (G_OBJECT (window), "gtk-tree-view-text",
7406                      (gchar *) gtk_entry_get_text (GTK_ENTRY (entry)));
7407   g_object_set_data (G_OBJECT (tree_view),
7408                      GTK_TREE_VIEW_SEARCH_DIALOG_KEY, window);
7409
7410   /* search first matching iter */
7411   gtk_tree_view_search_init (entry, tree_view);
7412 }
7413
7414 /* this function returns the new width of the column being resized given
7415  * the column and x position of the cursor; the x cursor position is passed
7416  * in as a pointer and automagicly corrected if it's beyond min/max limits
7417  */
7418 static gint
7419 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
7420                                 gint       i,
7421                                 gint      *x)
7422 {
7423   GtkTreeViewColumn *column;
7424   gint width;
7425
7426   /* first translate the x position from widget->window
7427    * to clist->clist_window
7428    */
7429
7430   column = g_list_nth (tree_view->priv->columns, i)->data;
7431   width = *x - column->button->allocation.x;
7432
7433   /* Clamp down the value */
7434   if (column->min_width == -1)
7435     width = MAX (column->button->requisition.width,
7436                  width);
7437   else
7438     width = MAX (column->min_width,
7439                  width);
7440   if (column->max_width != -1)
7441     width = MIN (width, column->max_width != -1);
7442   *x = column->button->allocation.x + width;
7443
7444   return width;
7445 }
7446
7447
7448 /* Callbacks */
7449 static void
7450 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
7451                                   GtkTreeView   *tree_view)
7452 {
7453   if (GTK_WIDGET_REALIZED (tree_view))
7454     {
7455       gint dy;
7456         
7457       gdk_window_move (tree_view->priv->bin_window,
7458                        - tree_view->priv->hadjustment->value,
7459                        TREE_VIEW_HEADER_HEIGHT (tree_view));
7460       gdk_window_move (tree_view->priv->header_window,
7461                        - tree_view->priv->hadjustment->value,
7462                        0);
7463       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
7464       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
7465
7466       /* update our dy and top_row */
7467       tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
7468       gtk_tree_view_dy_to_top_row (tree_view);
7469       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
7470       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
7471     }
7472 }
7473
7474 \f
7475
7476 /* Public methods
7477  */
7478
7479 /**
7480  * gtk_tree_view_new:
7481  *
7482  * Creates a new #GtkTreeView widget.
7483  *
7484  * Return value: A newly created #GtkTreeView widget.
7485  **/
7486 GtkWidget *
7487 gtk_tree_view_new (void)
7488 {
7489   GtkTreeView *tree_view;
7490
7491   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
7492
7493   return GTK_WIDGET (tree_view);
7494 }
7495
7496 /**
7497  * gtk_tree_view_new_with_model:
7498  * @model: the model.
7499  *
7500  * Creates a new #GtkTreeView widget with the model initialized to @model.
7501  *
7502  * Return value: A newly created #GtkTreeView widget.
7503  **/
7504 GtkWidget *
7505 gtk_tree_view_new_with_model (GtkTreeModel *model)
7506 {
7507   GtkTreeView *tree_view;
7508
7509   tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
7510   gtk_tree_view_set_model (tree_view, model);
7511
7512   return GTK_WIDGET (tree_view);
7513 }
7514
7515 /* Public Accessors
7516  */
7517
7518 /**
7519  * gtk_tree_view_get_model:
7520  * @tree_view: a #GtkTreeView
7521  *
7522  * Returns the model the the #GtkTreeView is based on.  Returns %NULL if the
7523  * model is unset.
7524  *
7525  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
7526  **/
7527 GtkTreeModel *
7528 gtk_tree_view_get_model (GtkTreeView *tree_view)
7529 {
7530   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7531
7532   return tree_view->priv->model;
7533 }
7534
7535 /**
7536  * gtk_tree_view_set_model:
7537  * @tree_view: A #GtkTreeNode.
7538  * @model: The model.
7539  *
7540  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
7541  * set, it will remove it before setting the new model.  If @model is %NULL, then
7542  * it will unset the old model.
7543  **/
7544 void
7545 gtk_tree_view_set_model (GtkTreeView  *tree_view,
7546                          GtkTreeModel *model)
7547 {
7548   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7549
7550   if (model == tree_view->priv->model)
7551     return;
7552
7553   if (tree_view->priv->model)
7554     {
7555       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
7556
7557       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7558                                             (gpointer) gtk_tree_view_row_changed, tree_view);
7559       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7560                                             (gpointer) gtk_tree_view_row_inserted, tree_view);
7561       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7562                                             (gpointer) gtk_tree_view_row_has_child_toggled, tree_view);
7563       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7564                                             (gpointer) gtk_tree_view_row_deleted, tree_view);
7565       g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
7566                                             (gpointer) gtk_tree_view_rows_reordered, tree_view);
7567       if (tree_view->priv->tree)
7568         {
7569           _gtk_rbtree_free (tree_view->priv->tree);
7570           tree_view->priv->tree = NULL;
7571         }
7572
7573       tree_view->priv->prelight_node = NULL;
7574       tree_view->priv->prelight_tree = NULL;
7575       tree_view->priv->button_pressed_node = NULL;
7576       tree_view->priv->button_pressed_tree = NULL;
7577
7578       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
7579       tree_view->priv->drag_dest_row = NULL;
7580       gtk_tree_row_reference_free (tree_view->priv->cursor);
7581       tree_view->priv->cursor = NULL;
7582       gtk_tree_row_reference_free (tree_view->priv->anchor);
7583       tree_view->priv->anchor = NULL;
7584
7585       g_object_unref (tree_view->priv->model);
7586       tree_view->priv->search_column = -1;
7587       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
7588       tree_view->priv->fixed_height_check = 0;
7589     }
7590
7591   tree_view->priv->model = model;
7592
7593
7594   if (tree_view->priv->model)
7595     {
7596       gint i;
7597       GtkTreePath *path;
7598       GtkTreeIter iter;
7599
7600
7601       if (tree_view->priv->search_column == -1)
7602         {
7603           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
7604             {
7605               if (gtk_tree_model_get_column_type (model, i) == G_TYPE_STRING)
7606                 {
7607                   tree_view->priv->search_column = i;
7608                   break;
7609                 }
7610             }
7611         }
7612       g_object_ref (tree_view->priv->model);
7613       g_signal_connect (tree_view->priv->model,
7614                         "row_changed",
7615                         G_CALLBACK (gtk_tree_view_row_changed),
7616                         tree_view);
7617       g_signal_connect (tree_view->priv->model,
7618                         "row_inserted",
7619                         G_CALLBACK (gtk_tree_view_row_inserted),
7620                         tree_view);
7621       g_signal_connect (tree_view->priv->model,
7622                         "row_has_child_toggled",
7623                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
7624                         tree_view);
7625       g_signal_connect (tree_view->priv->model,
7626                         "row_deleted",
7627                         G_CALLBACK (gtk_tree_view_row_deleted),
7628                         tree_view);
7629       g_signal_connect (tree_view->priv->model,
7630                         "rows_reordered",
7631                         G_CALLBACK (gtk_tree_view_rows_reordered),
7632                         tree_view);
7633
7634       path = gtk_tree_path_new_first ();
7635       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
7636         {
7637           tree_view->priv->tree = _gtk_rbtree_new ();
7638           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
7639         }
7640       gtk_tree_path_free (path);
7641
7642       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
7643       install_presize_handler (tree_view);
7644     }
7645
7646   g_object_notify (G_OBJECT (tree_view), "model");
7647
7648   if (GTK_WIDGET_REALIZED (tree_view))
7649     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7650 }
7651
7652 /**
7653  * gtk_tree_view_get_selection:
7654  * @tree_view: A #GtkTreeView.
7655  *
7656  * Gets the #GtkTreeSelection associated with @tree_view.
7657  *
7658  * Return value: A #GtkTreeSelection object.
7659  **/
7660 GtkTreeSelection *
7661 gtk_tree_view_get_selection (GtkTreeView *tree_view)
7662 {
7663   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7664
7665   return tree_view->priv->selection;
7666 }
7667
7668 /**
7669  * gtk_tree_view_get_hadjustment:
7670  * @tree_view: A #GtkTreeView
7671  *
7672  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
7673  *
7674  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
7675  * used.
7676  **/
7677 GtkAdjustment *
7678 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
7679 {
7680   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7681
7682   if (tree_view->priv->hadjustment == NULL)
7683     gtk_tree_view_set_hadjustment (tree_view, NULL);
7684
7685   return tree_view->priv->hadjustment;
7686 }
7687
7688 /**
7689  * gtk_tree_view_set_hadjustment:
7690  * @tree_view: A #GtkTreeView
7691  * @adjustment: The #GtkAdjustment to set, or %NULL
7692  *
7693  * Sets the #GtkAdjustment for the current horizontal aspect.
7694  **/
7695 void
7696 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
7697                                GtkAdjustment *adjustment)
7698 {
7699   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7700
7701   gtk_tree_view_set_adjustments (tree_view,
7702                                  adjustment,
7703                                  tree_view->priv->vadjustment);
7704
7705   g_object_notify (G_OBJECT (tree_view), "hadjustment");
7706 }
7707
7708 /**
7709  * gtk_tree_view_get_vadjustment:
7710  * @tree_view: A #GtkTreeView
7711  *
7712  * Gets the #GtkAdjustment currently being used for the vertical aspect.
7713  *
7714  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
7715  * used.
7716  **/
7717 GtkAdjustment *
7718 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
7719 {
7720   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
7721
7722   if (tree_view->priv->vadjustment == NULL)
7723     gtk_tree_view_set_vadjustment (tree_view, NULL);
7724
7725   return tree_view->priv->vadjustment;
7726 }
7727
7728 /**
7729  * gtk_tree_view_set_vadjustment:
7730  * @tree_view: A #GtkTreeView
7731  * @adjustment: The #GtkAdjustment to set, or %NULL
7732  *
7733  * Sets the #GtkAdjustment for the current vertical aspect.
7734  **/
7735 void
7736 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
7737                                GtkAdjustment *adjustment)
7738 {
7739   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7740
7741   gtk_tree_view_set_adjustments (tree_view,
7742                                  tree_view->priv->hadjustment,
7743                                  adjustment);
7744
7745   g_object_notify (G_OBJECT (tree_view), "vadjustment");
7746 }
7747
7748 /* Column and header operations */
7749
7750 /**
7751  * gtk_tree_view_get_headers_visible:
7752  * @tree_view: A #GtkTreeView.
7753  *
7754  * Returns %TRUE if the headers on the @tree_view are visible.
7755  *
7756  * Return value: Whether the headers are visible or not.
7757  **/
7758 gboolean
7759 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
7760 {
7761   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7762
7763   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
7764 }
7765
7766 /**
7767  * gtk_tree_view_set_headers_visible:
7768  * @tree_view: A #GtkTreeView.
7769  * @headers_visible: %TRUE if the headers are visible
7770  *
7771  * Sets the the visibility state of the headers.
7772  **/
7773 void
7774 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
7775                                    gboolean     headers_visible)
7776 {
7777   gint x, y;
7778   GList *list;
7779   GtkTreeViewColumn *column;
7780
7781   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7782
7783   headers_visible = !! headers_visible;
7784
7785   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
7786     return;
7787
7788   if (headers_visible)
7789     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
7790   else
7791     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
7792
7793   if (GTK_WIDGET_REALIZED (tree_view))
7794     {
7795       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
7796       if (headers_visible)
7797         {
7798           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));
7799
7800           if (GTK_WIDGET_MAPPED (tree_view))
7801             gtk_tree_view_map_buttons (tree_view);
7802         }
7803       else
7804         {
7805           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
7806
7807           for (list = tree_view->priv->columns; list; list = list->next)
7808             {
7809               column = list->data;
7810               gtk_widget_unmap (column->button);
7811             }
7812           gdk_window_hide (tree_view->priv->header_window);
7813         }
7814     }
7815
7816   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
7817   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
7818   tree_view->priv->vadjustment->lower = 0;
7819   tree_view->priv->vadjustment->upper = tree_view->priv->height;
7820   gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
7821
7822   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7823
7824   g_object_notify (G_OBJECT (tree_view), "headers_visible");
7825 }
7826
7827 /**
7828  * gtk_tree_view_columns_autosize:
7829  * @tree_view: A #GtkTreeView.
7830  *
7831  * Resizes all columns to their optimal width. Only works after the
7832  * treeview has been realized.
7833  **/
7834 void
7835 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
7836 {
7837   gboolean dirty = FALSE;
7838   GList *list;
7839   GtkTreeViewColumn *column;
7840
7841   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7842
7843   for (list = tree_view->priv->columns; list; list = list->next)
7844     {
7845       column = list->data;
7846       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
7847         continue;
7848       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
7849       dirty = TRUE;
7850     }
7851
7852   if (dirty)
7853     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7854 }
7855
7856 /**
7857  * gtk_tree_view_set_headers_clickable:
7858  * @tree_view: A #GtkTreeView.
7859  * @setting: %TRUE if the columns are clickable.
7860  *
7861  * Allow the column title buttons to be clicked.
7862  **/
7863 void
7864 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
7865                                      gboolean   setting)
7866 {
7867   GList *list;
7868
7869   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7870   g_return_if_fail (tree_view->priv->model != NULL);
7871
7872   for (list = tree_view->priv->columns; list; list = list->next)
7873     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
7874
7875   g_object_notify (G_OBJECT (tree_view), "headers_clickable");
7876 }
7877
7878
7879 /**
7880  * gtk_tree_view_set_rules_hint
7881  * @tree_view: a #GtkTreeView
7882  * @setting: %TRUE if the tree requires reading across rows
7883  *
7884  * This function tells GTK+ that the user interface for your
7885  * application requires users to read across tree rows and associate
7886  * cells with one another. By default, GTK+ will then render the tree
7887  * with alternating row colors. Do <emphasis>not</emphasis> use it
7888  * just because you prefer the appearance of the ruled tree; that's a
7889  * question for the theme. Some themes will draw tree rows in
7890  * alternating colors even when rules are turned off, and users who
7891  * prefer that appearance all the time can choose those themes. You
7892  * should call this function only as a <emphasis>semantic</emphasis>
7893  * hint to the theme engine that your tree makes alternating colors
7894  * useful from a functional standpoint (since it has lots of columns,
7895  * generally).
7896  *
7897  **/
7898 void
7899 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
7900                               gboolean      setting)
7901 {
7902   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7903
7904   setting = setting != FALSE;
7905
7906   if (tree_view->priv->has_rules != setting)
7907     {
7908       tree_view->priv->has_rules = setting;
7909       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7910     }
7911
7912   g_object_notify (G_OBJECT (tree_view), "rules_hint");
7913 }
7914
7915 /**
7916  * gtk_tree_view_get_rules_hint
7917  * @tree_view: a #GtkTreeView
7918  *
7919  * Gets the setting set by gtk_tree_view_set_rules_hint().
7920  *
7921  * Return value: %TRUE if rules are useful for the user of this tree
7922  **/
7923 gboolean
7924 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
7925 {
7926   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
7927
7928   return tree_view->priv->has_rules;
7929 }
7930
7931 /* Public Column functions
7932  */
7933
7934 /**
7935  * gtk_tree_view_append_column:
7936  * @tree_view: A #GtkTreeView.
7937  * @column: The #GtkTreeViewColumn to add.
7938  *
7939  * Appends @column to the list of columns.
7940  *
7941  * Return value: The number of columns in @tree_view after appending.
7942  **/
7943 gint
7944 gtk_tree_view_append_column (GtkTreeView       *tree_view,
7945                              GtkTreeViewColumn *column)
7946 {
7947   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7948   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
7949   g_return_val_if_fail (column->tree_view == NULL, -1);
7950
7951   return gtk_tree_view_insert_column (tree_view, column, -1);
7952 }
7953
7954
7955 /**
7956  * gtk_tree_view_remove_column:
7957  * @tree_view: A #GtkTreeView.
7958  * @column: The #GtkTreeViewColumn to remove.
7959  *
7960  * Removes @column from @tree_view.
7961  *
7962  * Return value: The number of columns in @tree_view after removing.
7963  **/
7964 gint
7965 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
7966                              GtkTreeViewColumn *column)
7967 {
7968   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
7969   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
7970   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
7971
7972   _gtk_tree_view_column_unset_tree_view (column);
7973
7974   if (tree_view->priv->focus_column == column)
7975     tree_view->priv->focus_column = NULL;
7976
7977   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
7978   tree_view->priv->n_columns--;
7979
7980   if (GTK_WIDGET_REALIZED (tree_view))
7981     {
7982       GList *list;
7983
7984       _gtk_tree_view_column_unrealize_button (column);
7985       for (list = tree_view->priv->columns; list; list = list->next)
7986         {
7987           GtkTreeViewColumn *tmp_column;
7988
7989           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
7990           if (tmp_column->visible)
7991             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
7992         }
7993
7994       if (tree_view->priv->n_columns == 0 &&
7995           gtk_tree_view_get_headers_visible (tree_view))
7996         gdk_window_hide (tree_view->priv->header_window);
7997
7998       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7999     }
8000
8001   g_object_unref (G_OBJECT (column));
8002   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
8003
8004   return tree_view->priv->n_columns;
8005 }
8006
8007 /**
8008  * gtk_tree_view_insert_column:
8009  * @tree_view: A #GtkTreeView.
8010  * @column: The #GtkTreeViewColumn to be inserted.
8011  * @position: The position to insert @column in.
8012  *
8013  * This inserts the @column into the @tree_view at @position.  If @position is
8014  * -1, then the column is inserted at the end.
8015  *
8016  * Return value: The number of columns in @tree_view after insertion.
8017  **/
8018 gint
8019 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
8020                              GtkTreeViewColumn *column,
8021                              gint               position)
8022 {
8023   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
8024   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
8025   g_return_val_if_fail (column->tree_view == NULL, -1);
8026
8027   g_object_ref (G_OBJECT (column));
8028   gtk_object_sink (GTK_OBJECT (column));
8029
8030   if (tree_view->priv->n_columns == 0 &&
8031       GTK_WIDGET_REALIZED (tree_view) &&
8032       gtk_tree_view_get_headers_visible (tree_view))
8033     {
8034       gdk_window_show (tree_view->priv->header_window);
8035     }
8036
8037   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
8038                                             column, position);
8039   tree_view->priv->n_columns++;
8040
8041   _gtk_tree_view_column_set_tree_view (column, tree_view);
8042
8043   if (GTK_WIDGET_REALIZED (tree_view))
8044     {
8045       GList *list;
8046
8047       _gtk_tree_view_column_realize_button (column);
8048
8049       for (list = tree_view->priv->columns; list; list = list->next)
8050         {
8051           column = GTK_TREE_VIEW_COLUMN (list->data);
8052           if (column->visible)
8053             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8054         }
8055       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8056     }
8057
8058   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
8059
8060   return tree_view->priv->n_columns;
8061 }
8062
8063 /**
8064  * gtk_tree_view_insert_column_with_attributes:
8065  * @tree_view: A #GtkTreeView
8066  * @position: The position to insert the new column in.
8067  * @title: The title to set the header to.
8068  * @cell: The #GtkCellRenderer.
8069  * @Varargs: A %NULL-terminated list of attributes.
8070  *
8071  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
8072  * @position.  If @position is -1, then the newly created column is inserted at
8073  * the end.  The column is initialized with the attributes given.
8074  *
8075  * Return value: The number of columns in @tree_view after insertion.
8076  **/
8077 gint
8078 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
8079                                              gint             position,
8080                                              const gchar     *title,
8081                                              GtkCellRenderer *cell,
8082                                              ...)
8083 {
8084   GtkTreeViewColumn *column;
8085   gchar *attribute;
8086   va_list args;
8087   gint column_id;
8088
8089   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
8090
8091   column = gtk_tree_view_column_new ();
8092
8093   gtk_tree_view_column_set_title (column, title);
8094   gtk_tree_view_column_pack_start (column, cell, TRUE);
8095
8096   va_start (args, cell);
8097
8098   attribute = va_arg (args, gchar *);
8099
8100   while (attribute != NULL)
8101     {
8102       column_id = va_arg (args, gint);
8103       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
8104       attribute = va_arg (args, gchar *);
8105     }
8106
8107   va_end (args);
8108
8109   gtk_tree_view_insert_column (tree_view, column, position);
8110
8111   return tree_view->priv->n_columns;
8112 }
8113
8114 /**
8115  * gtk_tree_view_insert_column_with_data_func:
8116  * @tree_view: a #GtkTreeView
8117  * @position: Position to insert, -1 for append
8118  * @title: column title
8119  * @cell: cell renderer for column
8120  * @func: function to set attributes of cell renderer
8121  * @data: data for @func
8122  * @dnotify: destroy notifier for @data
8123  *
8124  * Convenience function that inserts a new column into the #GtkTreeView
8125  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
8126  * attributes (normally using data from the model). See also
8127  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
8128  *
8129  * Return value: number of columns in the tree view post-insert
8130  **/
8131 gint
8132 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
8133                                              gint                       position,
8134                                              const gchar               *title,
8135                                              GtkCellRenderer           *cell,
8136                                              GtkTreeCellDataFunc        func,
8137                                              gpointer                   data,
8138                                              GDestroyNotify             dnotify)
8139 {
8140   GtkTreeViewColumn *column;
8141
8142   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
8143
8144   column = gtk_tree_view_column_new ();
8145
8146   gtk_tree_view_column_set_title (column, title);
8147   gtk_tree_view_column_pack_start (column, cell, TRUE);
8148   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
8149
8150   gtk_tree_view_insert_column (tree_view, column, position);
8151
8152   return tree_view->priv->n_columns;
8153 }
8154
8155 /**
8156  * gtk_tree_view_get_column:
8157  * @tree_view: A #GtkTreeView.
8158  * @n: The position of the column, counting from 0.
8159  *
8160  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
8161  *
8162  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
8163  * range of columns.
8164  **/
8165 GtkTreeViewColumn *
8166 gtk_tree_view_get_column (GtkTreeView *tree_view,
8167                           gint         n)
8168 {
8169   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
8170
8171   if (n < 0 || n >= tree_view->priv->n_columns)
8172     return NULL;
8173
8174   if (tree_view->priv->columns == NULL)
8175     return NULL;
8176
8177   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
8178 }
8179
8180 /**
8181  * gtk_tree_view_get_columns:
8182  * @tree_view: A #GtkTreeView
8183  *
8184  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
8185  * The returned list must be freed with g_list_free ().
8186  *
8187  * Return value: A list of #GtkTreeViewColumn s
8188  **/
8189 GList *
8190 gtk_tree_view_get_columns (GtkTreeView *tree_view)
8191 {
8192   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
8193
8194   return g_list_copy (tree_view->priv->columns);
8195 }
8196
8197 /**
8198  * gtk_tree_view_move_column_after:
8199  * @tree_view: A #GtkTreeView
8200  * @column: The #GtkTreeViewColumn to be moved.
8201  * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
8202  *
8203  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
8204  * @column is placed in the first position.
8205  **/
8206 void
8207 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
8208                                  GtkTreeViewColumn *column,
8209                                  GtkTreeViewColumn *base_column)
8210 {
8211   GList *column_list_el, *base_el = NULL;
8212
8213   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8214
8215   column_list_el = g_list_find (tree_view->priv->columns, column);
8216   g_return_if_fail (column_list_el != NULL);
8217
8218   if (base_column)
8219     {
8220       base_el = g_list_find (tree_view->priv->columns, base_column);
8221       g_return_if_fail (base_el != NULL);
8222     }
8223
8224   if (column_list_el->prev == base_el)
8225     return;
8226
8227   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
8228   if (base_el == NULL)
8229     {
8230       column_list_el->prev = NULL;
8231       column_list_el->next = tree_view->priv->columns;
8232       if (column_list_el->next)
8233         column_list_el->next->prev = column_list_el;
8234       tree_view->priv->columns = column_list_el;
8235     }
8236   else
8237     {
8238       column_list_el->prev = base_el;
8239       column_list_el->next = base_el->next;
8240       if (column_list_el->next)
8241         column_list_el->next->prev = column_list_el;
8242       base_el->next = column_list_el;
8243     }
8244
8245   if (GTK_WIDGET_REALIZED (tree_view))
8246     {
8247       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8248       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view));
8249     }
8250
8251   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
8252 }
8253
8254 /**
8255  * gtk_tree_view_set_expander_column:
8256  * @tree_view: A #GtkTreeView
8257  * @column: %NULL, or the column to draw the expander arrow at.
8258  *
8259  * Sets the column to draw the expander arrow at. It must be in @tree_view.  If
8260  * @column is %NULL, then the expander arrow is always at the first visible
8261  * column.
8262  **/
8263 void
8264 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
8265                                    GtkTreeViewColumn *column)
8266 {
8267   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8268   if (column != NULL)
8269     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
8270
8271   if (tree_view->priv->expander_column != column)
8272     {
8273       GList *list;
8274
8275       if (column)
8276         {
8277           /* Confirm that column is in tree_view */
8278           for (list = tree_view->priv->columns; list; list = list->next)
8279             if (list->data == column)
8280               break;
8281           g_return_if_fail (list != NULL);
8282         }
8283
8284       tree_view->priv->expander_column = column;
8285       g_object_notify (G_OBJECT (tree_view), "expander_column");
8286     }
8287 }
8288
8289 /**
8290  * gtk_tree_view_get_expander_column:
8291  * @tree_view: A #GtkTreeView
8292  *
8293  * Returns the column that is the current expander column.  This
8294  * column has the expander arrow drawn next to it.
8295  *
8296  * Return value: The expander column.
8297  **/
8298 GtkTreeViewColumn *
8299 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
8300 {
8301   GList *list;
8302
8303   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
8304
8305   for (list = tree_view->priv->columns; list; list = list->next)
8306     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
8307       return (GtkTreeViewColumn *) list->data;
8308   return NULL;
8309 }
8310
8311
8312 /**
8313  * gtk_tree_view_set_column_drag_function:
8314  * @tree_view: A #GtkTreeView.
8315  * @func: A function to determine which columns are reorderable, or %NULL.
8316  * @user_data: User data to be passed to @func, or %NULL
8317  * @destroy: Destroy notifier for @user_data, or %NULL
8318  *
8319  * Sets a user function for determining where a column may be dropped when
8320  * dragged.  This function is called on every column pair in turn at the
8321  * beginning of a column drag to determine where a drop can take place.  The
8322  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
8323  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
8324  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
8325  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
8326  * @tree_view reverts to the default behavior of allowing all columns to be
8327  * dropped everywhere.
8328  **/
8329 void
8330 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
8331                                         GtkTreeViewColumnDropFunc  func,
8332                                         gpointer                   user_data,
8333                                         GtkDestroyNotify           destroy)
8334 {
8335   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8336
8337   if (tree_view->priv->column_drop_func_data_destroy)
8338     (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
8339
8340   tree_view->priv->column_drop_func = func;
8341   tree_view->priv->column_drop_func_data = user_data;
8342   tree_view->priv->column_drop_func_data_destroy = destroy;
8343 }
8344
8345 /**
8346  * gtk_tree_view_scroll_to_point:
8347  * @tree_view: a #GtkTreeView
8348  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
8349  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
8350  *
8351  * Scrolls the tree view such that the top-left corner of the visible
8352  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
8353  * in tree window coordinates.  The @tree_view must be realized before
8354  * this function is called.  If it isn't, you probably want to be
8355  * using gtk_tree_view_scroll_to_cell().
8356  *
8357  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
8358  **/
8359 void
8360 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
8361                                gint         tree_x,
8362                                gint         tree_y)
8363 {
8364   GtkAdjustment *hadj;
8365   GtkAdjustment *vadj;
8366
8367   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8368   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
8369
8370   hadj = tree_view->priv->hadjustment;
8371   vadj = tree_view->priv->vadjustment;
8372
8373   if (tree_x != -1)
8374     gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
8375   if (tree_y != -1)
8376     gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
8377 }
8378
8379 /**
8380  * gtk_tree_view_scroll_to_cell
8381  * @tree_view: A #GtkTreeView.
8382  * @path: The path of the row to move to, or %NULL.
8383  * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
8384  * @use_align: whether to use alignment arguments, or %FALSE.
8385  * @row_align: The vertical alignment of the row specified by @path.
8386  * @col_align: The horizontal alignment of the column specified by @column.
8387  *
8388  * Moves the alignments of @tree_view to the position specified by @column and
8389  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
8390  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
8391  * or @path need to be non-%NULL.  @row_align determines where the row is
8392  * placed, and @col_align determines where @column is placed.  Both are expected
8393  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
8394  * right/bottom alignment, 0.5 means center.
8395  *
8396  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
8397  * tree does the minimum amount of work to scroll the cell onto the screen.
8398  * This means that the cell will be scrolled to the edge closest to it's current
8399  * position.  If the cell is currently visible on the screen, nothing is done.
8400  *
8401  * This function only works if the model is set, and @path is a valid row on the
8402  * model.  If the model changes before the @tree_view is realized, the centered
8403  * path will be modified to reflect this change.
8404  **/
8405 void
8406 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
8407                               GtkTreePath       *path,
8408                               GtkTreeViewColumn *column,
8409                               gboolean           use_align,
8410                               gfloat             row_align,
8411                               gfloat             col_align)
8412 {
8413   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8414   g_return_if_fail (tree_view->priv->model != NULL);
8415   g_return_if_fail (tree_view->priv->tree != NULL);
8416   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
8417   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
8418   g_return_if_fail (path != NULL || column != NULL);
8419
8420 #if 0
8421   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
8422            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
8423 #endif
8424   row_align = CLAMP (row_align, 0.0, 1.0);
8425   col_align = CLAMP (col_align, 0.0, 1.0);
8426
8427
8428   /* Note: Despite the benefits that come from having one code path for the
8429    * scrolling code, we short-circuit validate_visible_area's immplementation as
8430    * it is much slower than just going to the point.
8431    */
8432   if (! GTK_WIDGET_REALIZED (tree_view) ||
8433       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
8434     {
8435       if (tree_view->priv->scroll_to_path)
8436         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
8437
8438       tree_view->priv->scroll_to_path = NULL;
8439       tree_view->priv->scroll_to_column = NULL;
8440
8441       if (path)
8442         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
8443       if (column)
8444         tree_view->priv->scroll_to_column = column;
8445       tree_view->priv->scroll_to_use_align = use_align;
8446       tree_view->priv->scroll_to_row_align = row_align;
8447       tree_view->priv->scroll_to_col_align = col_align;
8448
8449       install_presize_handler (tree_view);
8450     }
8451   else
8452     {
8453       GdkRectangle cell_rect;
8454       GdkRectangle vis_rect;
8455       gint dest_x, dest_y;
8456
8457       gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
8458       gtk_tree_view_widget_to_tree_coords (tree_view, cell_rect.x, cell_rect.y, &(cell_rect.x), &(cell_rect.y));
8459       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
8460
8461       dest_x = vis_rect.x;
8462       dest_y = vis_rect.y;
8463
8464       if (column)
8465         {
8466           if (use_align)
8467             {
8468               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
8469             }
8470           else
8471             {
8472               if (cell_rect.x < vis_rect.x)
8473                 dest_x = cell_rect.x;
8474               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
8475                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
8476             }
8477         }
8478
8479       if (path)
8480         {
8481           if (use_align)
8482             {
8483               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
8484               dest_y = MAX (dest_y, 0);
8485             }
8486           else
8487             {
8488               if (cell_rect.y < vis_rect.y)
8489                 dest_y = cell_rect.y;
8490               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
8491                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
8492             }
8493         }
8494
8495       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
8496     }
8497 }
8498
8499 /**
8500  * gtk_tree_view_row_activated:
8501  * @tree_view: A #GtkTreeView
8502  * @path: The #GtkTreePath to be activated.
8503  * @column: The #GtkTreeViewColumn to be activated.
8504  *
8505  * Activates the cell determined by @path and @column.
8506  **/
8507 void
8508 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
8509                              GtkTreePath       *path,
8510                              GtkTreeViewColumn *column)
8511 {
8512   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8513
8514   g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, path, column);
8515 }
8516
8517
8518 static void
8519 gtk_tree_view_expand_all_helper (GtkRBTree  *tree,
8520                                  GtkRBNode  *node,
8521                                  gpointer  data)
8522 {
8523   GtkTreeView *tree_view = data;
8524
8525   if (node->children)
8526     _gtk_rbtree_traverse (node->children,
8527                           node->children->root,
8528                           G_PRE_ORDER,
8529                           gtk_tree_view_expand_all_helper,
8530                           data);
8531   else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
8532     {
8533       GtkTreePath *path;
8534       GtkTreeIter iter;
8535       GtkTreeIter child;
8536
8537       node->children = _gtk_rbtree_new ();
8538       node->children->parent_tree = tree;
8539       node->children->parent_node = node;
8540       path = _gtk_tree_view_find_path (tree_view, tree, node);
8541       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
8542       gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
8543       gtk_tree_view_build_tree (tree_view,
8544                                 node->children,
8545                                 &child,
8546                                 gtk_tree_path_get_depth (path) + 1,
8547                                 TRUE);
8548       gtk_tree_path_free (path);
8549     }
8550 }
8551
8552 /**
8553  * gtk_tree_view_expand_all:
8554  * @tree_view: A #GtkTreeView.
8555  *
8556  * Recursively expands all nodes in the @tree_view.
8557  **/
8558 void
8559 gtk_tree_view_expand_all (GtkTreeView *tree_view)
8560 {
8561   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8562
8563   if (tree_view->priv->tree == NULL)
8564     return;
8565
8566   _gtk_rbtree_traverse (tree_view->priv->tree,
8567                         tree_view->priv->tree->root,
8568                         G_PRE_ORDER,
8569                         gtk_tree_view_expand_all_helper,
8570                         tree_view);
8571 }
8572
8573 /* Timeout to animate the expander during expands and collapses */
8574 static gboolean
8575 expand_collapse_timeout (gpointer data)
8576 {
8577   GtkTreeView *tree_view = data;
8578   GtkRBNode *node;
8579   GtkRBTree *tree;
8580   gboolean expanding;
8581   gboolean redraw;
8582
8583   GDK_THREADS_ENTER ();
8584
8585   redraw = FALSE;
8586   expanding = TRUE;
8587
8588   node = tree_view->priv->expanded_collapsed_node;
8589   tree = tree_view->priv->expanded_collapsed_tree;
8590
8591   if (node->children == NULL)
8592     expanding = FALSE;
8593
8594   if (expanding)
8595     {
8596       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
8597         {
8598           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8599           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
8600
8601           redraw = TRUE;
8602
8603         }
8604       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
8605         {
8606           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
8607
8608           redraw = TRUE;
8609         }
8610     }
8611   else
8612     {
8613       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
8614         {
8615           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
8616           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8617
8618           redraw = TRUE;
8619         }
8620       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
8621         {
8622           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8623
8624           redraw = TRUE;
8625
8626         }
8627     }
8628
8629   if (redraw)
8630     {
8631       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
8632
8633       GDK_THREADS_LEAVE ();
8634
8635       return TRUE;
8636     }
8637
8638   GDK_THREADS_LEAVE ();
8639
8640   return FALSE;
8641 }
8642
8643 /**
8644  * gtk_tree_view_collapse_all:
8645  * @tree_view: A #GtkTreeView.
8646  *
8647  * Recursively collapses all visible, expanded nodes in @tree_view.
8648  **/
8649 void
8650 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
8651 {
8652   GtkRBTree *tree;
8653   GtkRBNode *node;
8654   GtkTreePath *path;
8655   guint *indices;
8656
8657   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8658
8659   if (tree_view->priv->tree == NULL)
8660     return;
8661
8662   path = gtk_tree_path_new ();
8663   gtk_tree_path_down (path);
8664   indices = gtk_tree_path_get_indices (path);
8665
8666   tree = tree_view->priv->tree;
8667   node = tree->root;
8668   while (node && node->left != tree->nil)
8669     node = node->left;
8670
8671   while (node)
8672     {
8673       if (node->children)
8674         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
8675       indices[0]++;
8676       node = _gtk_rbtree_next (tree, node);
8677     }
8678
8679   gtk_tree_path_free (path);
8680 }
8681
8682 /* FIXME the bool return values for expand_row and collapse_row are
8683  * not analagous; they should be TRUE if the row had children and
8684  * was not already in the requested state.
8685  */
8686
8687
8688 static gboolean
8689 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
8690                                GtkTreePath *path,
8691                                GtkRBTree   *tree,
8692                                GtkRBNode   *node,
8693                                gboolean     open_all,
8694                                gboolean     animate)
8695 {
8696   GtkTreeIter iter;
8697   GtkTreeIter temp;
8698   gboolean expand;
8699
8700
8701   if (node->children && !open_all)
8702     return TRUE;
8703   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
8704     return FALSE;
8705
8706   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
8707   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
8708     return FALSE;
8709
8710   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
8711
8712   if (expand)
8713     return FALSE;
8714
8715   node->children = _gtk_rbtree_new ();
8716   node->children->parent_tree = tree;
8717   node->children->parent_node = node;
8718
8719   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
8720
8721   gtk_tree_view_build_tree (tree_view,
8722                             node->children,
8723                             &temp,
8724                             gtk_tree_path_get_depth (path) + 1,
8725                             open_all);
8726
8727   if (tree_view->priv->expand_collapse_timeout)
8728     {
8729       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
8730       tree_view->priv->expand_collapse_timeout = 0;
8731     }
8732
8733   if (tree_view->priv->expanded_collapsed_node != NULL)
8734     {
8735       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
8736       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8737
8738       tree_view->priv->expanded_collapsed_node = NULL;
8739     }
8740
8741   if (animate)
8742     {
8743       tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
8744       tree_view->priv->expanded_collapsed_node = node;
8745       tree_view->priv->expanded_collapsed_tree = tree;
8746
8747       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8748     }
8749
8750   install_presize_handler (tree_view);
8751
8752   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
8753   return TRUE;
8754 }
8755
8756
8757 /**
8758  * gtk_tree_view_expand_row:
8759  * @tree_view: a #GtkTreeView
8760  * @path: path to a row
8761  * @open_all: whether to recursively expand, or just expand immediate children
8762  *
8763  * Opens the row so its children are visible.
8764  *
8765  * Return value: %TRUE if the row existed and had children
8766  **/
8767 gboolean
8768 gtk_tree_view_expand_row (GtkTreeView *tree_view,
8769                           GtkTreePath *path,
8770                           gboolean     open_all)
8771 {
8772   GtkRBTree *tree;
8773   GtkRBNode *node;
8774
8775   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8776   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
8777   g_return_val_if_fail (path != NULL, FALSE);
8778
8779   if (_gtk_tree_view_find_node (tree_view,
8780                                 path,
8781                                 &tree,
8782                                 &node))
8783     return FALSE;
8784
8785   if (tree != NULL)
8786     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
8787   else
8788     return FALSE;
8789 }
8790
8791 static gboolean
8792 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
8793                                  GtkTreePath *path,
8794                                  GtkRBTree   *tree,
8795                                  GtkRBNode   *node,
8796                                  gboolean     animate)
8797 {
8798   GtkTreeIter iter;
8799   GtkTreeIter children;
8800   gboolean collapse;
8801   gint x, y;
8802   GList *list;
8803
8804   if (node->children == NULL)
8805     return FALSE;
8806
8807   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
8808
8809   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
8810
8811   if (collapse)
8812     return FALSE;
8813
8814   /* if the prelighted node is a child of us, we want to unprelight it.  We have
8815    * a chance to prelight the correct node below */
8816
8817   if (tree_view->priv->prelight_tree)
8818     {
8819       GtkRBTree *parent_tree;
8820       GtkRBNode *parent_node;
8821
8822       parent_tree = tree_view->priv->prelight_tree->parent_tree;
8823       parent_node = tree_view->priv->prelight_tree->parent_node;
8824       while (parent_tree)
8825         {
8826           if (parent_tree == tree && parent_node == node)
8827             {
8828               ensure_unprelighted (tree_view);
8829               break;
8830             }
8831           parent_node = parent_tree->parent_node;
8832           parent_tree = parent_tree->parent_tree;
8833         }
8834     }
8835
8836   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
8837
8838   for (list = tree_view->priv->columns; list; list = list->next)
8839     {
8840       GtkTreeViewColumn *column = list->data;
8841
8842       if (column->visible == FALSE)
8843         continue;
8844       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8845         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8846     }
8847
8848   if (tree_view->priv->destroy_count_func)
8849     {
8850       GtkTreePath *child_path;
8851       gint child_count = 0;
8852       child_path = gtk_tree_path_copy (path);
8853       gtk_tree_path_down (child_path);
8854       if (node->children)
8855         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8856       (* tree_view->priv->destroy_count_func) (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
8857       gtk_tree_path_free (child_path);
8858     }
8859
8860   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
8861     {
8862       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8863
8864       if (gtk_tree_path_is_ancestor (path, cursor_path))
8865         {
8866           gtk_tree_row_reference_free (tree_view->priv->cursor);
8867           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
8868                                                                       tree_view->priv->model,
8869                                                                       path);
8870         }
8871       gtk_tree_path_free (cursor_path);
8872     }
8873
8874   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
8875     {
8876       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
8877       if (gtk_tree_path_is_ancestor (path, anchor_path))
8878         {
8879           gtk_tree_row_reference_free (tree_view->priv->anchor);
8880           tree_view->priv->anchor = NULL;
8881         }
8882       gtk_tree_path_free (anchor_path);
8883     }
8884
8885   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press))
8886     {
8887       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
8888       if (gtk_tree_path_is_ancestor (path, lsc))
8889         {
8890           gtk_tree_row_reference_free (tree_view->priv->last_button_press);
8891           tree_view->priv->last_button_press = NULL;
8892         }
8893       gtk_tree_path_free (lsc);
8894     }
8895
8896   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press_2))
8897     {
8898       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press_2);
8899       if (gtk_tree_path_is_ancestor (path, lsc))
8900         {
8901           gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
8902           tree_view->priv->last_button_press_2 = NULL;
8903         }
8904       gtk_tree_path_free (lsc);
8905     }
8906
8907   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
8908     {
8909       _gtk_rbtree_remove (node->children);
8910       g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed", 0);
8911     }
8912   else
8913     _gtk_rbtree_remove (node->children);
8914
8915   if (tree_view->priv->expand_collapse_timeout)
8916     {
8917       gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
8918       tree_view->priv->expand_collapse_timeout = 0;
8919     }
8920   
8921   if (tree_view->priv->expanded_collapsed_node != NULL)
8922     {
8923       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
8924       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8925       
8926       tree_view->priv->expanded_collapsed_node = NULL;
8927     }
8928
8929   if (animate)
8930     {
8931       tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
8932       tree_view->priv->expanded_collapsed_node = node;
8933       tree_view->priv->expanded_collapsed_tree = tree;
8934
8935       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
8936     }
8937   
8938   if (GTK_WIDGET_MAPPED (tree_view))
8939     {
8940       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8941     }
8942
8943   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
8944
8945   /* now that we've collapsed all rows, we want to try to set the prelight
8946    * again. To do this, we fake a motion event and send it to ourselves. */
8947
8948   if (gdk_window_at_pointer (&x, &y) == tree_view->priv->bin_window)
8949     {
8950       GdkEventMotion event;
8951       event.window = tree_view->priv->bin_window;
8952       event.x = x;
8953       event.y = y;
8954
8955       /* despite the fact this isn't a real event, I'm almost positive it will
8956        * never trigger a drag event.  maybe_drag is the only function that uses
8957        * more than just event.x and event.y. */
8958       gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
8959     }
8960   return TRUE;
8961 }
8962
8963 /**
8964  * gtk_tree_view_collapse_row:
8965  * @tree_view: a #GtkTreeView
8966  * @path: path to a row in the @tree_view
8967  *
8968  * Collapses a row (hides its child rows, if they exist).
8969  *
8970  * Return value: %TRUE if the row was collapsed.
8971  **/
8972 gboolean
8973 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
8974                             GtkTreePath *path)
8975 {
8976   GtkRBTree *tree;
8977   GtkRBNode *node;
8978
8979   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8980   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
8981   g_return_val_if_fail (path != NULL, FALSE);
8982
8983   if (_gtk_tree_view_find_node (tree_view,
8984                                 path,
8985                                 &tree,
8986                                 &node))
8987     return FALSE;
8988
8989   if (tree == NULL || node->children == NULL)
8990     return FALSE;
8991
8992   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
8993 }
8994
8995 static void
8996 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
8997                                         GtkRBTree              *tree,
8998                                         GtkTreePath            *path,
8999                                         GtkTreeViewMappingFunc  func,
9000                                         gpointer                user_data)
9001 {
9002   GtkRBNode *node;
9003
9004   if (tree == NULL || tree->root == NULL)
9005     return;
9006
9007   node = tree->root;
9008
9009   while (node && node->left != tree->nil)
9010     node = node->left;
9011
9012   while (node)
9013     {
9014       if (node->children)
9015         {
9016           gtk_tree_path_down (path);
9017           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
9018           gtk_tree_path_up (path);
9019           (* func) (tree_view, path, user_data);
9020         }
9021       gtk_tree_path_next (path);
9022       node = _gtk_rbtree_next (tree, node);
9023     }
9024 }
9025
9026 /**
9027  * gtk_tree_view_map_expanded_rows:
9028  * @tree_view: A #GtkTreeView
9029  * @func: A function to be called
9030  * @data: User data to be passed to the function.
9031  *
9032  * Calls @func on all expanded rows.
9033  **/
9034 void
9035 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
9036                                  GtkTreeViewMappingFunc  func,
9037                                  gpointer                user_data)
9038 {
9039   GtkTreePath *path;
9040
9041   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9042   g_return_if_fail (func != NULL);
9043
9044   path = gtk_tree_path_new_first ();
9045
9046   gtk_tree_view_map_expanded_rows_helper (tree_view,
9047                                           tree_view->priv->tree,
9048                                           path, func, user_data);
9049
9050   gtk_tree_path_free (path);
9051 }
9052
9053 /**
9054  * gtk_tree_view_row_expanded:
9055  * @tree_view: A #GtkTreeView.
9056  * @path: A #GtkTreePath to test expansion state.
9057  *
9058  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
9059  *
9060  * Return value: %TRUE if #path is expanded.
9061  **/
9062 gboolean
9063 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
9064                             GtkTreePath *path)
9065 {
9066   GtkRBTree *tree;
9067   GtkRBNode *node;
9068
9069   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
9070   g_return_val_if_fail (path != NULL, FALSE);
9071
9072   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9073
9074   if (node == NULL)
9075     return FALSE;
9076
9077   return (node->children != NULL);
9078 }
9079
9080 static GtkTargetEntry row_targets[] = {
9081   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
9082 };
9083
9084
9085 /**
9086  * gtk_tree_view_get_reorderable:
9087  * @tree_view: a #GtkTreeView
9088  *
9089  * Retrieves whether the user can reorder the tree via drag-and-drop. See
9090  * gtk_tree_view_set_reorderable().
9091  *
9092  * Return value: %TRUE if the tree can be reordered.
9093  **/
9094 gboolean
9095 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
9096 {
9097   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
9098
9099   return tree_view->priv->reorderable;
9100 }
9101
9102 /**
9103  * gtk_tree_view_set_reorderable:
9104  * @tree_view: A #GtkTreeView.
9105  * @reorderable: %TRUE, if the tree can be reordered.
9106  *
9107  * This function is a convenience function to allow you to reorder models that
9108  * support the #GtkDragSourceIface and the #GtkDragDestIface.  Both
9109  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
9110  * the user can reorder the model by dragging and dropping rows.  The
9111  * developer can listen to these changes by connecting to the model's
9112  * signals.
9113  *
9114  * This function does not give you any degree of control over the order -- any
9115  * reorderering is allowed.  If more control is needed, you should probably
9116  * handle drag and drop manually.
9117  **/
9118 void
9119 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
9120                                gboolean     reorderable)
9121 {
9122   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9123
9124   reorderable = reorderable != FALSE;
9125
9126   if (tree_view->priv->reorderable == reorderable)
9127     return;
9128
9129   if (reorderable)
9130     {
9131       gtk_tree_view_enable_model_drag_source (tree_view,
9132                                               GDK_BUTTON1_MASK,
9133                                               row_targets,
9134                                               G_N_ELEMENTS (row_targets),
9135                                               GDK_ACTION_MOVE);
9136       gtk_tree_view_enable_model_drag_dest (tree_view,
9137                                             row_targets,
9138                                             G_N_ELEMENTS (row_targets),
9139                                             GDK_ACTION_MOVE);
9140     }
9141   else
9142     {
9143       gtk_tree_view_unset_rows_drag_source (tree_view);
9144       gtk_tree_view_unset_rows_drag_dest (tree_view);
9145     }
9146
9147   tree_view->priv->reorderable = reorderable;
9148
9149   g_object_notify (G_OBJECT (tree_view), "reorderable");
9150 }
9151
9152 static void
9153 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
9154                                GtkTreePath     *path,
9155                                gboolean         clear_and_select,
9156                                gboolean         clamp_node)
9157 {
9158   GtkRBTree *tree = NULL;
9159   GtkRBNode *node = NULL;
9160   GdkModifierType state = 0;
9161
9162   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9163     {
9164       GtkTreePath *cursor_path;
9165       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9166       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9167       gtk_tree_path_free (cursor_path);
9168     }
9169
9170   gtk_tree_row_reference_free (tree_view->priv->cursor);
9171   gtk_get_current_event_state (&state);
9172
9173   tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
9174                                                               tree_view->priv->model,
9175                                                               path);
9176   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9177   if (tree != NULL)
9178     {
9179       if (clear_and_select && !((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK))
9180         _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
9181                                                   node, tree, path,
9182                                                   state, FALSE);
9183       if (clamp_node)
9184         {
9185           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
9186           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
9187         }
9188     }
9189
9190   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[CURSOR_CHANGED], 0);
9191 }
9192
9193 /**
9194  * gtk_tree_view_get_cursor:
9195  * @tree_view: A #GtkTreeView
9196  * @path: A pointer to be filled with the current cursor path, or %NULL
9197  * @focus_column: A pointer to be filled with the current focus column, or %NULL
9198  *
9199  * Fills in @path and @focus_column with the current path and focus column.  If
9200  * the cursor isn't currently set, then *@path will be %NULL.  If no column
9201  * currently has focus, then *@focus_column will be %NULL.
9202  **/
9203 void
9204 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
9205                           GtkTreePath       **path,
9206                           GtkTreeViewColumn **focus_column)
9207 {
9208   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9209
9210   if (path)
9211     {
9212       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9213         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9214       else
9215         *path = NULL;
9216     }
9217
9218   if (focus_column)
9219     {
9220       *focus_column = tree_view->priv->focus_column;
9221     }
9222 }
9223
9224 /**
9225  * gtk_tree_view_set_cursor:
9226  * @tree_view: A #GtkTreeView
9227  * @path: A #GtkTreePath
9228  * @focus_column: A #GtkTreeViewColumn, or %NULL
9229  * @start_editing: %TRUE if the specified cell should start being edited.
9230  *
9231  * Sets the current keyboard focus to be at @path, and selects it.  This is
9232  * useful when you want to focus the user's attention on a particular row.  If
9233  * @column is not %NULL, then focus is given to the column specified by it.
9234  * Additionally, if @column is specified, and @start_editing is %TRUE, then
9235  * editing should be started in the specified cell.  This function is often
9236  * followed by @gtk_widget_grab_focus (@tree_view) in order to give keyboard
9237  * focus to the widget.  Please note that editing can only happen when the
9238  * widget is realized.
9239  **/
9240 void
9241 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
9242                           GtkTreePath       *path,
9243                           GtkTreeViewColumn *focus_column,
9244                           gboolean           start_editing)
9245 {
9246   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9247   g_return_if_fail (path != NULL);
9248   if (focus_column)
9249     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (focus_column));
9250
9251   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
9252
9253   if (focus_column && focus_column->visible)
9254     {
9255       GList *list;
9256       gboolean column_in_tree = FALSE;
9257
9258       for (list = tree_view->priv->columns; list; list = list->next)
9259         if (list->data == focus_column)
9260           {
9261             column_in_tree = TRUE;
9262             break;
9263           }
9264       g_return_if_fail (column_in_tree);
9265       tree_view->priv->focus_column = focus_column;
9266       if (start_editing)
9267         gtk_tree_view_start_editing (tree_view, path);
9268     }
9269 }
9270
9271
9272 /**
9273  * gtk_tree_view_get_bin_window:
9274  * @tree_view: A #GtkTreeView
9275  * 
9276  * Returns the window that @tree_view renders to.  This is used primarily to
9277  * compare to <literal>event->window</literal> to confirm that the event on
9278  * @tree_view is on the right window.
9279  * 
9280  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
9281  **/
9282 GdkWindow *
9283 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
9284 {
9285   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
9286
9287   return tree_view->priv->bin_window;
9288 }
9289
9290 /**
9291  * gtk_tree_view_get_path_at_pos:
9292  * @tree_view: A #GtkTreeView.
9293  * @x: The x position to be identified.
9294  * @y: The y position to be identified.
9295  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
9296  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
9297  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
9298  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
9299  *
9300  * Finds the path at the point (@x, @y), relative to widget coordinates.  That
9301  * is, @x and @y are relative to an events coordinates. @x and @y must come
9302  * from an event on the @tree_view only where event->window ==
9303  * gtk_tree_view_get_bin (). It is primarily for things like popup menus.
9304  * If @path is non-%NULL, then it will be filled with the #GtkTreePath at that
9305  * point.  This path should be freed with gtk_tree_path_free().  If @column
9306  * is non-%NULL, then it will be filled with the column at that point.
9307  * @cell_x and @cell_y return the coordinates relative to the cell background
9308  * (i.e. the @background_area passed to gtk_cell_renderer_render()).  This
9309  * function is only meaningful if @tree_view is realized.
9310  *
9311  * Return value: %TRUE if a row exists at that coordinate.
9312  **/
9313 gboolean
9314 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
9315                                gint                x,
9316                                gint                y,
9317                                GtkTreePath       **path,
9318                                GtkTreeViewColumn **column,
9319                                gint               *cell_x,
9320                                gint               *cell_y)
9321 {
9322   GtkRBTree *tree;
9323   GtkRBNode *node;
9324   gint y_offset;
9325
9326   g_return_val_if_fail (tree_view != NULL, FALSE);
9327   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
9328
9329   if (path)
9330     *path = NULL;
9331   if (column)
9332     *column = NULL;
9333
9334   if (tree_view->priv->tree == NULL)
9335     return FALSE;
9336
9337   if (x > tree_view->priv->hadjustment->page_size)
9338     return FALSE;
9339
9340   if (x < 0 || y < 0)
9341     return FALSE;
9342
9343   if (column || cell_x)
9344     {
9345       GtkTreeViewColumn *tmp_column;
9346       GtkTreeViewColumn *last_column = NULL;
9347       GList *list;
9348       gint remaining_x = x;
9349       gboolean found = FALSE;
9350
9351       for (list = tree_view->priv->columns; list; list = list->next)
9352         {
9353           tmp_column = list->data;
9354
9355           if (tmp_column->visible == FALSE)
9356             continue;
9357
9358           last_column = tmp_column;
9359           if (remaining_x <= tmp_column->width)
9360             {
9361               found = TRUE;
9362
9363               if (column)
9364                 *column = tmp_column;
9365
9366               if (cell_x)
9367                 *cell_x = remaining_x;
9368
9369               break;
9370             }
9371           remaining_x -= tmp_column->width;
9372         }
9373
9374       if (!found)
9375         {
9376           if (column)
9377             *column = last_column;
9378
9379           if (cell_x)
9380             *cell_x = last_column->width + remaining_x;
9381         }
9382     }
9383
9384   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
9385                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
9386                                       &tree, &node);
9387
9388   if (tree == NULL)
9389     return FALSE;
9390
9391   if (cell_y)
9392     *cell_y = y_offset;
9393
9394   if (path)
9395     *path = _gtk_tree_view_find_path (tree_view, tree, node);
9396
9397   return TRUE;
9398 }
9399
9400
9401 /**
9402  * gtk_tree_view_get_cell_area:
9403  * @tree_view: a #GtkTreeView
9404  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
9405  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
9406  * @rect: rectangle to fill with cell rect
9407  *
9408  * Fills the bounding rectangle in tree window coordinates for the cell at the
9409  * row specified by @path and the column specified by @column.  If @path is
9410  * %NULL, or points to a path not currently displayed, the @y and @height fields
9411  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
9412  * fields will be filled with 0.  The sum of all cell rects does not cover the
9413  * entire tree; there are extra pixels in between rows, for example. The
9414  * returned rectangle is equivalent to the @cell_area passed to
9415  * gtk_cell_renderer_render().  This function is only valid if #tree_view is
9416  * realized.
9417  **/
9418 void
9419 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
9420                              GtkTreePath        *path,
9421                              GtkTreeViewColumn  *column,
9422                              GdkRectangle       *rect)
9423 {
9424   GtkRBTree *tree = NULL;
9425   GtkRBNode *node = NULL;
9426   gint vertical_separator;
9427   gint horizontal_separator;
9428
9429   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9430   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
9431   g_return_if_fail (rect != NULL);
9432   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
9433   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
9434
9435   gtk_widget_style_get (GTK_WIDGET (tree_view),
9436                         "vertical_separator", &vertical_separator,
9437                         "horizontal_separator", &horizontal_separator,
9438                         NULL);
9439
9440   rect->x = 0;
9441   rect->y = 0;
9442   rect->width = 0;
9443   rect->height = 0;
9444
9445   if (column)
9446     {
9447       rect->x = column->button->allocation.x + horizontal_separator/2;
9448       rect->width = column->button->allocation.width - horizontal_separator;
9449     }
9450
9451   if (path)
9452     {
9453       /* Get vertical coords */
9454       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
9455           tree == NULL)
9456         return;
9457
9458       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9459       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
9460
9461       if (gtk_tree_view_is_expander_column (tree_view, column) &&
9462           TREE_VIEW_DRAW_EXPANDERS (tree_view))
9463         {
9464           gint depth = gtk_tree_path_get_depth (path) - 1;
9465
9466           rect->x += depth * tree_view->priv->expander_size;
9467           rect->width -= depth * tree_view->priv->expander_size;
9468           rect->width = MAX (rect->width, 0);
9469         }
9470     }
9471 }
9472
9473 /**
9474  * gtk_tree_view_get_background_area:
9475  * @tree_view: a #GtkTreeView
9476  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
9477  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
9478  * @rect: rectangle to fill with cell background rect
9479  *
9480  * Fills the bounding rectangle in tree window coordinates for the cell at the
9481  * row specified by @path and the column specified by @column.  If @path is
9482  * %NULL, or points to a node not found in the tree, the @y and @height fields of
9483  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
9484  * fields will be filled with 0.  The returned rectangle is equivalent to the
9485  * @background_area passed to gtk_cell_renderer_render().  These background
9486  * areas tile to cover the entire tree window (except for the area used for
9487  * header buttons). Contrast with the @cell_area, returned by
9488  * gtk_tree_view_get_cell_area(), which returns only the cell itself, excluding
9489  * surrounding borders and the tree expander area.
9490  *
9491  **/
9492 void
9493 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
9494                                    GtkTreePath        *path,
9495                                    GtkTreeViewColumn  *column,
9496                                    GdkRectangle       *rect)
9497 {
9498   GtkRBTree *tree = NULL;
9499   GtkRBNode *node = NULL;
9500
9501   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9502   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
9503   g_return_if_fail (rect != NULL);
9504
9505   rect->x = 0;
9506   rect->y = 0;
9507   rect->width = 0;
9508   rect->height = 0;
9509
9510   if (path)
9511     {
9512       /* Get vertical coords */
9513
9514       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
9515           tree == NULL)
9516         return;
9517
9518       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9519
9520       rect->height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
9521     }
9522
9523   if (column)
9524     {
9525       gint x2 = 0;
9526
9527       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
9528       rect->width = x2 - rect->x;
9529     }
9530 }
9531
9532 /**
9533  * gtk_tree_view_get_visible_rect:
9534  * @tree_view: a #GtkTreeView
9535  * @visible_rect: rectangle to fill
9536  *
9537  * Fills @visible_rect with the currently-visible region of the
9538  * buffer, in tree coordinates. Convert to widget coordinates with
9539  * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
9540  * 0,0 for row 0 of the tree, and cover the entire scrollable area of
9541  * the tree.
9542  **/
9543 void
9544 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
9545                                 GdkRectangle *visible_rect)
9546 {
9547   GtkWidget *widget;
9548
9549   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9550
9551   widget = GTK_WIDGET (tree_view);
9552
9553   if (visible_rect)
9554     {
9555       visible_rect->x = tree_view->priv->hadjustment->value;
9556       visible_rect->y = tree_view->priv->vadjustment->value;
9557       visible_rect->width = widget->allocation.width;
9558       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
9559     }
9560 }
9561
9562 /**
9563  * gtk_tree_view_widget_to_tree_coords:
9564  * @tree_view: a #GtkTreeView
9565  * @wx: widget X coordinate
9566  * @wy: widget Y coordinate
9567  * @tx: return location for tree X coordinate
9568  * @ty: return location for tree Y coordinate
9569  *
9570  * Converts widget coordinates to coordinates for the
9571  * tree window (the full scrollable area of the tree).
9572  *
9573  **/
9574 void
9575 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
9576                                      gint         wx,
9577                                      gint         wy,
9578                                      gint        *tx,
9579                                      gint        *ty)
9580 {
9581   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9582
9583   if (tx)
9584     *tx = wx + tree_view->priv->hadjustment->value;
9585   if (ty)
9586     *ty = wy + tree_view->priv->dy;
9587 }
9588
9589 /**
9590  * gtk_tree_view_tree_to_widget_coords:
9591  * @tree_view: a #GtkTreeView
9592  * @tx: tree X coordinate
9593  * @ty: tree Y coordinate
9594  * @wx: return location for widget X coordinate
9595  * @wy: return location for widget Y coordinate
9596  *
9597  * Converts tree coordinates (coordinates in full scrollable area of the tree)
9598  * to widget coordinates.
9599  *
9600  **/
9601 void
9602 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
9603                                      gint         tx,
9604                                      gint         ty,
9605                                      gint        *wx,
9606                                      gint        *wy)
9607 {
9608   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9609
9610   if (wx)
9611     *wx = tx - tree_view->priv->hadjustment->value;
9612   if (wy)
9613     *wy = ty - tree_view->priv->dy;
9614 }
9615
9616 static void
9617 unset_reorderable (GtkTreeView *tree_view)
9618 {
9619   if (tree_view->priv->reorderable)
9620     {
9621       tree_view->priv->reorderable = FALSE;
9622       g_object_notify (G_OBJECT (tree_view), "reorderable");
9623     }
9624 }
9625
9626 void
9627 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
9628                                         GdkModifierType           start_button_mask,
9629                                         const GtkTargetEntry     *targets,
9630                                         gint                      n_targets,
9631                                         GdkDragAction             actions)
9632 {
9633   TreeViewDragInfo *di;
9634
9635   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9636
9637   di = ensure_info (tree_view);
9638   clear_source_info (di);
9639
9640   di->start_button_mask = start_button_mask;
9641   di->source_target_list = gtk_target_list_new (targets, n_targets);
9642   di->source_actions = actions;
9643
9644   di->source_set = TRUE;
9645
9646   unset_reorderable (tree_view);
9647 }
9648
9649 void
9650 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
9651                                       const GtkTargetEntry     *targets,
9652                                       gint                      n_targets,
9653                                       GdkDragAction             actions)
9654 {
9655   TreeViewDragInfo *di;
9656
9657   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9658
9659   gtk_drag_dest_set (GTK_WIDGET (tree_view),
9660                      0,
9661                      NULL,
9662                      0,
9663                      actions);
9664
9665   di = ensure_info (tree_view);
9666   clear_dest_info (di);
9667
9668   if (targets)
9669     di->dest_target_list = gtk_target_list_new (targets, n_targets);
9670
9671   di->dest_set = TRUE;
9672
9673   unset_reorderable (tree_view);
9674 }
9675
9676 void
9677 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
9678 {
9679   TreeViewDragInfo *di;
9680
9681   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9682
9683   di = get_info (tree_view);
9684
9685   if (di)
9686     {
9687       if (di->source_set)
9688         {
9689           clear_source_info (di);
9690           di->source_set = FALSE;
9691         }
9692
9693       if (!di->dest_set && !di->source_set)
9694         remove_info (tree_view);
9695     }
9696   
9697   unset_reorderable (tree_view);
9698 }
9699
9700 void
9701 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
9702 {
9703   TreeViewDragInfo *di;
9704
9705   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9706
9707   di = get_info (tree_view);
9708
9709   if (di)
9710     {
9711       if (di->dest_set)
9712         {
9713           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
9714           clear_dest_info (di);
9715           di->dest_set = FALSE;
9716         }
9717
9718       if (!di->dest_set && !di->source_set)
9719         remove_info (tree_view);
9720     }
9721
9722   unset_reorderable (tree_view);
9723 }
9724
9725 void
9726 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
9727                                  GtkTreePath            *path,
9728                                  GtkTreeViewDropPosition pos)
9729 {
9730   GtkTreePath *current_dest;
9731   /* Note; this function is exported to allow a custom DND
9732    * implementation, so it can't touch TreeViewDragInfo
9733    */
9734
9735   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9736
9737   current_dest = NULL;
9738
9739   if (tree_view->priv->drag_dest_row)
9740     current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
9741
9742   if (tree_view->priv->drag_dest_row)
9743     gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
9744
9745   tree_view->priv->drag_dest_pos = pos;
9746
9747   if (path)
9748     {
9749       tree_view->priv->drag_dest_row =
9750         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
9751       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
9752     }
9753   else
9754     tree_view->priv->drag_dest_row = NULL;
9755
9756   if (current_dest)
9757     {
9758       GtkRBTree *tree, *new_tree;
9759       GtkRBNode *node, *new_node;
9760
9761       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
9762       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
9763
9764       if (tree && node)
9765         {
9766           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
9767           if (new_tree && new_node)
9768             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
9769
9770           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
9771           if (new_tree && new_node)
9772             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
9773         }
9774       gtk_tree_path_free (current_dest);
9775     }
9776 }
9777
9778 void
9779 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
9780                                  GtkTreePath             **path,
9781                                  GtkTreeViewDropPosition  *pos)
9782 {
9783   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
9784
9785   if (path)
9786     {
9787       if (tree_view->priv->drag_dest_row)
9788         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
9789       else
9790         *path = NULL;
9791     }
9792
9793   if (pos)
9794     *pos = tree_view->priv->drag_dest_pos;
9795 }
9796
9797 gboolean
9798 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
9799                                    gint                     drag_x,
9800                                    gint                     drag_y,
9801                                    GtkTreePath            **path,
9802                                    GtkTreeViewDropPosition *pos)
9803 {
9804   gint cell_y;
9805   gdouble offset_into_row;
9806   gdouble third;
9807   GdkRectangle cell;
9808   GtkTreeViewColumn *column = NULL;
9809   GtkTreePath *tmp_path = NULL;
9810
9811   /* Note; this function is exported to allow a custom DND
9812    * implementation, so it can't touch TreeViewDragInfo
9813    */
9814
9815   g_return_val_if_fail (tree_view != NULL, FALSE);
9816   g_return_val_if_fail (drag_x >= 0, FALSE);
9817   g_return_val_if_fail (drag_y >= 0, FALSE);
9818   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
9819
9820
9821   if (path)
9822     *path = NULL;
9823
9824   if (tree_view->priv->tree == NULL)
9825     return FALSE;
9826
9827   /* If in the top third of a row, we drop before that row; if
9828    * in the bottom third, drop after that row; if in the middle,
9829    * and the row has children, drop into the row.
9830    */
9831
9832   if (!gtk_tree_view_get_path_at_pos (tree_view,
9833                                       drag_x,
9834                                       drag_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
9835                                       &tmp_path,
9836                                       &column,
9837                                       NULL,
9838                                       &cell_y))
9839     return FALSE;
9840
9841   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
9842                                      &cell);
9843
9844   offset_into_row = cell_y;
9845
9846   if (path)
9847     *path = tmp_path;
9848   else
9849     gtk_tree_path_free (tmp_path);
9850
9851   tmp_path = NULL;
9852
9853   third = cell.height / 3.0;
9854
9855   if (pos)
9856     {
9857       if (offset_into_row < third)
9858         {
9859           *pos = GTK_TREE_VIEW_DROP_BEFORE;
9860         }
9861       else if (offset_into_row < (cell.height / 2.0))
9862         {
9863           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
9864         }
9865       else if (offset_into_row < third * 2.0)
9866         {
9867           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
9868         }
9869       else
9870         {
9871           *pos = GTK_TREE_VIEW_DROP_AFTER;
9872         }
9873     }
9874
9875   return TRUE;
9876 }
9877
9878
9879
9880 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
9881 /**
9882  * gtk_tree_view_create_row_drag_icon:
9883  * @tree_view: a #GtkTreeView
9884  * @path: a #GtkTreePath in @tree_view
9885  *
9886  * Creates a #GdkPixmap representation of the row at @path.  This image is used
9887  * for a drag icon.
9888  *
9889  * Return value: a newly-allocated pixmap of the drag icon.
9890  **/
9891 GdkPixmap *
9892 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
9893                                     GtkTreePath  *path)
9894 {
9895   GtkTreeIter   iter;
9896   GtkRBTree    *tree;
9897   GtkRBNode    *node;
9898   gint cell_offset;
9899   GList *list;
9900   GdkRectangle background_area;
9901   GdkRectangle expose_area;
9902   GtkWidget *widget;
9903   gint depth;
9904   /* start drawing inside the black outline */
9905   gint x = 1, y = 1;
9906   GdkDrawable *drawable;
9907   gint bin_window_width;
9908
9909   widget = GTK_WIDGET (tree_view);
9910
9911   depth = gtk_tree_path_get_depth (path);
9912
9913   _gtk_tree_view_find_node (tree_view,
9914                             path,
9915                             &tree,
9916                             &node);
9917
9918   if (tree == NULL)
9919     return NULL;
9920
9921   if (!gtk_tree_model_get_iter (tree_view->priv->model,
9922                                 &iter,
9923                                 path))
9924     return NULL;
9925
9926   cell_offset = x;
9927
9928   background_area.y = y;
9929   background_area.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size);
9930
9931   gdk_drawable_get_size (tree_view->priv->bin_window,
9932                          &bin_window_width, NULL);
9933
9934   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
9935                              bin_window_width + 2,
9936                              background_area.height + 2,
9937                              -1);
9938
9939   expose_area.x = 0;
9940   expose_area.y = 0;
9941   expose_area.width = bin_window_width + 2;
9942   expose_area.height = background_area.height + 2;
9943
9944   gdk_draw_rectangle (drawable,
9945                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
9946                       TRUE,
9947                       0, 0,
9948                       bin_window_width + 2,
9949                       background_area.height + 2);
9950
9951   for (list = tree_view->priv->columns; list; list = list->next)
9952     {
9953       GtkTreeViewColumn *column = list->data;
9954       GdkRectangle cell_area;
9955       gint vertical_separator;
9956
9957       if (!column->visible)
9958         continue;
9959
9960       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
9961                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
9962                                                node->children?TRUE:FALSE);
9963
9964       background_area.x = cell_offset;
9965       background_area.width = column->width;
9966
9967       cell_area = background_area;
9968
9969       gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
9970       cell_area.y += vertical_separator / 2;
9971       cell_area.height -= vertical_separator;
9972
9973       if (gtk_tree_view_is_expander_column (tree_view, column) &&
9974           TREE_VIEW_DRAW_EXPANDERS(tree_view))
9975         {
9976           cell_area.x += depth * tree_view->priv->expander_size;
9977           cell_area.width -= depth * tree_view->priv->expander_size;
9978         }
9979
9980       if (gtk_tree_view_column_cell_is_visible (column))
9981         _gtk_tree_view_column_cell_render (column,
9982                                            drawable,
9983                                            &background_area,
9984                                            &cell_area,
9985                                            &expose_area,
9986                                            0);
9987       cell_offset += column->width;
9988     }
9989
9990   gdk_draw_rectangle (drawable,
9991                       widget->style->black_gc,
9992                       FALSE,
9993                       0, 0,
9994                       bin_window_width + 1,
9995                       background_area.height + 1);
9996
9997   return drawable;
9998 }
9999
10000
10001 /**
10002  * gtk_tree_view_set_destroy_count_func:
10003  * @tree_view: A #GtkTreeView
10004  * @func: Function to be called when a view row is destroyed, or %NULL
10005  * @data: User data to be passed to @func, or %NULL
10006  * @destroy: Destroy notifier for @data, or %NULL
10007  *
10008  * This function should almost never be used.  It is meant for private use by
10009  * ATK for determining the number of visible children that are removed when the
10010  * user collapses a row, or a row is deleted.
10011  **/
10012 void
10013 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
10014                                       GtkTreeDestroyCountFunc  func,
10015                                       gpointer                 data,
10016                                       GtkDestroyNotify         destroy)
10017 {
10018   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10019
10020   if (tree_view->priv->destroy_count_destroy)
10021     (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
10022
10023   tree_view->priv->destroy_count_func = func;
10024   tree_view->priv->destroy_count_data = data;
10025   tree_view->priv->destroy_count_destroy = destroy;
10026 }
10027
10028
10029 /*
10030  * Interactive search
10031  */
10032
10033 /**
10034  * gtk_tree_view_set_enable_search:
10035  * @tree_view: A #GtkTreeView
10036  * @enable_search: %TRUE, if the user can search interactively
10037  *
10038  * If @enable_search is set, then the user can type in text to search through
10039  * the tree interactively.
10040  */
10041 void
10042 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
10043                                  gboolean     enable_search)
10044 {
10045   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10046
10047   enable_search = !!enable_search;
10048   
10049   if (tree_view->priv->enable_search != enable_search)
10050     {
10051        tree_view->priv->enable_search = enable_search;
10052        g_object_notify (G_OBJECT (tree_view), "enable_search");
10053     }
10054 }
10055
10056 /**
10057  * gtk_tree_view_get_enable_search:
10058  * @tree_view: A #GtkTreeView
10059  *
10060  * Returns whether or not the tree allows interactive searching.
10061  *
10062  * Return value: whether or not to let the user search interactively
10063  */
10064 gboolean
10065 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
10066 {
10067   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10068
10069   return tree_view->priv->enable_search;
10070 }
10071
10072
10073 /**
10074  * gtk_tree_view_get_search_column:
10075  * @tree_view: A #GtkTreeView
10076  *
10077  * Gets the column searched on by the interactive search code.
10078  *
10079  * Return value: the column the interactive search code searches in.
10080  */
10081 gint
10082 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
10083 {
10084   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
10085
10086   return (tree_view->priv->search_column);
10087 }
10088
10089 /**
10090  * gtk_tree_view_set_search_column:
10091  * @tree_view: A #GtkTreeView
10092  * @column: the column to search in
10093  *
10094  * Sets @column as the column where the interactive search code should search
10095  * in.  Additionally, turns on interactive searching.
10096  */
10097 void
10098 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
10099                                  gint         column)
10100 {
10101   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10102   g_return_if_fail (column >= 0);
10103
10104   if (tree_view->priv->search_column == column)
10105     return;
10106
10107   tree_view->priv->search_column = column;
10108   g_object_notify (G_OBJECT (tree_view), "search_column");
10109 }
10110
10111 /**
10112  * gtk_tree_view_get_search_equal_func:
10113  * @tree_view: A #GtkTreeView
10114  *
10115  * Returns the compare function currently in use.
10116  *
10117  * Return value: the currently used compare function for the search code.
10118  */
10119
10120 GtkTreeViewSearchEqualFunc
10121 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
10122 {
10123   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10124
10125   return tree_view->priv->search_equal_func;
10126 }
10127
10128 /**
10129  * gtk_tree_view_set_search_equal_func:
10130  * @tree_view: A #GtkTreeView
10131  * @search_equal_func: the compare function to use during the search
10132  * @search_user_data: user data to pass to @search_equal_func, or %NULL
10133  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
10134  *
10135  * Sets the compare function for the interactive search capabilities.
10136  **/
10137 void
10138 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
10139                                      GtkTreeViewSearchEqualFunc  search_equal_func,
10140                                      gpointer                    search_user_data,
10141                                      GtkDestroyNotify            search_destroy)
10142 {
10143   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10144   g_return_if_fail (search_equal_func !=NULL);
10145
10146   if (tree_view->priv->search_destroy)
10147     (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
10148
10149   tree_view->priv->search_equal_func = search_equal_func;
10150   tree_view->priv->search_user_data = search_user_data;
10151   tree_view->priv->search_destroy = search_destroy;
10152   if (tree_view->priv->search_equal_func == NULL)
10153     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
10154 }
10155
10156 static void
10157 gtk_tree_view_search_dialog_destroy (GtkWidget   *search_dialog,
10158                                      GtkTreeView *tree_view)
10159 {
10160   GtkEntry *entry = (GtkEntry *)(gtk_container_get_children (GTK_CONTAINER (search_dialog)))->data;
10161   gint *selected_iter;
10162
10163   if (tree_view->priv->disable_popdown)
10164     return;
10165
10166   if (entry)
10167     {
10168       GdkEventFocus focus_event;
10169
10170       focus_event.type = GDK_FOCUS_CHANGE;
10171       focus_event.in = FALSE;
10172       gtk_widget_event (GTK_WIDGET (entry), (GdkEvent *) &focus_event);
10173     }
10174
10175   /* remove data from tree_view */
10176   g_object_set_data (G_OBJECT (tree_view), GTK_TREE_VIEW_SEARCH_DIALOG_KEY,
10177                      NULL);
10178
10179   selected_iter = g_object_get_data (G_OBJECT (search_dialog),
10180                                      "gtk-tree-view-selected-iter");
10181   if (selected_iter)
10182     g_free (selected_iter);
10183   g_object_set_data (G_OBJECT (search_dialog), "gtk-tree-view-selected-iter",
10184                      NULL);
10185
10186   gtk_widget_destroy (search_dialog);
10187 }
10188
10189 static void
10190 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
10191                                     GtkWidget   *search_dialog)
10192 {
10193   gint x, y;
10194   gint tree_x, tree_y;
10195   gint tree_width, tree_height;
10196   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
10197   GtkRequisition requisition;
10198
10199   gtk_widget_realize (search_dialog);
10200
10201   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
10202   gdk_window_get_size (tree_window,
10203                        &tree_width,
10204                        &tree_height);
10205   gtk_widget_size_request (search_dialog, &requisition);
10206
10207   if (tree_x + tree_width - requisition.width > gdk_screen_width ())
10208     x = gdk_screen_width () - requisition.width;
10209   else if (tree_x + tree_width - requisition.width < 0)
10210     x = 0;
10211   else
10212     x = tree_x + tree_width - requisition.width;
10213
10214   if (tree_y + tree_height > gdk_screen_height ())
10215     y = gdk_screen_height () - requisition.height;
10216   else if (tree_y + tree_height < 0) /* isn't really possible ... */
10217     y = 0;
10218   else
10219     y = tree_y + tree_height;
10220
10221   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
10222 }
10223
10224 static void
10225 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
10226                                       GtkMenu  *menu,
10227                                       gpointer  data)
10228 {
10229   GtkTreeView *tree_view = (GtkTreeView *)data;
10230
10231   tree_view->priv->disable_popdown = 1;
10232   g_signal_connect (G_OBJECT (menu), "hide",
10233                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
10234 }
10235
10236 static gboolean
10237 gtk_tree_view_real_search_enable_popdown (gpointer data)
10238 {
10239   GtkTreeView *tree_view = (GtkTreeView *)data;
10240
10241   GDK_THREADS_ENTER ();
10242
10243   tree_view->priv->disable_popdown = 0;
10244
10245   GDK_THREADS_LEAVE ();
10246
10247   return FALSE;
10248 }
10249
10250 static void
10251 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
10252                                      gpointer   data)
10253 {
10254   g_timeout_add (200, gtk_tree_view_real_search_enable_popdown, data);
10255 }
10256
10257 static gboolean
10258 gtk_tree_view_search_delete_event (GtkWidget *widget,
10259                                    GdkEventAny *event,
10260                                    GtkTreeView *tree_view)
10261 {
10262   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
10263
10264   gtk_tree_view_search_dialog_destroy (widget, tree_view);
10265
10266   return TRUE;
10267 }
10268
10269 static gboolean
10270 gtk_tree_view_search_button_press_event (GtkWidget *widget,
10271                                          GdkEventButton *event,
10272                                          GtkTreeView *tree_view)
10273 {
10274   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
10275
10276   gtk_tree_view_search_dialog_destroy (widget, tree_view);
10277
10278   return TRUE;
10279 }
10280
10281 static gboolean
10282 gtk_tree_view_search_key_press_event (GtkWidget *widget,
10283                                       GdkEventKey *event,
10284                                       GtkTreeView *tree_view)
10285 {
10286   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
10287   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10288
10289   /* close window */
10290   if (event->keyval == GDK_Escape ||
10291       event->keyval == GDK_Return ||
10292       event->keyval == GDK_Tab)
10293     {
10294       gtk_tree_view_search_dialog_destroy (widget, tree_view);
10295       return TRUE;
10296     }
10297
10298   /* select previous matching iter */
10299   if (event->keyval == GDK_Up)
10300     {
10301       gtk_tree_view_search_move (widget, tree_view, TRUE);
10302       return TRUE;
10303     }
10304
10305   /* select next matching iter */
10306   if (event->keyval == GDK_Down)
10307     {
10308       gtk_tree_view_search_move (widget, tree_view, FALSE);
10309       return TRUE;
10310     }
10311
10312   return FALSE;
10313 }
10314
10315 static void
10316 gtk_tree_view_search_move (GtkWidget   *window,
10317                            GtkTreeView *tree_view,
10318                            gboolean     up)
10319 {
10320   gboolean ret;
10321   gint *selected_iter;
10322   gint len;
10323   gint count = 0;
10324   gchar *text;
10325   GtkTreeIter iter;
10326   GtkTreeModel *model;
10327   GtkTreeSelection *selection;
10328
10329   text = g_object_get_data (G_OBJECT (window), "gtk-tree-view-text");
10330   selected_iter = g_object_get_data (G_OBJECT (window), "gtk-tree-view-selected-iter");
10331
10332   g_return_if_fail (text != NULL);
10333
10334   if (!selected_iter || (up && *selected_iter == 1))
10335     return;
10336
10337   len = strlen (text);
10338
10339   if (len < 1)
10340     return;
10341
10342   model = gtk_tree_view_get_model (tree_view);
10343   selection = gtk_tree_view_get_selection (tree_view);
10344
10345   /* search */
10346   gtk_tree_selection_unselect_all (selection);
10347   gtk_tree_model_get_iter_first (model, &iter);
10348
10349   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
10350                                    &count, up?((*selected_iter) - 1):((*selected_iter + 1)));
10351
10352   if (ret)
10353     {
10354       /* found */
10355       *selected_iter += up?(-1):(1);
10356     }
10357   else
10358     {
10359       /* return to old iter */
10360       count = 0;
10361       gtk_tree_model_get_iter_first (model, &iter);
10362       gtk_tree_view_search_iter (model, selection,
10363                                  &iter, text,
10364                                  &count, *selected_iter);
10365     }
10366 }
10367
10368 static gboolean
10369 gtk_tree_view_search_equal_func (GtkTreeModel *model,
10370                                  gint          column,
10371                                  const gchar  *key,
10372                                  GtkTreeIter  *iter,
10373                                  gpointer      search_data)
10374 {
10375   gboolean retval = TRUE;
10376   gchar *normalized_string;
10377   gchar *normalized_key;
10378   gchar *case_normalized_string;
10379   gchar *case_normalized_key;
10380   GValue value = {0,};
10381   gint key_len;
10382
10383   gtk_tree_model_get_value (model, iter, column, &value);
10384   normalized_string = g_utf8_normalize (g_value_get_string (&value), -1, G_NORMALIZE_ALL);
10385   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
10386   case_normalized_string = g_utf8_casefold (normalized_string, -1);
10387   case_normalized_key = g_utf8_casefold (normalized_key, -1);
10388
10389   key_len = strlen (case_normalized_key);
10390
10391   if (!strncmp (case_normalized_key, case_normalized_string, key_len))
10392     retval = FALSE;
10393
10394   g_value_unset (&value);
10395   g_free (normalized_key);
10396   g_free (normalized_string);
10397   g_free (case_normalized_key);
10398   g_free (case_normalized_string);
10399
10400   return retval;
10401 }
10402
10403 static gboolean
10404 gtk_tree_view_search_iter (GtkTreeModel     *model,
10405                            GtkTreeSelection *selection,
10406                            GtkTreeIter      *iter,
10407                            const gchar      *text,
10408                            gint             *count,
10409                            gint              n)
10410 {
10411   GtkRBTree *tree = NULL;
10412   GtkRBNode *node = NULL;
10413   GtkTreePath *path;
10414
10415   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
10416   GtkTreeViewColumn *column =
10417     gtk_tree_view_get_column (tree_view, tree_view->priv->search_column);
10418
10419   path = gtk_tree_model_get_path (model, iter);
10420   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
10421
10422   do
10423     {
10424       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
10425         {
10426           (*count)++;
10427           if (*count == n)
10428             {
10429               gtk_tree_view_scroll_to_cell (tree_view, path, column,
10430                                             TRUE, 0.5, 0.5);
10431               gtk_tree_selection_select_iter (selection, iter);
10432               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
10433
10434               if (path)
10435                 gtk_tree_path_free (path);
10436
10437               return TRUE;
10438             }
10439         }
10440
10441       if (node->children)
10442         {
10443           gboolean has_child;
10444           GtkTreeIter tmp;
10445
10446           tree = node->children;
10447           node = tree->root;
10448
10449           while (node->left != tree->nil)
10450             node = node->left;
10451
10452           tmp = *iter;
10453           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
10454           gtk_tree_path_down (path);
10455
10456           /* sanity check */
10457           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
10458         }
10459       else
10460         {
10461           gboolean done = FALSE;
10462
10463           do
10464             {
10465               node = _gtk_rbtree_next (tree, node);
10466
10467               if (node)
10468                 {
10469                   gboolean has_next;
10470
10471                   has_next = gtk_tree_model_iter_next (model, iter);
10472
10473                   done = TRUE;
10474                   gtk_tree_path_next (path);
10475
10476                   /* sanity check */
10477                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
10478                 }
10479               else
10480                 {
10481                   gboolean has_parent;
10482                   GtkTreeIter tmp_iter = *iter;
10483
10484                   node = tree->parent_node;
10485                   tree = tree->parent_tree;
10486
10487                   if (!tree)
10488                     {
10489                       if (path)
10490                         gtk_tree_path_free (path);
10491
10492                       /* we've run out of tree, done with this func */
10493                       return FALSE;
10494                     }
10495
10496                   has_parent = gtk_tree_model_iter_parent (model,
10497                                                            iter,
10498                                                            &tmp_iter);
10499                   gtk_tree_path_up (path);
10500
10501                   /* sanity check */
10502                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
10503                 }
10504             }
10505           while (!done);
10506         }
10507     }
10508   while (1);
10509
10510   if (path)
10511     gtk_tree_path_free (path);
10512
10513   return FALSE;
10514 }
10515
10516 static void
10517 gtk_tree_view_search_init (GtkWidget   *entry,
10518                            GtkTreeView *tree_view)
10519 {
10520   gint ret;
10521   gint *selected_iter;
10522   gint len;
10523   gint count = 0;
10524   const gchar *text;
10525   GtkWidget *window;
10526   GtkTreeIter iter;
10527   GtkTreeModel *model;
10528   GtkTreeSelection *selection;
10529
10530   g_return_if_fail (GTK_IS_ENTRY (entry));
10531   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10532
10533   window = gtk_widget_get_parent (entry);
10534   text = gtk_entry_get_text (GTK_ENTRY (entry));
10535   len = strlen (text);
10536   model = gtk_tree_view_get_model (tree_view);
10537   selection = gtk_tree_view_get_selection (tree_view);
10538
10539   /* search */
10540   gtk_tree_selection_unselect_all (selection);
10541   selected_iter = g_object_get_data (G_OBJECT (window), "gtk-tree-view-selected-iter");
10542   if (selected_iter)
10543     g_free (selected_iter);
10544   g_object_set_data (G_OBJECT (window), "gtk-tree-view-selected-iter", NULL);
10545
10546   if (len < 1)
10547     return;
10548
10549   gtk_tree_model_get_iter_first (model, &iter);
10550
10551   ret = gtk_tree_view_search_iter (model, selection,
10552                                    &iter, text,
10553                                    &count, 1);
10554
10555   if (ret)
10556     {
10557       selected_iter = g_malloc (sizeof (int));
10558       *selected_iter = 1;
10559       g_object_set_data (G_OBJECT (window), "gtk-tree-view-selected-iter",
10560                          selected_iter);
10561     }
10562 }
10563
10564 static void
10565 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
10566                              GtkTreeView     *tree_view)
10567 {
10568   if (tree_view->priv->edited_column == NULL)
10569     return;
10570
10571   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
10572   tree_view->priv->edited_column = NULL;
10573
10574   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10575
10576   gtk_container_remove (GTK_CONTAINER (tree_view),
10577                         GTK_WIDGET (cell_editable));
10578 }
10579
10580 static gboolean
10581 gtk_tree_view_start_editing (GtkTreeView *tree_view,
10582                              GtkTreePath *cursor_path)
10583 {
10584   GtkTreeIter iter;
10585   GdkRectangle background_area;
10586   GdkRectangle cell_area;
10587   GtkCellEditable *editable_widget = NULL;
10588   gchar *path_string;
10589   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
10590   gint retval = FALSE;
10591   GtkRBTree *cursor_tree;
10592   GtkRBNode *cursor_node;
10593
10594   g_assert (tree_view->priv->focus_column);
10595
10596   if (! GTK_WIDGET_REALIZED (tree_view))
10597     return FALSE;
10598
10599   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
10600       cursor_node == NULL)
10601     return FALSE;
10602
10603   path_string = gtk_tree_path_to_string (cursor_path);
10604   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
10605
10606   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
10607
10608   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10609                                            tree_view->priv->model,
10610                                            &iter,
10611                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10612                                            cursor_node->children?TRUE:FALSE);
10613   gtk_tree_view_get_background_area (tree_view,
10614                                      cursor_path,
10615                                      tree_view->priv->focus_column,
10616                                      &background_area);
10617   gtk_tree_view_get_cell_area (tree_view,
10618                                cursor_path,
10619                                tree_view->priv->focus_column,
10620                                &cell_area);
10621   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
10622                                         &editable_widget,
10623                                         NULL,
10624                                         path_string,
10625                                         &background_area,
10626                                         &cell_area,
10627                                         flags))
10628     {
10629       retval = TRUE;
10630       if (editable_widget != NULL)
10631         {
10632           gtk_tree_view_real_start_editing (tree_view,
10633                                             tree_view->priv->focus_column,
10634                                             cursor_path,
10635                                             editable_widget,
10636                                             &cell_area,
10637                                             NULL,
10638                                             flags);
10639         }
10640
10641     }
10642   g_free (path_string);
10643   return retval;
10644 }
10645
10646 static void
10647 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
10648                                   GtkTreeViewColumn *column,
10649                                   GtkTreePath       *path,
10650                                   GtkCellEditable   *cell_editable,
10651                                   GdkRectangle      *cell_area,
10652                                   GdkEvent          *event,
10653                                   guint              flags)
10654 {
10655   gint pre_val = tree_view->priv->vadjustment->value;
10656
10657   tree_view->priv->edited_column = column;
10658   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
10659
10660   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
10661
10662   cell_area->y += pre_val - tree_view->priv->vadjustment->value;
10663
10664   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
10665   gtk_tree_view_put (tree_view,
10666                      GTK_WIDGET (cell_editable),
10667                      cell_area->x, cell_area->y, cell_area->width, cell_area->height);
10668   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
10669                                    (GdkEvent *)event);
10670   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
10671   g_signal_connect (cell_editable, "remove_widget", G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
10672 }
10673
10674 static void
10675 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
10676                             gboolean     cancel_editing)
10677 {
10678   GtkTreeViewColumn *column;
10679
10680   if (tree_view->priv->edited_column == NULL)
10681     return;
10682
10683   /*
10684    * This is very evil. We need to do this, because
10685    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
10686    * later on. If gtk_tree_view_row_changed notices
10687    * tree_view->priv->edited_column != NULL, it'll call
10688    * gtk_tree_view_stop_editing again. Bad things will happen then.
10689    *
10690    * Please read that again if you intend to modify anything here.
10691    */
10692
10693   column = tree_view->priv->edited_column;
10694   tree_view->priv->edited_column = NULL;
10695
10696   if (! cancel_editing)
10697     gtk_cell_editable_editing_done (column->editable_widget);
10698
10699   tree_view->priv->edited_column = column;
10700
10701   gtk_cell_editable_remove_widget (column->editable_widget);
10702 }