]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
fully initialize GdkWindowAttr to avoid valgrind warnings. (#507751, patch
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include <config.h>
22 #include <string.h>
23 #include <gdk/gdkkeysyms.h>
24
25 #include "gtktreeview.h"
26 #include "gtkrbtree.h"
27 #include "gtktreednd.h"
28 #include "gtktreeprivate.h"
29 #include "gtkcellrenderer.h"
30 #include "gtkmain.h"
31 #include "gtkmarshalers.h"
32 #include "gtkbuildable.h"
33 #include "gtkbutton.h"
34 #include "gtkalignment.h"
35 #include "gtklabel.h"
36 #include "gtkhbox.h"
37 #include "gtkvbox.h"
38 #include "gtkarrow.h"
39 #include "gtkintl.h"
40 #include "gtkbindings.h"
41 #include "gtkcontainer.h"
42 #include "gtkentry.h"
43 #include "gtkframe.h"
44 #include "gtktreemodelsort.h"
45 #include "gtktooltip.h"
46 #include "gtkprivate.h"
47 #include "gtkalias.h"
48
49 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
50 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
51 #define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 500
52 #define SCROLL_EDGE_SIZE 15
53 #define EXPANDER_EXTRA_PADDING 4
54 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
55 #define AUTO_EXPAND_TIMEOUT 500
56
57 /* The "background" areas of all rows/cells add up to cover the entire tree.
58  * The background includes all inter-row and inter-cell spacing.
59  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
60  * i.e. just the cells, no spacing.
61  */
62
63 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
64 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
65
66 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
67  * vice versa.
68  */
69 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
70 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
71
72 /* This is in bin_window coordinates */
73 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
74 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
75
76 #define ROW_HEIGHT(tree_view,height) \
77   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
78
79
80 typedef struct _GtkTreeViewChild GtkTreeViewChild;
81 struct _GtkTreeViewChild
82 {
83   GtkWidget *widget;
84   gint x;
85   gint y;
86   gint width;
87   gint height;
88 };
89
90
91 typedef struct _TreeViewDragInfo TreeViewDragInfo;
92 struct _TreeViewDragInfo
93 {
94   GdkModifierType start_button_mask;
95   GtkTargetList *source_target_list;
96   GdkDragAction source_actions;
97
98   GtkTargetList *dest_target_list;
99
100   guint source_set : 1;
101   guint dest_set : 1;
102 };
103
104
105 /* Signals */
106 enum
107 {
108   ROW_ACTIVATED,
109   TEST_EXPAND_ROW,
110   TEST_COLLAPSE_ROW,
111   ROW_EXPANDED,
112   ROW_COLLAPSED,
113   COLUMNS_CHANGED,
114   CURSOR_CHANGED,
115   MOVE_CURSOR,
116   SELECT_ALL,
117   UNSELECT_ALL,
118   SELECT_CURSOR_ROW,
119   TOGGLE_CURSOR_ROW,
120   EXPAND_COLLAPSE_CURSOR_ROW,
121   SELECT_CURSOR_PARENT,
122   START_INTERACTIVE_SEARCH,
123   LAST_SIGNAL
124 };
125
126 /* Properties */
127 enum {
128   PROP_0,
129   PROP_MODEL,
130   PROP_HADJUSTMENT,
131   PROP_VADJUSTMENT,
132   PROP_HEADERS_VISIBLE,
133   PROP_HEADERS_CLICKABLE,
134   PROP_EXPANDER_COLUMN,
135   PROP_REORDERABLE,
136   PROP_RULES_HINT,
137   PROP_ENABLE_SEARCH,
138   PROP_SEARCH_COLUMN,
139   PROP_FIXED_HEIGHT_MODE,
140   PROP_HOVER_SELECTION,
141   PROP_HOVER_EXPAND,
142   PROP_SHOW_EXPANDERS,
143   PROP_LEVEL_INDENTATION,
144   PROP_RUBBER_BANDING,
145   PROP_ENABLE_GRID_LINES,
146   PROP_ENABLE_TREE_LINES,
147   PROP_TOOLTIP_COLUMN
148 };
149
150 /* object signals */
151 static void     gtk_tree_view_finalize             (GObject          *object);
152 static void     gtk_tree_view_set_property         (GObject         *object,
153                                                     guint            prop_id,
154                                                     const GValue    *value,
155                                                     GParamSpec      *pspec);
156 static void     gtk_tree_view_get_property         (GObject         *object,
157                                                     guint            prop_id,
158                                                     GValue          *value,
159                                                     GParamSpec      *pspec);
160
161 /* gtkobject signals */
162 static void     gtk_tree_view_destroy              (GtkObject        *object);
163
164 /* gtkwidget signals */
165 static void     gtk_tree_view_realize              (GtkWidget        *widget);
166 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
167 static void     gtk_tree_view_map                  (GtkWidget        *widget);
168 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
169                                                     GtkRequisition   *requisition);
170 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
171                                                     GtkAllocation    *allocation);
172 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
173                                                     GdkEventExpose   *event);
174 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
175                                                     GdkEventKey      *event);
176 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
177                                                     GdkEventKey      *event);
178 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
179                                                     GdkEventMotion   *event);
180 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
181                                                     GdkEventCrossing *event);
182 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
183                                                     GdkEventCrossing *event);
184 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
185                                                     GdkEventButton   *event);
186 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
187                                                     GdkEventButton   *event);
188 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
189                                                     GdkEventGrabBroken *event);
190 #if 0
191 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
192                                                     GdkEventConfigure *event);
193 #endif
194
195 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
196                                                     GtkWidget        *child);
197 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
198                                                     GdkEventFocus    *event);
199 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
200                                                     GtkDirectionType  direction);
201 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
202 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
203                                                     GtkStyle         *previous_style);
204 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
205                                                     gboolean          was_grabbed);
206 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
207                                                     GtkStateType      previous_state);
208
209 /* container signals */
210 static void     gtk_tree_view_remove               (GtkContainer     *container,
211                                                     GtkWidget        *widget);
212 static void     gtk_tree_view_forall               (GtkContainer     *container,
213                                                     gboolean          include_internals,
214                                                     GtkCallback       callback,
215                                                     gpointer          callback_data);
216
217 /* Source side drag signals */
218 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
219                                             GdkDragContext   *context);
220 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
221                                             GdkDragContext   *context);
222 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
223                                             GdkDragContext   *context,
224                                             GtkSelectionData *selection_data,
225                                             guint             info,
226                                             guint             time);
227 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
228                                             GdkDragContext   *context);
229
230 /* Target side drag signals */
231 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
232                                                   GdkDragContext   *context,
233                                                   guint             time);
234 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
235                                                   GdkDragContext   *context,
236                                                   gint              x,
237                                                   gint              y,
238                                                   guint             time);
239 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
240                                                   GdkDragContext   *context,
241                                                   gint              x,
242                                                   gint              y,
243                                                   guint             time);
244 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
245                                                   GdkDragContext   *context,
246                                                   gint              x,
247                                                   gint              y,
248                                                   GtkSelectionData *selection_data,
249                                                   guint             info,
250                                                   guint             time);
251
252 /* tree_model signals */
253 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
254                                                            GtkAdjustment   *hadj,
255                                                            GtkAdjustment   *vadj);
256 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
257                                                            GtkMovementStep  step,
258                                                            gint             count);
259 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
260 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
261 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
262                                                            gboolean         start_editing);
263 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
264 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
265                                                                gboolean         logical,
266                                                                gboolean         expand,
267                                                                gboolean         open_all);
268 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
269 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
270                                                            GtkTreePath     *path,
271                                                            GtkTreeIter     *iter,
272                                                            gpointer         data);
273 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
274                                                            GtkTreePath     *path,
275                                                            GtkTreeIter     *iter,
276                                                            gpointer         data);
277 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
278                                                            GtkTreePath     *path,
279                                                            GtkTreeIter     *iter,
280                                                            gpointer         data);
281 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
282                                                            GtkTreePath     *path,
283                                                            gpointer         data);
284 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
285                                                            GtkTreePath     *parent,
286                                                            GtkTreeIter     *iter,
287                                                            gint            *new_order,
288                                                            gpointer         data);
289
290 /* Incremental reflow */
291 static gboolean validate_row             (GtkTreeView *tree_view,
292                                           GtkRBTree   *tree,
293                                           GtkRBNode   *node,
294                                           GtkTreeIter *iter,
295                                           GtkTreePath *path);
296 static void     validate_visible_area    (GtkTreeView *tree_view);
297 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
298 static gboolean do_validate_rows         (GtkTreeView *tree_view,
299                                           gboolean     size_request);
300 static gboolean validate_rows            (GtkTreeView *tree_view);
301 static gboolean presize_handler_callback (gpointer     data);
302 static void     install_presize_handler  (GtkTreeView *tree_view);
303 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
304 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
305                                              GtkTreePath *path,
306                                              gint         offset);
307 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
308 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
309 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
310
311 /* Internal functions */
312 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView       *tree_view,
313                                                               GtkTreeViewColumn *column);
314 static void     gtk_tree_view_add_move_binding               (GtkBindingSet     *binding_set,
315                                                               guint              keyval,
316                                                               guint              modmask,
317                                                               gboolean           add_shifted_binding,
318                                                               GtkMovementStep    step,
319                                                               gint               count);
320 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView       *tree_view,
321                                                               GtkRBTree         *tree);
322 static void     gtk_tree_view_queue_draw_path                (GtkTreeView       *tree_view,
323                                                               GtkTreePath       *path,
324                                                               GdkRectangle      *clip_rect);
325 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView       *tree_view,
326                                                               GtkRBTree         *tree,
327                                                               GtkRBNode         *node,
328                                                               GdkRectangle      *clip_rect);
329 static void     gtk_tree_view_draw_arrow                     (GtkTreeView       *tree_view,
330                                                               GtkRBTree         *tree,
331                                                               GtkRBNode         *node,
332                                                               gint               x,
333                                                               gint               y);
334 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView       *tree_view,
335                                                               GtkRBTree         *tree,
336                                                               gint              *x1,
337                                                               gint              *x2);
338 static gint     gtk_tree_view_new_column_width               (GtkTreeView       *tree_view,
339                                                               gint               i,
340                                                               gint              *x);
341 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment     *adjustment,
342                                                               GtkTreeView       *tree_view);
343 static void     gtk_tree_view_build_tree                     (GtkTreeView       *tree_view,
344                                                               GtkRBTree         *tree,
345                                                               GtkTreeIter       *iter,
346                                                               gint               depth,
347                                                               gboolean           recurse);
348 static gboolean gtk_tree_view_discover_dirty_iter            (GtkTreeView       *tree_view,
349                                                               GtkTreeIter       *iter,
350                                                               gint               depth,
351                                                               gint              *height,
352                                                               GtkRBNode         *node);
353 static void     gtk_tree_view_discover_dirty                 (GtkTreeView       *tree_view,
354                                                               GtkRBTree         *tree,
355                                                               GtkTreeIter       *iter,
356                                                               gint               depth);
357 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView       *tree_view,
358                                                               GtkRBTree         *tree,
359                                                               GtkRBNode         *node);
360 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView       *tree_view,
361                                                               GtkTreeViewColumn *column,
362                                                               gboolean           focus_to_cell);
363 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView       *tree_view,
364                                                               GdkEventMotion    *event);
365 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView       *tree_view);
366 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView       *tree_view,
367                                                               gint               count);
368 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView       *tree_view,
369                                                               gint               count);
370 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView       *tree_view,
371                                                               gint               count);
372 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView       *tree_view,
373                                                               gint               count);
374 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView       *tree_view,
375                                                               GtkTreePath       *path,
376                                                               GtkRBTree         *tree,
377                                                               GtkRBNode         *node,
378                                                               gboolean           animate);
379 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView       *tree_view,
380                                                               GtkTreePath       *path,
381                                                               GtkRBTree         *tree,
382                                                               GtkRBNode         *node,
383                                                               gboolean           open_all,
384                                                               gboolean           animate);
385 static void     gtk_tree_view_real_set_cursor                (GtkTreeView       *tree_view,
386                                                               GtkTreePath       *path,
387                                                               gboolean           clear_and_select,
388                                                               gboolean           clamp_node);
389 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView       *tree_view);
390 static void     column_sizing_notify                         (GObject           *object,
391                                                               GParamSpec        *pspec,
392                                                               gpointer           data);
393 static gboolean expand_collapse_timeout                      (gpointer           data);
394 static gboolean do_expand_collapse                           (GtkTreeView       *tree_view);
395 static void     gtk_tree_view_stop_rubber_band                (GtkTreeView       *tree_view);
396
397 /* interactive search */
398 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
399 static void     gtk_tree_view_search_dialog_hide     (GtkWidget        *search_dialog,
400                                                          GtkTreeView      *tree_view);
401 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
402                                                          GtkWidget        *search_dialog,
403                                                          gpointer          user_data);
404 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
405                                                          GtkMenu          *menu,
406                                                          gpointer          data);
407 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
408                                                          GtkTreeView      *tree_view);
409 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
410                                                          GtkTreeView      *tree_view);
411 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
412 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
413                                                          gpointer          data);
414 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
415                                                          GdkEventAny      *event,
416                                                          GtkTreeView      *tree_view);
417 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
418                                                          GdkEventButton   *event,
419                                                          GtkTreeView      *tree_view);
420 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
421                                                          GdkEventScroll   *event,
422                                                          GtkTreeView      *tree_view);
423 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
424                                                          GdkEventKey      *event,
425                                                          GtkTreeView      *tree_view);
426 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
427                                                          GtkTreeView      *tree_view,
428                                                          gboolean          up);
429 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
430                                                          gint              column,
431                                                          const gchar      *key,
432                                                          GtkTreeIter      *iter,
433                                                          gpointer          search_data);
434 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
435                                                          GtkTreeSelection *selection,
436                                                          GtkTreeIter      *iter,
437                                                          const gchar      *text,
438                                                          gint             *count,
439                                                          gint              n);
440 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
441                                                          GtkTreeView      *tree_view);
442 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
443                                                          GtkWidget        *child_widget,
444                                                          gint              x,
445                                                          gint              y,
446                                                          gint              width,
447                                                          gint              height);
448 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
449                                                          GtkTreePath      *cursor_path);
450 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
451                                               GtkTreeViewColumn *column,
452                                               GtkTreePath       *path,
453                                               GtkCellEditable   *cell_editable,
454                                               GdkRectangle      *cell_area,
455                                               GdkEvent          *event,
456                                               guint              flags);
457 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
458                                                          gboolean     cancel_editing);
459 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
460                                                              gboolean     keybinding);
461 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
462 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
463                                                          GtkTreeViewColumn *column,
464                                                          gint               drop_position);
465
466 /* GtkBuildable */
467 static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
468                                                GtkBuilder  *builder,
469                                                GObject     *child,
470                                                const gchar *type);
471 static void gtk_tree_view_buildable_init      (GtkBuildableIface *iface);
472
473
474 static gboolean scroll_row_timeout                   (gpointer     data);
475 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
476 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
477
478 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
479
480 \f
481
482 /* GType Methods
483  */
484
485 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
486                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
487                                                 gtk_tree_view_buildable_init))
488
489 static void
490 gtk_tree_view_class_init (GtkTreeViewClass *class)
491 {
492   GObjectClass *o_class;
493   GtkObjectClass *object_class;
494   GtkWidgetClass *widget_class;
495   GtkContainerClass *container_class;
496   GtkBindingSet *binding_set;
497
498   binding_set = gtk_binding_set_by_class (class);
499
500   o_class = (GObjectClass *) class;
501   object_class = (GtkObjectClass *) class;
502   widget_class = (GtkWidgetClass *) class;
503   container_class = (GtkContainerClass *) class;
504
505   /* GObject signals */
506   o_class->set_property = gtk_tree_view_set_property;
507   o_class->get_property = gtk_tree_view_get_property;
508   o_class->finalize = gtk_tree_view_finalize;
509
510   /* GtkObject signals */
511   object_class->destroy = gtk_tree_view_destroy;
512
513   /* GtkWidget signals */
514   widget_class->map = gtk_tree_view_map;
515   widget_class->realize = gtk_tree_view_realize;
516   widget_class->unrealize = gtk_tree_view_unrealize;
517   widget_class->size_request = gtk_tree_view_size_request;
518   widget_class->size_allocate = gtk_tree_view_size_allocate;
519   widget_class->button_press_event = gtk_tree_view_button_press;
520   widget_class->button_release_event = gtk_tree_view_button_release;
521   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
522   /*widget_class->configure_event = gtk_tree_view_configure;*/
523   widget_class->motion_notify_event = gtk_tree_view_motion;
524   widget_class->expose_event = gtk_tree_view_expose;
525   widget_class->key_press_event = gtk_tree_view_key_press;
526   widget_class->key_release_event = gtk_tree_view_key_release;
527   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
528   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
529   widget_class->focus_out_event = gtk_tree_view_focus_out;
530   widget_class->drag_begin = gtk_tree_view_drag_begin;
531   widget_class->drag_end = gtk_tree_view_drag_end;
532   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
533   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
534   widget_class->drag_leave = gtk_tree_view_drag_leave;
535   widget_class->drag_motion = gtk_tree_view_drag_motion;
536   widget_class->drag_drop = gtk_tree_view_drag_drop;
537   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
538   widget_class->focus = gtk_tree_view_focus;
539   widget_class->grab_focus = gtk_tree_view_grab_focus;
540   widget_class->style_set = gtk_tree_view_style_set;
541   widget_class->grab_notify = gtk_tree_view_grab_notify;
542   widget_class->state_changed = gtk_tree_view_state_changed;
543
544   /* GtkContainer signals */
545   container_class->remove = gtk_tree_view_remove;
546   container_class->forall = gtk_tree_view_forall;
547   container_class->set_focus_child = gtk_tree_view_set_focus_child;
548
549   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
550   class->move_cursor = gtk_tree_view_real_move_cursor;
551   class->select_all = gtk_tree_view_real_select_all;
552   class->unselect_all = gtk_tree_view_real_unselect_all;
553   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
554   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
555   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
556   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
557   class->start_interactive_search = gtk_tree_view_start_interactive_search;
558
559   /* Properties */
560
561   g_object_class_install_property (o_class,
562                                    PROP_MODEL,
563                                    g_param_spec_object ("model",
564                                                         P_("TreeView Model"),
565                                                         P_("The model for the tree view"),
566                                                         GTK_TYPE_TREE_MODEL,
567                                                         GTK_PARAM_READWRITE));
568
569   g_object_class_install_property (o_class,
570                                    PROP_HADJUSTMENT,
571                                    g_param_spec_object ("hadjustment",
572                                                         P_("Horizontal Adjustment"),
573                                                         P_("Horizontal Adjustment for the widget"),
574                                                         GTK_TYPE_ADJUSTMENT,
575                                                         GTK_PARAM_READWRITE));
576
577   g_object_class_install_property (o_class,
578                                    PROP_VADJUSTMENT,
579                                    g_param_spec_object ("vadjustment",
580                                                         P_("Vertical Adjustment"),
581                                                         P_("Vertical Adjustment for the widget"),
582                                                         GTK_TYPE_ADJUSTMENT,
583                                                         GTK_PARAM_READWRITE));
584
585   g_object_class_install_property (o_class,
586                                    PROP_HEADERS_VISIBLE,
587                                    g_param_spec_boolean ("headers-visible",
588                                                          P_("Headers Visible"),
589                                                          P_("Show the column header buttons"),
590                                                          TRUE,
591                                                          GTK_PARAM_READWRITE));
592
593   g_object_class_install_property (o_class,
594                                    PROP_HEADERS_CLICKABLE,
595                                    g_param_spec_boolean ("headers-clickable",
596                                                          P_("Headers Clickable"),
597                                                          P_("Column headers respond to click events"),
598                                                          TRUE,
599                                                          GTK_PARAM_READWRITE));
600
601   g_object_class_install_property (o_class,
602                                    PROP_EXPANDER_COLUMN,
603                                    g_param_spec_object ("expander-column",
604                                                         P_("Expander Column"),
605                                                         P_("Set the column for the expander column"),
606                                                         GTK_TYPE_TREE_VIEW_COLUMN,
607                                                         GTK_PARAM_READWRITE));
608
609   g_object_class_install_property (o_class,
610                                    PROP_REORDERABLE,
611                                    g_param_spec_boolean ("reorderable",
612                                                          P_("Reorderable"),
613                                                          P_("View is reorderable"),
614                                                          FALSE,
615                                                          GTK_PARAM_READWRITE));
616
617   g_object_class_install_property (o_class,
618                                    PROP_RULES_HINT,
619                                    g_param_spec_boolean ("rules-hint",
620                                                          P_("Rules Hint"),
621                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
622                                                          FALSE,
623                                                          GTK_PARAM_READWRITE));
624
625     g_object_class_install_property (o_class,
626                                      PROP_ENABLE_SEARCH,
627                                      g_param_spec_boolean ("enable-search",
628                                                            P_("Enable Search"),
629                                                            P_("View allows user to search through columns interactively"),
630                                                            TRUE,
631                                                            GTK_PARAM_READWRITE));
632
633     g_object_class_install_property (o_class,
634                                      PROP_SEARCH_COLUMN,
635                                      g_param_spec_int ("search-column",
636                                                        P_("Search Column"),
637                                                        P_("Model column to search through when searching through code"),
638                                                        -1,
639                                                        G_MAXINT,
640                                                        -1,
641                                                        GTK_PARAM_READWRITE));
642
643     /**
644      * GtkTreeView:fixed-height-mode:
645      *
646      * Setting the ::fixed-height-mode property to %TRUE speeds up 
647      * #GtkTreeView by assuming that all rows have the same height. 
648      * Only enable this option if all rows are the same height.  
649      * Please see gtk_tree_view_set_fixed_height_mode() for more 
650      * information on this option.
651      *
652      * Since: 2.4
653      **/
654     g_object_class_install_property (o_class,
655                                      PROP_FIXED_HEIGHT_MODE,
656                                      g_param_spec_boolean ("fixed-height-mode",
657                                                            P_("Fixed Height Mode"),
658                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
659                                                            FALSE,
660                                                            GTK_PARAM_READWRITE));
661     
662     /**
663      * GtkTreeView:hover-selection:
664      * 
665      * Enables of disables the hover selection mode of @tree_view.
666      * Hover selection makes the selected row follow the pointer.
667      * Currently, this works only for the selection modes 
668      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
669      *
670      * This mode is primarily indended for treeviews in popups, e.g.
671      * in #GtkComboBox or #GtkEntryCompletion.
672      *
673      * Since: 2.6
674      */
675     g_object_class_install_property (o_class,
676                                      PROP_HOVER_SELECTION,
677                                      g_param_spec_boolean ("hover-selection",
678                                                            P_("Hover Selection"),
679                                                            P_("Whether the selection should follow the pointer"),
680                                                            FALSE,
681                                                            GTK_PARAM_READWRITE));
682
683     /**
684      * GtkTreeView:hover-expand:
685      * 
686      * Enables of disables the hover expansion mode of @tree_view.
687      * Hover expansion makes rows expand or collaps if the pointer moves 
688      * over them.
689      *
690      * This mode is primarily indended for treeviews in popups, e.g.
691      * in #GtkComboBox or #GtkEntryCompletion.
692      *
693      * Since: 2.6
694      */
695     g_object_class_install_property (o_class,
696                                      PROP_HOVER_EXPAND,
697                                      g_param_spec_boolean ("hover-expand",
698                                                            P_("Hover Expand"),
699                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
700                                                            FALSE,
701                                                            GTK_PARAM_READWRITE));
702
703     /**
704      * GtkTreeView:show-expanders:
705      *
706      * %TRUE if the view has expanders.
707      *
708      * Since: 2.12
709      */
710     g_object_class_install_property (o_class,
711                                      PROP_SHOW_EXPANDERS,
712                                      g_param_spec_boolean ("show-expanders",
713                                                            P_("Show Expanders"),
714                                                            P_("View has expanders"),
715                                                            TRUE,
716                                                            GTK_PARAM_READWRITE));
717
718     /**
719      * GtkTreeView:level-indentation:
720      *
721      * Extra indentation for each level.
722      *
723      * Since: 2.12
724      */
725     g_object_class_install_property (o_class,
726                                      PROP_LEVEL_INDENTATION,
727                                      g_param_spec_int ("level-indentation",
728                                                        P_("Level Indentation"),
729                                                        P_("Extra indentation for each level"),
730                                                        0,
731                                                        G_MAXINT,
732                                                        0,
733                                                        GTK_PARAM_READWRITE));
734
735     g_object_class_install_property (o_class,
736                                      PROP_RUBBER_BANDING,
737                                      g_param_spec_boolean ("rubber-banding",
738                                                            P_("Rubber Banding"),
739                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
740                                                            FALSE,
741                                                            GTK_PARAM_READWRITE));
742
743     g_object_class_install_property (o_class,
744                                      PROP_ENABLE_GRID_LINES,
745                                      g_param_spec_enum ("enable-grid-lines",
746                                                         P_("Enable Grid Lines"),
747                                                         P_("Whether grid lines should be drawn in the tree view"),
748                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
749                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
750                                                         GTK_PARAM_READWRITE));
751
752     g_object_class_install_property (o_class,
753                                      PROP_ENABLE_TREE_LINES,
754                                      g_param_spec_boolean ("enable-tree-lines",
755                                                            P_("Enable Tree Lines"),
756                                                            P_("Whether tree lines should be drawn in the tree view"),
757                                                            FALSE,
758                                                            GTK_PARAM_READWRITE));
759
760     g_object_class_install_property (o_class,
761                                      PROP_TOOLTIP_COLUMN,
762                                      g_param_spec_int ("tooltip-column",
763                                                        P_("Tooltip Column"),
764                                                        P_("The column in the model containing the tooltip texts for the rows"),
765                                                        -1,
766                                                        G_MAXINT,
767                                                        -1,
768                                                        GTK_PARAM_READWRITE));
769
770   /* Style properties */
771 #define _TREE_VIEW_EXPANDER_SIZE 12
772 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
773 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
774     
775   gtk_widget_class_install_style_property (widget_class,
776                                            g_param_spec_int ("expander-size",
777                                                              P_("Expander Size"),
778                                                              P_("Size of the expander arrow"),
779                                                              0,
780                                                              G_MAXINT,
781                                                              _TREE_VIEW_EXPANDER_SIZE,
782                                                              GTK_PARAM_READABLE));
783
784   gtk_widget_class_install_style_property (widget_class,
785                                            g_param_spec_int ("vertical-separator",
786                                                              P_("Vertical Separator Width"),
787                                                              P_("Vertical space between cells.  Must be an even number"),
788                                                              0,
789                                                              G_MAXINT,
790                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
791                                                              GTK_PARAM_READABLE));
792
793   gtk_widget_class_install_style_property (widget_class,
794                                            g_param_spec_int ("horizontal-separator",
795                                                              P_("Horizontal Separator Width"),
796                                                              P_("Horizontal space between cells.  Must be an even number"),
797                                                              0,
798                                                              G_MAXINT,
799                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
800                                                              GTK_PARAM_READABLE));
801
802   gtk_widget_class_install_style_property (widget_class,
803                                            g_param_spec_boolean ("allow-rules",
804                                                                  P_("Allow Rules"),
805                                                                  P_("Allow drawing of alternating color rows"),
806                                                                  TRUE,
807                                                                  GTK_PARAM_READABLE));
808
809   gtk_widget_class_install_style_property (widget_class,
810                                            g_param_spec_boolean ("indent-expanders",
811                                                                  P_("Indent Expanders"),
812                                                                  P_("Make the expanders indented"),
813                                                                  TRUE,
814                                                                  GTK_PARAM_READABLE));
815
816   gtk_widget_class_install_style_property (widget_class,
817                                            g_param_spec_boxed ("even-row-color",
818                                                                P_("Even Row Color"),
819                                                                P_("Color to use for even rows"),
820                                                                GDK_TYPE_COLOR,
821                                                                GTK_PARAM_READABLE));
822
823   gtk_widget_class_install_style_property (widget_class,
824                                            g_param_spec_boxed ("odd-row-color",
825                                                                P_("Odd Row Color"),
826                                                                P_("Color to use for odd rows"),
827                                                                GDK_TYPE_COLOR,
828                                                                GTK_PARAM_READABLE));
829
830   gtk_widget_class_install_style_property (widget_class,
831                                            g_param_spec_boolean ("row-ending-details",
832                                                                  P_("Row Ending details"),
833                                                                  P_("Enable extended row background theming"),
834                                                                  FALSE,
835                                                                  GTK_PARAM_READABLE));
836
837   gtk_widget_class_install_style_property (widget_class,
838                                            g_param_spec_int ("grid-line-width",
839                                                              P_("Grid line width"),
840                                                              P_("Width, in pixels, of the tree view grid lines"),
841                                                              0, G_MAXINT, 1,
842                                                              GTK_PARAM_READABLE));
843
844   gtk_widget_class_install_style_property (widget_class,
845                                            g_param_spec_int ("tree-line-width",
846                                                              P_("Tree line width"),
847                                                              P_("Width, in pixels, of the tree view lines"),
848                                                              0, G_MAXINT, 1,
849                                                              GTK_PARAM_READABLE));
850
851   gtk_widget_class_install_style_property (widget_class,
852                                            g_param_spec_string ("grid-line-pattern",
853                                                                 P_("Grid line pattern"),
854                                                                 P_("Dash pattern used to draw the tree view grid lines"),
855                                                                 "\1\1",
856                                                                 GTK_PARAM_READABLE));
857
858   gtk_widget_class_install_style_property (widget_class,
859                                            g_param_spec_string ("tree-line-pattern",
860                                                                 P_("Tree line pattern"),
861                                                                 P_("Dash pattern used to draw the tree view lines"),
862                                                                 "\1\1",
863                                                                 GTK_PARAM_READABLE));
864
865   /* Signals */
866   widget_class->set_scroll_adjustments_signal =
867     g_signal_new (I_("set_scroll_adjustments"),
868                   G_TYPE_FROM_CLASS (o_class),
869                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
870                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
871                   NULL, NULL,
872                   _gtk_marshal_VOID__OBJECT_OBJECT,
873                   G_TYPE_NONE, 2,
874                   GTK_TYPE_ADJUSTMENT,
875                   GTK_TYPE_ADJUSTMENT);
876
877   /**
878    * GtkTreeView::row-activated:
879    * @tree_view: the object on which the signal is emitted
880    * @path: the #GtkTreePath for the activated row
881    * @column: the #GtkTreeViewColumn in which the activation occurred
882    *
883    * The "row-activated" signal is emitted when the method
884    * gtk_tree_view_row_activated() is called or the user double clicks 
885    * a treeview row. It is also emitted when a non-editable row is 
886    * selected and one of the keys: Space, Shift+Space, Return or 
887    * Enter is pressed.
888    * 
889    * For selection handling refer to the <link linkend="TreeWidget">tree 
890    * widget conceptual overview</link> as well as #GtkTreeSelection.
891    */
892   tree_view_signals[ROW_ACTIVATED] =
893     g_signal_new (I_("row_activated"),
894                   G_TYPE_FROM_CLASS (o_class),
895                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
896                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
897                   NULL, NULL,
898                   _gtk_marshal_VOID__BOXED_OBJECT,
899                   G_TYPE_NONE, 2,
900                   GTK_TYPE_TREE_PATH,
901                   GTK_TYPE_TREE_VIEW_COLUMN);
902
903   /**
904    * GtkTreeView::test-expand-row:
905    * @tree_view: the object on which the signal is emitted
906    * @iter: the tree iter of the row to expand
907    * @path: a tree path that points to the row 
908    * 
909    * The given row is about to be expanded (show its children nodes). Use this
910    * signal if you need to control the expandability of individual rows.
911    *
912    * Returns: %FALSE to allow expansion, %TRUE to reject
913    */
914   tree_view_signals[TEST_EXPAND_ROW] =
915     g_signal_new (I_("test-expand-row"),
916                   G_TYPE_FROM_CLASS (o_class),
917                   G_SIGNAL_RUN_LAST,
918                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
919                   _gtk_boolean_handled_accumulator, NULL,
920                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
921                   G_TYPE_BOOLEAN, 2,
922                   GTK_TYPE_TREE_ITER,
923                   GTK_TYPE_TREE_PATH);
924
925   /**
926    * GtkTreeView::test-collapse-row:
927    * @tree_view: the object on which the signal is emitted
928    * @iter: the tree iter of the row to collapse
929    * @path: a tree path that points to the row 
930    * 
931    * The given row is about to be collapsed (hide its children nodes). Use this
932    * signal if you need to control the collapsibility of individual rows.
933    *
934    * Returns: %FALSE to allow collapsing, %TRUE to reject
935    */
936   tree_view_signals[TEST_COLLAPSE_ROW] =
937     g_signal_new (I_("test-collapse-row"),
938                   G_TYPE_FROM_CLASS (o_class),
939                   G_SIGNAL_RUN_LAST,
940                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
941                   _gtk_boolean_handled_accumulator, NULL,
942                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
943                   G_TYPE_BOOLEAN, 2,
944                   GTK_TYPE_TREE_ITER,
945                   GTK_TYPE_TREE_PATH);
946
947   /**
948    * GtkTreeView::row-expanded:
949    * @tree_view: the object on which the signal is emitted
950    * @iter: the tree iter of the expanded row
951    * @path: a tree path that points to the row 
952    * 
953    * The given row has been expanded (child nodes are shown).
954    */
955   tree_view_signals[ROW_EXPANDED] =
956     g_signal_new (I_("row-expanded"),
957                   G_TYPE_FROM_CLASS (o_class),
958                   G_SIGNAL_RUN_LAST,
959                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
960                   NULL, NULL,
961                   _gtk_marshal_VOID__BOXED_BOXED,
962                   G_TYPE_NONE, 2,
963                   GTK_TYPE_TREE_ITER,
964                   GTK_TYPE_TREE_PATH);
965
966   /**
967    * GtkTreeView::row-collapsed:
968    * @tree_view: the object on which the signal is emitted
969    * @iter: the tree iter of the collapsed row
970    * @path: a tree path that points to the row 
971    * 
972    * The given row has been collapsed (child nodes are hidden).
973    */
974   tree_view_signals[ROW_COLLAPSED] =
975     g_signal_new (I_("row-collapsed"),
976                   G_TYPE_FROM_CLASS (o_class),
977                   G_SIGNAL_RUN_LAST,
978                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
979                   NULL, NULL,
980                   _gtk_marshal_VOID__BOXED_BOXED,
981                   G_TYPE_NONE, 2,
982                   GTK_TYPE_TREE_ITER,
983                   GTK_TYPE_TREE_PATH);
984
985   /**
986    * GtkTreeView::columns-changed:
987    * @tree_view: the object on which the signal is emitted 
988    * 
989    * The number of columns of the treeview has changed.
990    */
991   tree_view_signals[COLUMNS_CHANGED] =
992     g_signal_new (I_("columns-changed"),
993                   G_TYPE_FROM_CLASS (o_class),
994                   G_SIGNAL_RUN_LAST,
995                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
996                   NULL, NULL,
997                   _gtk_marshal_NONE__NONE,
998                   G_TYPE_NONE, 0);
999
1000   /**
1001    * GtkTreeView::cursor-changed:
1002    * @tree_view: the object on which the signal is emitted
1003    * 
1004    * The position of the cursor (focused cell) has changed.
1005    */
1006   tree_view_signals[CURSOR_CHANGED] =
1007     g_signal_new (I_("cursor-changed"),
1008                   G_TYPE_FROM_CLASS (o_class),
1009                   G_SIGNAL_RUN_LAST,
1010                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1011                   NULL, NULL,
1012                   _gtk_marshal_NONE__NONE,
1013                   G_TYPE_NONE, 0);
1014
1015   tree_view_signals[MOVE_CURSOR] =
1016     g_signal_new (I_("move_cursor"),
1017                   G_TYPE_FROM_CLASS (object_class),
1018                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1019                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1020                   NULL, NULL,
1021                   _gtk_marshal_BOOLEAN__ENUM_INT,
1022                   G_TYPE_BOOLEAN, 2,
1023                   GTK_TYPE_MOVEMENT_STEP,
1024                   G_TYPE_INT);
1025
1026   tree_view_signals[SELECT_ALL] =
1027     g_signal_new (I_("select_all"),
1028                   G_TYPE_FROM_CLASS (object_class),
1029                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1030                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1031                   NULL, NULL,
1032                   _gtk_marshal_BOOLEAN__NONE,
1033                   G_TYPE_BOOLEAN, 0);
1034
1035   tree_view_signals[UNSELECT_ALL] =
1036     g_signal_new (I_("unselect_all"),
1037                   G_TYPE_FROM_CLASS (object_class),
1038                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1039                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1040                   NULL, NULL,
1041                   _gtk_marshal_BOOLEAN__NONE,
1042                   G_TYPE_BOOLEAN, 0);
1043
1044   tree_view_signals[SELECT_CURSOR_ROW] =
1045     g_signal_new (I_("select_cursor_row"),
1046                   G_TYPE_FROM_CLASS (object_class),
1047                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1048                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1049                   NULL, NULL,
1050                   _gtk_marshal_BOOLEAN__BOOLEAN,
1051                   G_TYPE_BOOLEAN, 1,
1052                   G_TYPE_BOOLEAN);
1053
1054   tree_view_signals[TOGGLE_CURSOR_ROW] =
1055     g_signal_new (I_("toggle_cursor_row"),
1056                   G_TYPE_FROM_CLASS (object_class),
1057                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1058                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1059                   NULL, NULL,
1060                   _gtk_marshal_BOOLEAN__NONE,
1061                   G_TYPE_BOOLEAN, 0);
1062
1063   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1064     g_signal_new (I_("expand_collapse_cursor_row"),
1065                   G_TYPE_FROM_CLASS (object_class),
1066                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1067                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1068                   NULL, NULL,
1069                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1070                   G_TYPE_BOOLEAN, 3,
1071                   G_TYPE_BOOLEAN,
1072                   G_TYPE_BOOLEAN,
1073                   G_TYPE_BOOLEAN);
1074
1075   tree_view_signals[SELECT_CURSOR_PARENT] =
1076     g_signal_new (I_("select_cursor_parent"),
1077                   G_TYPE_FROM_CLASS (object_class),
1078                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1079                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1080                   NULL, NULL,
1081                   _gtk_marshal_BOOLEAN__NONE,
1082                   G_TYPE_BOOLEAN, 0);
1083
1084   tree_view_signals[START_INTERACTIVE_SEARCH] =
1085     g_signal_new (I_("start_interactive_search"),
1086                   G_TYPE_FROM_CLASS (object_class),
1087                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1088                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1089                   NULL, NULL,
1090                   _gtk_marshal_BOOLEAN__NONE,
1091                   G_TYPE_BOOLEAN, 0);
1092
1093   /* Key bindings */
1094   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
1095                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1096   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
1097                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1098
1099   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
1100                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1101   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
1102                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1103
1104   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
1105                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1106
1107   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
1108                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1109
1110   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
1111                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1112   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
1113                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1114
1115   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
1116                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1117   gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
1118                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1119
1120   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
1121                                   GTK_MOVEMENT_PAGES, -1);
1122   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
1123                                   GTK_MOVEMENT_PAGES, -1);
1124
1125   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
1126                                   GTK_MOVEMENT_PAGES, 1);
1127   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
1128                                   GTK_MOVEMENT_PAGES, 1);
1129
1130
1131   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move_cursor", 2,
1132                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1133                                 G_TYPE_INT, 1);
1134
1135   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move_cursor", 2,
1136                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1137                                 G_TYPE_INT, -1);
1138
1139   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move_cursor", 2,
1140                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1141                                 G_TYPE_INT, 1);
1142
1143   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move_cursor", 2,
1144                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1145                                 G_TYPE_INT, -1);
1146
1147   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
1148                                 "move_cursor", 2,
1149                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1150                                 G_TYPE_INT, 1);
1151
1152   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
1153                                 "move_cursor", 2,
1154                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1155                                 G_TYPE_INT, -1);
1156
1157   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1158                                 "move_cursor", 2,
1159                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1160                                 G_TYPE_INT, 1);
1161
1162   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
1163                                 "move_cursor", 2,
1164                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1165                                 G_TYPE_INT, -1);
1166
1167   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_row", 0);
1168
1169   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
1170   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select_all", 0);
1171
1172   gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect_all", 0);
1173   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect_all", 0);
1174
1175   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select_cursor_row", 1,
1176                                 G_TYPE_BOOLEAN, TRUE);
1177
1178   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 1,
1179                                 G_TYPE_BOOLEAN, TRUE);
1180   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select_cursor_row", 1,
1181                                 G_TYPE_BOOLEAN, TRUE);
1182   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select_cursor_row", 1,
1183                                 G_TYPE_BOOLEAN, TRUE);
1184   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select_cursor_row", 1,
1185                                 G_TYPE_BOOLEAN, TRUE);
1186
1187   /* expand and collapse rows */
1188   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3,
1189                                 G_TYPE_BOOLEAN, TRUE,
1190                                 G_TYPE_BOOLEAN, TRUE,
1191                                 G_TYPE_BOOLEAN, FALSE);
1192
1193   gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
1194                                 "expand_collapse_cursor_row", 3,
1195                                 G_TYPE_BOOLEAN, TRUE,
1196                                 G_TYPE_BOOLEAN, TRUE,
1197                                 G_TYPE_BOOLEAN, TRUE);
1198   gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
1199                                 "expand_collapse_cursor_row", 3,
1200                                 G_TYPE_BOOLEAN, TRUE,
1201                                 G_TYPE_BOOLEAN, TRUE,
1202                                 G_TYPE_BOOLEAN, TRUE);
1203
1204   gtk_binding_entry_add_signal (binding_set, GDK_slash, 0,
1205                                 "expand_collapse_cursor_row", 3,
1206                                 G_TYPE_BOOLEAN, TRUE,
1207                                 G_TYPE_BOOLEAN, FALSE,
1208                                 G_TYPE_BOOLEAN, FALSE);
1209   gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
1210                                 "expand_collapse_cursor_row", 3,
1211                                 G_TYPE_BOOLEAN, TRUE,
1212                                 G_TYPE_BOOLEAN, FALSE,
1213                                 G_TYPE_BOOLEAN, FALSE);
1214
1215   /* Not doable on US keyboards */
1216   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1217                                 G_TYPE_BOOLEAN, TRUE,
1218                                 G_TYPE_BOOLEAN, TRUE,
1219                                 G_TYPE_BOOLEAN, TRUE);
1220   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand_collapse_cursor_row", 3,
1221                                 G_TYPE_BOOLEAN, TRUE,
1222                                 G_TYPE_BOOLEAN, TRUE,
1223                                 G_TYPE_BOOLEAN, FALSE);
1224   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1225                                 G_TYPE_BOOLEAN, TRUE,
1226                                 G_TYPE_BOOLEAN, TRUE,
1227                                 G_TYPE_BOOLEAN, TRUE);
1228   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1229                                 G_TYPE_BOOLEAN, TRUE,
1230                                 G_TYPE_BOOLEAN, TRUE,
1231                                 G_TYPE_BOOLEAN, TRUE);
1232   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
1233                                 "expand_collapse_cursor_row", 3,
1234                                 G_TYPE_BOOLEAN, FALSE,
1235                                 G_TYPE_BOOLEAN, TRUE,
1236                                 G_TYPE_BOOLEAN, TRUE);
1237   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
1238                                 "expand_collapse_cursor_row", 3,
1239                                 G_TYPE_BOOLEAN, FALSE,
1240                                 G_TYPE_BOOLEAN, TRUE,
1241                                 G_TYPE_BOOLEAN, TRUE);
1242   gtk_binding_entry_add_signal (binding_set, GDK_Right,
1243                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1244                                 "expand_collapse_cursor_row", 3,
1245                                 G_TYPE_BOOLEAN, FALSE,
1246                                 G_TYPE_BOOLEAN, TRUE,
1247                                 G_TYPE_BOOLEAN, TRUE);
1248   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
1249                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1250                                 "expand_collapse_cursor_row", 3,
1251                                 G_TYPE_BOOLEAN, FALSE,
1252                                 G_TYPE_BOOLEAN, TRUE,
1253                                 G_TYPE_BOOLEAN, TRUE);
1254
1255   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand_collapse_cursor_row", 3,
1256                                 G_TYPE_BOOLEAN, TRUE,
1257                                 G_TYPE_BOOLEAN, FALSE,
1258                                 G_TYPE_BOOLEAN, FALSE);
1259   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1260                                 G_TYPE_BOOLEAN, TRUE,
1261                                 G_TYPE_BOOLEAN, FALSE,
1262                                 G_TYPE_BOOLEAN, TRUE);
1263   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand_collapse_cursor_row", 3,
1264                                 G_TYPE_BOOLEAN, TRUE,
1265                                 G_TYPE_BOOLEAN, FALSE,
1266                                 G_TYPE_BOOLEAN, FALSE);
1267   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
1268                                 G_TYPE_BOOLEAN, TRUE,
1269                                 G_TYPE_BOOLEAN, FALSE,
1270                                 G_TYPE_BOOLEAN, TRUE);
1271   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
1272                                 "expand_collapse_cursor_row", 3,
1273                                 G_TYPE_BOOLEAN, FALSE,
1274                                 G_TYPE_BOOLEAN, FALSE,
1275                                 G_TYPE_BOOLEAN, TRUE);
1276   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
1277                                 "expand_collapse_cursor_row", 3,
1278                                 G_TYPE_BOOLEAN, FALSE,
1279                                 G_TYPE_BOOLEAN, FALSE,
1280                                 G_TYPE_BOOLEAN, TRUE);
1281   gtk_binding_entry_add_signal (binding_set, GDK_Left,
1282                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1283                                 "expand_collapse_cursor_row", 3,
1284                                 G_TYPE_BOOLEAN, FALSE,
1285                                 G_TYPE_BOOLEAN, FALSE,
1286                                 G_TYPE_BOOLEAN, TRUE);
1287   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
1288                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1289                                 "expand_collapse_cursor_row", 3,
1290                                 G_TYPE_BOOLEAN, FALSE,
1291                                 G_TYPE_BOOLEAN, FALSE,
1292                                 G_TYPE_BOOLEAN, TRUE);
1293
1294   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
1295   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select_cursor_parent", 0);
1296
1297   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start_interactive_search", 0);
1298
1299   gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start_interactive_search", 0);
1300
1301   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1302 }
1303
1304 static void
1305 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1306 {
1307   iface->add_child = gtk_tree_view_buildable_add_child;
1308 }
1309
1310 static void
1311 gtk_tree_view_init (GtkTreeView *tree_view)
1312 {
1313   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1314
1315   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
1316
1317   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1318
1319   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1320                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1321                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1322
1323   /* We need some padding */
1324   tree_view->priv->dy = 0;
1325   tree_view->priv->cursor_offset = 0;
1326   tree_view->priv->n_columns = 0;
1327   tree_view->priv->header_height = 1;
1328   tree_view->priv->x_drag = 0;
1329   tree_view->priv->drag_pos = -1;
1330   tree_view->priv->header_has_focus = FALSE;
1331   tree_view->priv->pressed_button = -1;
1332   tree_view->priv->press_start_x = -1;
1333   tree_view->priv->press_start_y = -1;
1334   tree_view->priv->reorderable = FALSE;
1335   tree_view->priv->presize_handler_timer = 0;
1336   tree_view->priv->scroll_sync_timer = 0;
1337   tree_view->priv->fixed_height = -1;
1338   tree_view->priv->fixed_height_mode = FALSE;
1339   tree_view->priv->fixed_height_check = 0;
1340   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1341   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1342   tree_view->priv->enable_search = TRUE;
1343   tree_view->priv->search_column = -1;
1344   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1345   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1346   tree_view->priv->search_custom_entry_set = FALSE;
1347   tree_view->priv->typeselect_flush_timeout = 0;
1348   tree_view->priv->init_hadjust_value = TRUE;    
1349   tree_view->priv->width = 0;
1350           
1351   tree_view->priv->hover_selection = FALSE;
1352   tree_view->priv->hover_expand = FALSE;
1353
1354   tree_view->priv->level_indentation = 0;
1355
1356   tree_view->priv->rubber_banding_enable = FALSE;
1357
1358   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1359   tree_view->priv->tree_lines_enabled = FALSE;
1360
1361   tree_view->priv->tooltip_column = -1;
1362 }
1363
1364 \f
1365
1366 /* GObject Methods
1367  */
1368
1369 static void
1370 gtk_tree_view_set_property (GObject         *object,
1371                             guint            prop_id,
1372                             const GValue    *value,
1373                             GParamSpec      *pspec)
1374 {
1375   GtkTreeView *tree_view;
1376
1377   tree_view = GTK_TREE_VIEW (object);
1378
1379   switch (prop_id)
1380     {
1381     case PROP_MODEL:
1382       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1383       break;
1384     case PROP_HADJUSTMENT:
1385       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1386       break;
1387     case PROP_VADJUSTMENT:
1388       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1389       break;
1390     case PROP_HEADERS_VISIBLE:
1391       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1392       break;
1393     case PROP_HEADERS_CLICKABLE:
1394       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1395       break;
1396     case PROP_EXPANDER_COLUMN:
1397       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1398       break;
1399     case PROP_REORDERABLE:
1400       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1401       break;
1402     case PROP_RULES_HINT:
1403       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1404       break;
1405     case PROP_ENABLE_SEARCH:
1406       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1407       break;
1408     case PROP_SEARCH_COLUMN:
1409       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1410       break;
1411     case PROP_FIXED_HEIGHT_MODE:
1412       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1413       break;
1414     case PROP_HOVER_SELECTION:
1415       tree_view->priv->hover_selection = g_value_get_boolean (value);
1416       break;
1417     case PROP_HOVER_EXPAND:
1418       tree_view->priv->hover_expand = g_value_get_boolean (value);
1419       break;
1420     case PROP_SHOW_EXPANDERS:
1421       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1422       break;
1423     case PROP_LEVEL_INDENTATION:
1424       tree_view->priv->level_indentation = g_value_get_int (value);
1425       break;
1426     case PROP_RUBBER_BANDING:
1427       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1428       break;
1429     case PROP_ENABLE_GRID_LINES:
1430       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1431       break;
1432     case PROP_ENABLE_TREE_LINES:
1433       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1434       break;
1435     case PROP_TOOLTIP_COLUMN:
1436       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1437       break;
1438     default:
1439       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1440       break;
1441     }
1442 }
1443
1444 static void
1445 gtk_tree_view_get_property (GObject    *object,
1446                             guint       prop_id,
1447                             GValue     *value,
1448                             GParamSpec *pspec)
1449 {
1450   GtkTreeView *tree_view;
1451
1452   tree_view = GTK_TREE_VIEW (object);
1453
1454   switch (prop_id)
1455     {
1456     case PROP_MODEL:
1457       g_value_set_object (value, tree_view->priv->model);
1458       break;
1459     case PROP_HADJUSTMENT:
1460       g_value_set_object (value, tree_view->priv->hadjustment);
1461       break;
1462     case PROP_VADJUSTMENT:
1463       g_value_set_object (value, tree_view->priv->vadjustment);
1464       break;
1465     case PROP_HEADERS_VISIBLE:
1466       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1467       break;
1468     case PROP_HEADERS_CLICKABLE:
1469       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1470       break;
1471     case PROP_EXPANDER_COLUMN:
1472       g_value_set_object (value, tree_view->priv->expander_column);
1473       break;
1474     case PROP_REORDERABLE:
1475       g_value_set_boolean (value, tree_view->priv->reorderable);
1476       break;
1477     case PROP_RULES_HINT:
1478       g_value_set_boolean (value, tree_view->priv->has_rules);
1479       break;
1480     case PROP_ENABLE_SEARCH:
1481       g_value_set_boolean (value, tree_view->priv->enable_search);
1482       break;
1483     case PROP_SEARCH_COLUMN:
1484       g_value_set_int (value, tree_view->priv->search_column);
1485       break;
1486     case PROP_FIXED_HEIGHT_MODE:
1487       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1488       break;
1489     case PROP_HOVER_SELECTION:
1490       g_value_set_boolean (value, tree_view->priv->hover_selection);
1491       break;
1492     case PROP_HOVER_EXPAND:
1493       g_value_set_boolean (value, tree_view->priv->hover_expand);
1494       break;
1495     case PROP_SHOW_EXPANDERS:
1496       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1497       break;
1498     case PROP_LEVEL_INDENTATION:
1499       g_value_set_int (value, tree_view->priv->level_indentation);
1500       break;
1501     case PROP_RUBBER_BANDING:
1502       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1503       break;
1504     case PROP_ENABLE_GRID_LINES:
1505       g_value_set_enum (value, tree_view->priv->grid_lines);
1506       break;
1507     case PROP_ENABLE_TREE_LINES:
1508       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1509       break;
1510     case PROP_TOOLTIP_COLUMN:
1511       g_value_set_int (value, tree_view->priv->tooltip_column);
1512       break;
1513     default:
1514       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1515       break;
1516     }
1517 }
1518
1519 static void
1520 gtk_tree_view_finalize (GObject *object)
1521 {
1522   (* G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize) (object);
1523 }
1524
1525 \f
1526
1527 static void
1528 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1529                                    GtkBuilder  *builder,
1530                                    GObject     *child,
1531                                    const gchar *type)
1532 {
1533   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1534 }
1535
1536 /* GtkObject Methods
1537  */
1538
1539 static void
1540 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1541 {
1542   _gtk_rbtree_free (tree_view->priv->tree);
1543   
1544   tree_view->priv->tree = NULL;
1545   tree_view->priv->button_pressed_node = NULL;
1546   tree_view->priv->button_pressed_tree = NULL;
1547   tree_view->priv->prelight_tree = NULL;
1548   tree_view->priv->prelight_node = NULL;
1549   tree_view->priv->expanded_collapsed_node = NULL;
1550   tree_view->priv->expanded_collapsed_tree = NULL;
1551 }
1552
1553 static void
1554 gtk_tree_view_destroy (GtkObject *object)
1555 {
1556   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1557   GList *list;
1558
1559   gtk_tree_view_stop_editing (tree_view, TRUE);
1560
1561   if (tree_view->priv->columns != NULL)
1562     {
1563       list = tree_view->priv->columns;
1564       while (list)
1565         {
1566           GtkTreeViewColumn *column;
1567           column = GTK_TREE_VIEW_COLUMN (list->data);
1568           list = list->next;
1569           gtk_tree_view_remove_column (tree_view, column);
1570         }
1571       tree_view->priv->columns = NULL;
1572     }
1573
1574   if (tree_view->priv->tree != NULL)
1575     {
1576       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1577
1578       gtk_tree_view_free_rbtree (tree_view);
1579     }
1580
1581   if (tree_view->priv->selection != NULL)
1582     {
1583       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1584       g_object_unref (tree_view->priv->selection);
1585       tree_view->priv->selection = NULL;
1586     }
1587
1588   if (tree_view->priv->scroll_to_path != NULL)
1589     {
1590       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1591       tree_view->priv->scroll_to_path = NULL;
1592     }
1593
1594   if (tree_view->priv->drag_dest_row != NULL)
1595     {
1596       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1597       tree_view->priv->drag_dest_row = NULL;
1598     }
1599
1600   if (tree_view->priv->last_button_press != NULL)
1601     {
1602       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
1603       tree_view->priv->last_button_press = NULL;
1604     }
1605
1606   if (tree_view->priv->last_button_press_2 != NULL)
1607     {
1608       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
1609       tree_view->priv->last_button_press_2 = NULL;
1610     }
1611
1612   if (tree_view->priv->top_row != NULL)
1613     {
1614       gtk_tree_row_reference_free (tree_view->priv->top_row);
1615       tree_view->priv->top_row = NULL;
1616     }
1617
1618   if (tree_view->priv->column_drop_func_data &&
1619       tree_view->priv->column_drop_func_data_destroy)
1620     {
1621       (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
1622       tree_view->priv->column_drop_func_data = NULL;
1623     }
1624
1625   if (tree_view->priv->destroy_count_destroy &&
1626       tree_view->priv->destroy_count_data)
1627     {
1628       (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
1629       tree_view->priv->destroy_count_data = NULL;
1630     }
1631
1632   gtk_tree_row_reference_free (tree_view->priv->cursor);
1633   tree_view->priv->cursor = NULL;
1634
1635   gtk_tree_row_reference_free (tree_view->priv->anchor);
1636   tree_view->priv->anchor = NULL;
1637
1638   /* destroy interactive search dialog */
1639   if (tree_view->priv->search_window)
1640     {
1641       gtk_widget_destroy (tree_view->priv->search_window);
1642       tree_view->priv->search_window = NULL;
1643       tree_view->priv->search_entry = NULL;
1644       if (tree_view->priv->typeselect_flush_timeout)
1645         {
1646           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1647           tree_view->priv->typeselect_flush_timeout = 0;
1648         }
1649     }
1650
1651   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1652     {
1653       (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
1654       tree_view->priv->search_user_data = NULL;
1655     }
1656
1657   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1658     {
1659       (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
1660       tree_view->priv->search_position_user_data = NULL;
1661     }
1662
1663   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1664     {
1665       (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data);
1666       tree_view->priv->row_separator_data = NULL;
1667     }
1668   
1669   gtk_tree_view_set_model (tree_view, NULL);
1670
1671   if (tree_view->priv->hadjustment)
1672     {
1673       g_object_unref (tree_view->priv->hadjustment);
1674       tree_view->priv->hadjustment = NULL;
1675     }
1676   if (tree_view->priv->vadjustment)
1677     {
1678       g_object_unref (tree_view->priv->vadjustment);
1679       tree_view->priv->vadjustment = NULL;
1680     }
1681
1682   if (GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy)
1683     (* GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy) (object);
1684 }
1685
1686 \f
1687
1688 /* GtkWidget Methods
1689  */
1690
1691 /* GtkWidget::map helper */
1692 static void
1693 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1694 {
1695   GList *list;
1696
1697   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1698
1699   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1700     {
1701       GtkTreeViewColumn *column;
1702
1703       for (list = tree_view->priv->columns; list; list = list->next)
1704         {
1705           column = list->data;
1706           if (GTK_WIDGET_VISIBLE (column->button) &&
1707               !GTK_WIDGET_MAPPED (column->button))
1708             gtk_widget_map (column->button);
1709         }
1710       for (list = tree_view->priv->columns; list; list = list->next)
1711         {
1712           column = list->data;
1713           if (column->visible == FALSE)
1714             continue;
1715           if (column->resizable)
1716             {
1717               gdk_window_raise (column->window);
1718               gdk_window_show (column->window);
1719             }
1720           else
1721             gdk_window_hide (column->window);
1722         }
1723       gdk_window_show (tree_view->priv->header_window);
1724     }
1725 }
1726
1727 static void
1728 gtk_tree_view_map (GtkWidget *widget)
1729 {
1730   GList *tmp_list;
1731   GtkTreeView *tree_view;
1732
1733   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1734
1735   tree_view = GTK_TREE_VIEW (widget);
1736
1737   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1738
1739   tmp_list = tree_view->priv->children;
1740   while (tmp_list)
1741     {
1742       GtkTreeViewChild *child = tmp_list->data;
1743       tmp_list = tmp_list->next;
1744
1745       if (GTK_WIDGET_VISIBLE (child->widget))
1746         {
1747           if (!GTK_WIDGET_MAPPED (child->widget))
1748             gtk_widget_map (child->widget);
1749         }
1750     }
1751   gdk_window_show (tree_view->priv->bin_window);
1752
1753   gtk_tree_view_map_buttons (tree_view);
1754
1755   gdk_window_show (widget->window);
1756 }
1757
1758 static void
1759 gtk_tree_view_realize (GtkWidget *widget)
1760 {
1761   GList *tmp_list;
1762   GtkTreeView *tree_view;
1763   GdkWindowAttr attributes;
1764   gint attributes_mask;
1765
1766   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1767
1768   tree_view = GTK_TREE_VIEW (widget);
1769
1770   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1771
1772   /* Make the main, clipping window */
1773   attributes.window_type = GDK_WINDOW_CHILD;
1774   attributes.x = widget->allocation.x;
1775   attributes.y = widget->allocation.y;
1776   attributes.width = widget->allocation.width;
1777   attributes.height = widget->allocation.height;
1778   attributes.wclass = GDK_INPUT_OUTPUT;
1779   attributes.visual = gtk_widget_get_visual (widget);
1780   attributes.colormap = gtk_widget_get_colormap (widget);
1781   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1782
1783   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1784
1785   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1786                                    &attributes, attributes_mask);
1787   gdk_window_set_user_data (widget->window, widget);
1788
1789   /* Make the window for the tree */
1790   attributes.x = 0;
1791   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1792   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1793   attributes.height = widget->allocation.height;
1794   attributes.event_mask = GDK_EXPOSURE_MASK |
1795     GDK_SCROLL_MASK |
1796     GDK_POINTER_MOTION_MASK |
1797     GDK_ENTER_NOTIFY_MASK |
1798     GDK_LEAVE_NOTIFY_MASK |
1799     GDK_BUTTON_PRESS_MASK |
1800     GDK_BUTTON_RELEASE_MASK |
1801     gtk_widget_get_events (widget);
1802
1803   tree_view->priv->bin_window = gdk_window_new (widget->window,
1804                                                 &attributes, attributes_mask);
1805   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1806
1807   /* Make the column header window */
1808   attributes.x = 0;
1809   attributes.y = 0;
1810   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1811   attributes.height = tree_view->priv->header_height;
1812   attributes.event_mask = (GDK_EXPOSURE_MASK |
1813                            GDK_SCROLL_MASK |
1814                            GDK_BUTTON_PRESS_MASK |
1815                            GDK_BUTTON_RELEASE_MASK |
1816                            GDK_KEY_PRESS_MASK |
1817                            GDK_KEY_RELEASE_MASK) |
1818     gtk_widget_get_events (widget);
1819
1820   tree_view->priv->header_window = gdk_window_new (widget->window,
1821                                                    &attributes, attributes_mask);
1822   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1823
1824   /* Add them all up. */
1825   widget->style = gtk_style_attach (widget->style, widget->window);
1826   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1827   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1828   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1829
1830   tmp_list = tree_view->priv->children;
1831   while (tmp_list)
1832     {
1833       GtkTreeViewChild *child = tmp_list->data;
1834       tmp_list = tmp_list->next;
1835
1836       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1837     }
1838
1839   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1840     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1841
1842   /* Need to call those here, since they create GCs */
1843   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1844   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1845
1846   install_presize_handler (tree_view); 
1847 }
1848
1849 static void
1850 gtk_tree_view_unrealize (GtkWidget *widget)
1851 {
1852   GtkTreeView *tree_view;
1853   GtkTreeViewPrivate *priv;
1854   GList *list;
1855
1856   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1857
1858   tree_view = GTK_TREE_VIEW (widget);
1859   priv = tree_view->priv;
1860
1861   if (priv->scroll_timeout != 0)
1862     {
1863       g_source_remove (priv->scroll_timeout);
1864       priv->scroll_timeout = 0;
1865     }
1866
1867   if (priv->auto_expand_timeout != 0)
1868     {
1869       g_source_remove (priv->auto_expand_timeout);
1870       priv->auto_expand_timeout = 0;
1871     }
1872
1873   if (priv->open_dest_timeout != 0)
1874     {
1875       g_source_remove (priv->open_dest_timeout);
1876       priv->open_dest_timeout = 0;
1877     }
1878
1879   if (priv->expand_collapse_timeout != 0)
1880     {
1881       g_source_remove (priv->expand_collapse_timeout);
1882       priv->expand_collapse_timeout = 0;
1883     }
1884   
1885   if (priv->presize_handler_timer != 0)
1886     {
1887       g_source_remove (priv->presize_handler_timer);
1888       priv->presize_handler_timer = 0;
1889     }
1890
1891   if (priv->validate_rows_timer != 0)
1892     {
1893       g_source_remove (priv->validate_rows_timer);
1894       priv->validate_rows_timer = 0;
1895     }
1896
1897   if (priv->scroll_sync_timer != 0)
1898     {
1899       g_source_remove (priv->scroll_sync_timer);
1900       priv->scroll_sync_timer = 0;
1901     }
1902
1903   if (priv->typeselect_flush_timeout)
1904     {
1905       g_source_remove (priv->typeselect_flush_timeout);
1906       priv->typeselect_flush_timeout = 0;
1907     }
1908   
1909   for (list = priv->columns; list; list = list->next)
1910     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1911
1912   gdk_window_set_user_data (priv->bin_window, NULL);
1913   gdk_window_destroy (priv->bin_window);
1914   priv->bin_window = NULL;
1915
1916   gdk_window_set_user_data (priv->header_window, NULL);
1917   gdk_window_destroy (priv->header_window);
1918   priv->header_window = NULL;
1919
1920   if (priv->drag_window)
1921     {
1922       gdk_window_set_user_data (priv->drag_window, NULL);
1923       gdk_window_destroy (priv->drag_window);
1924       priv->drag_window = NULL;
1925     }
1926
1927   if (priv->drag_highlight_window)
1928     {
1929       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1930       gdk_window_destroy (priv->drag_highlight_window);
1931       priv->drag_highlight_window = NULL;
1932     }
1933
1934   if (priv->tree_line_gc)
1935     {
1936       g_object_unref (priv->tree_line_gc);
1937       priv->tree_line_gc = NULL;
1938     }
1939
1940   if (priv->grid_line_gc)
1941     {
1942       g_object_unref (priv->grid_line_gc);
1943       priv->grid_line_gc = NULL;
1944     }
1945
1946   /* GtkWidget::unrealize destroys children and widget->window */
1947   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize)
1948     (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize) (widget);
1949 }
1950
1951 /* GtkWidget::size_request helper */
1952 static void
1953 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1954 {
1955   GList *list;
1956
1957   tree_view->priv->header_height = 0;
1958
1959   if (tree_view->priv->model)
1960     {
1961       for (list = tree_view->priv->columns; list; list = list->next)
1962         {
1963           GtkRequisition requisition;
1964           GtkTreeViewColumn *column = list->data;
1965
1966           if (column->button == NULL)
1967             continue;
1968
1969           column = list->data;
1970           
1971           gtk_widget_size_request (column->button, &requisition);
1972           column->button_request = requisition.width;
1973           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1974         }
1975     }
1976 }
1977
1978
1979 /* Called only by ::size_request */
1980 static void
1981 gtk_tree_view_update_size (GtkTreeView *tree_view)
1982 {
1983   GList *list;
1984   GtkTreeViewColumn *column;
1985   gint i;
1986
1987   if (tree_view->priv->model == NULL)
1988     {
1989       tree_view->priv->width = 0;
1990       tree_view->priv->prev_width = 0;                   
1991       tree_view->priv->height = 0;
1992       return;
1993     }
1994
1995   tree_view->priv->prev_width = tree_view->priv->width;  
1996   tree_view->priv->width = 0;
1997   /* keep this in sync with size_allocate below */
1998   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1999     {
2000       gint real_requested_width = 0;
2001       column = list->data;
2002       if (!column->visible)
2003         continue;
2004
2005       if (column->use_resized_width)
2006         {
2007           real_requested_width = column->resized_width;
2008         }
2009       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2010         {
2011           real_requested_width = column->fixed_width;
2012         }
2013       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2014         {
2015           real_requested_width = MAX (column->requested_width, column->button_request);
2016         }
2017       else
2018         {
2019           real_requested_width = column->requested_width;
2020         }
2021
2022       if (column->min_width != -1)
2023         real_requested_width = MAX (real_requested_width, column->min_width);
2024       if (column->max_width != -1)
2025         real_requested_width = MIN (real_requested_width, column->max_width);
2026
2027       tree_view->priv->width += real_requested_width;
2028     }
2029
2030   if (tree_view->priv->tree == NULL)
2031     tree_view->priv->height = 0;
2032   else
2033     tree_view->priv->height = tree_view->priv->tree->root->offset;
2034 }
2035
2036 static void
2037 gtk_tree_view_size_request (GtkWidget      *widget,
2038                             GtkRequisition *requisition)
2039 {
2040   GtkTreeView *tree_view;
2041   GList *tmp_list;
2042
2043   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
2044
2045   tree_view = GTK_TREE_VIEW (widget);
2046
2047   /* we validate GTK_TREE_VIEW_NUM_ROWS_PER_IDLE rows initially just to make
2048    * sure we have some size. In practice, with a lot of static lists, this
2049    * should get a good width.
2050    */
2051   do_validate_rows (tree_view, FALSE);
2052   gtk_tree_view_size_request_columns (tree_view);
2053   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2054
2055   requisition->width = tree_view->priv->width;
2056   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2057
2058   tmp_list = tree_view->priv->children;
2059
2060   while (tmp_list)
2061     {
2062       GtkTreeViewChild *child = tmp_list->data;
2063       GtkRequisition child_requisition;
2064
2065       tmp_list = tmp_list->next;
2066
2067       if (GTK_WIDGET_VISIBLE (child->widget))
2068         gtk_widget_size_request (child->widget, &child_requisition);
2069     }
2070 }
2071
2072
2073 static void
2074 invalidate_column (GtkTreeView       *tree_view,
2075                    GtkTreeViewColumn *column)
2076 {
2077   gint column_offset = 0;
2078   GList *list;
2079   GtkWidget *widget = GTK_WIDGET (tree_view);
2080   gboolean rtl;
2081
2082   if (!GTK_WIDGET_REALIZED (widget))
2083     return;
2084
2085   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2086   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2087        list;
2088        list = (rtl ? list->prev : list->next))
2089     {
2090       GtkTreeViewColumn *tmpcolumn = list->data;
2091       if (tmpcolumn == column)
2092         {
2093           GdkRectangle invalid_rect;
2094           
2095           invalid_rect.x = column_offset;
2096           invalid_rect.y = 0;
2097           invalid_rect.width = column->width;
2098           invalid_rect.height = widget->allocation.height;
2099           
2100           gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
2101           break;
2102         }
2103       
2104       column_offset += tmpcolumn->width;
2105     }
2106 }
2107
2108 static void
2109 invalidate_last_column (GtkTreeView *tree_view)
2110 {
2111   GList *last_column;
2112   gboolean rtl;
2113
2114   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2115
2116   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2117        last_column;
2118        last_column = (rtl ? last_column->next : last_column->prev))
2119     {
2120       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2121         {
2122           invalidate_column (tree_view, last_column->data);
2123           return;
2124         }
2125     }
2126 }
2127
2128 static gint
2129 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2130                                                     GtkTreeViewColumn *column)
2131 {
2132   gint real_requested_width;
2133
2134   if (column->use_resized_width)
2135     {
2136       real_requested_width = column->resized_width;
2137     }
2138   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2139     {
2140       real_requested_width = column->fixed_width;
2141     }
2142   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2143     {
2144       real_requested_width = MAX (column->requested_width, column->button_request);
2145     }
2146   else
2147     {
2148       real_requested_width = column->requested_width;
2149       if (real_requested_width < 0)
2150         real_requested_width = 0;
2151     }
2152
2153   if (column->min_width != -1)
2154     real_requested_width = MAX (real_requested_width, column->min_width);
2155   if (column->max_width != -1)
2156     real_requested_width = MIN (real_requested_width, column->max_width);
2157
2158   return real_requested_width;
2159 }
2160
2161 /* GtkWidget::size_allocate helper */
2162 static void
2163 gtk_tree_view_size_allocate_columns (GtkWidget *widget)
2164 {
2165   GtkTreeView *tree_view;
2166   GList *list, *first_column, *last_column;
2167   GtkTreeViewColumn *column;
2168   GtkAllocation allocation;
2169   gint width = 0;
2170   gint extra, extra_per_column;
2171   gint full_requested_width = 0;
2172   gint number_of_expand_columns = 0;
2173   gboolean column_changed = FALSE;
2174   gboolean rtl;
2175   
2176   tree_view = GTK_TREE_VIEW (widget);
2177
2178   for (last_column = g_list_last (tree_view->priv->columns);
2179        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2180        last_column = last_column->prev)
2181     ;
2182   if (last_column == NULL)
2183     return;
2184
2185   for (first_column = g_list_first (tree_view->priv->columns);
2186        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2187        first_column = first_column->next)
2188     ;
2189
2190   allocation.y = 0;
2191   allocation.height = tree_view->priv->header_height;
2192
2193   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2194
2195   /* find out how many extra space and expandable columns we have */
2196   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2197     {
2198       column = (GtkTreeViewColumn *)list->data;
2199
2200       if (!column->visible)
2201         continue;
2202
2203       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2204
2205       if (column->expand)
2206         number_of_expand_columns++;
2207     }
2208
2209   extra = MAX (widget->allocation.width - full_requested_width, 0);
2210   if (number_of_expand_columns > 0)
2211     extra_per_column = extra/number_of_expand_columns;
2212   else
2213     extra_per_column = 0;
2214
2215   for (list = (rtl ? last_column : first_column); 
2216        list != (rtl ? first_column->prev : last_column->next);
2217        list = (rtl ? list->prev : list->next)) 
2218     {
2219       gint real_requested_width = 0;
2220       gint old_width;
2221
2222       column = list->data;
2223       old_width = column->width;
2224
2225       if (!column->visible)
2226         continue;
2227
2228       /* We need to handle the dragged button specially.
2229        */
2230       if (column == tree_view->priv->drag_column)
2231         {
2232           GtkAllocation drag_allocation;
2233           gdk_drawable_get_size (tree_view->priv->drag_window,
2234                                  &(drag_allocation.width),
2235                                  &(drag_allocation.height));
2236           drag_allocation.x = 0;
2237           drag_allocation.y = 0;
2238           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2239                                     &drag_allocation);
2240           width += drag_allocation.width;
2241           continue;
2242         }
2243
2244       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2245
2246       allocation.x = width;
2247       column->width = real_requested_width;
2248
2249       if (column->expand)
2250         {
2251           if (number_of_expand_columns == 1)
2252             {
2253               /* We add the remander to the last column as
2254                * */
2255               column->width += extra;
2256             }
2257           else
2258             {
2259               column->width += extra_per_column;
2260               extra -= extra_per_column;
2261               number_of_expand_columns --;
2262             }
2263         }
2264       else if (number_of_expand_columns == 0 &&
2265                list == last_column)
2266         {
2267           column->width += extra;
2268         }
2269
2270       g_object_notify (G_OBJECT (column), "width");
2271
2272       allocation.width = column->width;
2273       width += column->width;
2274
2275       if (column->width > old_width)
2276         column_changed = TRUE;
2277
2278       gtk_widget_size_allocate (column->button, &allocation);
2279
2280       if (column->window)
2281         gdk_window_move_resize (column->window,
2282                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2283                                 allocation.y,
2284                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2285     }
2286
2287   if (column_changed)
2288     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2289 }
2290
2291
2292 static void
2293 gtk_tree_view_size_allocate (GtkWidget     *widget,
2294                              GtkAllocation *allocation)
2295 {
2296   GList *tmp_list;
2297   GtkTreeView *tree_view;
2298   gboolean width_changed = FALSE;
2299   gint old_width = widget->allocation.width;           
2300
2301   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
2302
2303   if (allocation->width != widget->allocation.width)
2304     width_changed = TRUE;
2305   
2306   widget->allocation = *allocation;
2307
2308   tree_view = GTK_TREE_VIEW (widget);
2309
2310   tmp_list = tree_view->priv->children;
2311
2312   while (tmp_list)
2313     {
2314       GtkAllocation allocation;
2315
2316       GtkTreeViewChild *child = tmp_list->data;
2317       tmp_list = tmp_list->next;
2318
2319       /* totally ignore our child's requisition */
2320       allocation.x = child->x;
2321       allocation.y = child->y;
2322       allocation.width = child->width;
2323       allocation.height = child->height;
2324       gtk_widget_size_allocate (child->widget, &allocation);
2325     }
2326
2327
2328   tree_view->priv->hadjustment->page_size = allocation->width;
2329   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2330   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2331   tree_view->priv->hadjustment->lower = 0;
2332   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2333
2334   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2335      {
2336       if (allocation->width < tree_view->priv->width)
2337          {
2338          if (tree_view->priv->init_hadjust_value)
2339            {
2340            tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2341            tree_view->priv->init_hadjust_value = FALSE;
2342            }
2343          else if(allocation->width != old_width)
2344            tree_view->priv->hadjustment->value = CLAMP(tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2345          else
2346            tree_view->priv->hadjustment->value = CLAMP(tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value), 0, tree_view->priv->width - allocation->width);
2347          }
2348       else
2349          {
2350          tree_view->priv->hadjustment->value = 0;
2351          tree_view->priv->init_hadjust_value = TRUE;
2352          }
2353      }
2354   else
2355      if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2356         tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2357
2358   gtk_adjustment_changed (tree_view->priv->hadjustment);
2359
2360   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2361   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2362   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2363   tree_view->priv->vadjustment->lower = 0;
2364   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2365
2366   gtk_adjustment_changed (tree_view->priv->vadjustment);
2367
2368   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2369   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2370     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2371   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2372     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2373                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2374   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2375     gtk_tree_view_top_row_to_dy (tree_view);
2376   else
2377     gtk_tree_view_dy_to_top_row (tree_view);
2378   
2379   if (GTK_WIDGET_REALIZED (widget))
2380     {
2381       gdk_window_move_resize (widget->window,
2382                               allocation->x, allocation->y,
2383                               allocation->width, allocation->height);
2384       gdk_window_move_resize (tree_view->priv->header_window,
2385                               - (gint) tree_view->priv->hadjustment->value,
2386                               0,
2387                               MAX (tree_view->priv->width, allocation->width),
2388                               tree_view->priv->header_height);
2389       gdk_window_move_resize (tree_view->priv->bin_window,
2390                               - (gint) tree_view->priv->hadjustment->value,
2391                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2392                               MAX (tree_view->priv->width, allocation->width),
2393                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2394     }
2395
2396   gtk_tree_view_size_allocate_columns (widget);
2397
2398   if (tree_view->priv->tree == NULL)
2399     invalidate_empty_focus (tree_view);
2400
2401   if (GTK_WIDGET_REALIZED (widget))
2402     {
2403       gboolean has_expand_column = FALSE;
2404       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2405         {
2406           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2407             {
2408               has_expand_column = TRUE;
2409               break;
2410             }
2411         }
2412
2413       /* This little hack only works if we have an LTR locale, and no column has the  */
2414       if (width_changed)
2415         {
2416           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2417               ! has_expand_column)
2418             invalidate_last_column (tree_view);
2419           else
2420             gtk_widget_queue_draw (widget);
2421         }
2422     }
2423 }
2424
2425 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2426 static void
2427 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2428 {
2429   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
2430     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2431   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2432 }
2433
2434 static inline gboolean
2435 row_is_separator (GtkTreeView *tree_view,
2436                   GtkTreeIter *iter,
2437                   GtkTreePath *path)
2438 {
2439   gboolean is_separator = FALSE;
2440
2441   if (tree_view->priv->row_separator_func)
2442     {
2443       GtkTreeIter tmpiter;
2444
2445       if (iter)
2446         tmpiter = *iter;
2447       else
2448         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2449
2450       is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
2451                                                               &tmpiter,
2452                                                               tree_view->priv->row_separator_data);
2453     }
2454
2455   return is_separator;
2456 }
2457
2458 static gboolean
2459 gtk_tree_view_button_press (GtkWidget      *widget,
2460                             GdkEventButton *event)
2461 {
2462   GtkTreeView *tree_view;
2463   GList *list;
2464   GtkTreeViewColumn *column = NULL;
2465   gint i;
2466   GdkRectangle background_area;
2467   GdkRectangle cell_area;
2468   gint vertical_separator;
2469   gint horizontal_separator;
2470   gboolean path_is_selectable;
2471   gboolean rtl;
2472
2473   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2474   g_return_val_if_fail (event != NULL, FALSE);
2475
2476   tree_view = GTK_TREE_VIEW (widget);
2477   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2478   gtk_tree_view_stop_editing (tree_view, FALSE);
2479   gtk_widget_style_get (widget,
2480                         "vertical-separator", &vertical_separator,
2481                         "horizontal-separator", &horizontal_separator,
2482                         NULL);
2483
2484
2485   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2486    * we're done handling the button press.
2487    */
2488
2489   if (event->window == tree_view->priv->bin_window)
2490     {
2491       GtkRBNode *node;
2492       GtkRBTree *tree;
2493       GtkTreePath *path;
2494       gchar *path_string;
2495       gint depth;
2496       gint new_y;
2497       gint y_offset;
2498       gint dval;
2499       gint pre_val, aft_val;
2500       GtkTreeViewColumn *column = NULL;
2501       GtkCellRenderer *focus_cell = NULL;
2502       gint column_handled_click = FALSE;
2503       gboolean row_double_click = FALSE;
2504       gboolean rtl;
2505       gboolean node_selected;
2506
2507       /* Empty tree? */
2508       if (tree_view->priv->tree == NULL)
2509         {
2510           grab_focus_and_unset_draw_keyfocus (tree_view);
2511           return TRUE;
2512         }
2513
2514       /* are we in an arrow? */
2515       if (tree_view->priv->prelight_node &&
2516           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2517           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2518         {
2519           if (event->button == 1)
2520             {
2521               gtk_grab_add (widget);
2522               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2523               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2524               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2525                                         tree_view->priv->prelight_tree,
2526                                         tree_view->priv->prelight_node,
2527                                         event->x,
2528                                         event->y);
2529             }
2530
2531           grab_focus_and_unset_draw_keyfocus (tree_view);
2532           return TRUE;
2533         }
2534
2535       /* find the node that was clicked */
2536       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2537       if (new_y < 0)
2538         new_y = 0;
2539       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2540
2541       if (node == NULL)
2542         {
2543           /* We clicked in dead space */
2544           grab_focus_and_unset_draw_keyfocus (tree_view);
2545           return TRUE;
2546         }
2547
2548       /* Get the path and the node */
2549       path = _gtk_tree_view_find_path (tree_view, tree, node);
2550       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2551
2552       if (!path_is_selectable)
2553         {
2554           gtk_tree_path_free (path);
2555           grab_focus_and_unset_draw_keyfocus (tree_view);
2556           return TRUE;
2557         }
2558
2559       depth = gtk_tree_path_get_depth (path);
2560       background_area.y = y_offset + event->y;
2561       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2562       background_area.x = 0;
2563
2564
2565       /* Let the column have a chance at selecting it. */
2566       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2567       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2568            list; list = (rtl ? list->prev : list->next))
2569         {
2570           GtkTreeViewColumn *candidate = list->data;
2571
2572           if (!candidate->visible)
2573             continue;
2574
2575           background_area.width = candidate->width;
2576           if ((background_area.x > (gint) event->x) ||
2577               (background_area.x + background_area.width <= (gint) event->x))
2578             {
2579               background_area.x += background_area.width;
2580               continue;
2581             }
2582
2583           /* we found the focus column */
2584           column = candidate;
2585           cell_area = background_area;
2586           cell_area.width -= horizontal_separator;
2587           cell_area.height -= vertical_separator;
2588           cell_area.x += horizontal_separator/2;
2589           cell_area.y += vertical_separator/2;
2590           if (gtk_tree_view_is_expander_column (tree_view, column))
2591             {
2592               if (!rtl)
2593                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2594               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2595
2596               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2597                 {
2598                   if (!rtl)
2599                     cell_area.x += depth * tree_view->priv->expander_size;
2600                   cell_area.width -= depth * tree_view->priv->expander_size;
2601                 }
2602             }
2603           break;
2604         }
2605
2606       if (column == NULL)
2607         {
2608           gtk_tree_path_free (path);
2609           grab_focus_and_unset_draw_keyfocus (tree_view);
2610           return FALSE;
2611         }
2612
2613       tree_view->priv->focus_column = column;
2614
2615       /* decide if we edit */
2616       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2617           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2618         {
2619           GtkTreePath *anchor;
2620           GtkTreeIter iter;
2621
2622           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2623           gtk_tree_view_column_cell_set_cell_data (column,
2624                                                    tree_view->priv->model,
2625                                                    &iter,
2626                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2627                                                    node->children?TRUE:FALSE);
2628
2629           if (tree_view->priv->anchor)
2630             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2631           else
2632             anchor = NULL;
2633
2634           if ((anchor && !gtk_tree_path_compare (anchor, path))
2635               || !_gtk_tree_view_column_has_editable_cell (column))
2636             {
2637               GtkCellEditable *cell_editable = NULL;
2638
2639               /* FIXME: get the right flags */
2640               guint flags = 0;
2641
2642               path_string = gtk_tree_path_to_string (path);
2643
2644               if (_gtk_tree_view_column_cell_event (column,
2645                                                     &cell_editable,
2646                                                     (GdkEvent *)event,
2647                                                     path_string,
2648                                                     &background_area,
2649                                                     &cell_area, flags))
2650                 {
2651                   if (cell_editable != NULL)
2652                     {
2653                       gint left, right;
2654                       GdkRectangle area;
2655
2656                       area = cell_area;
2657                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2658
2659                       area.x += left;
2660                       area.width -= right + left;
2661
2662                       gtk_tree_view_real_start_editing (tree_view,
2663                                                         column,
2664                                                         path,
2665                                                         cell_editable,
2666                                                         &area,
2667                                                         (GdkEvent *)event,
2668                                                         flags);
2669                       g_free (path_string);
2670                       gtk_tree_path_free (path);
2671                       gtk_tree_path_free (anchor);
2672                       return TRUE;
2673                     }
2674                   column_handled_click = TRUE;
2675                 }
2676               g_free (path_string);
2677             }
2678           if (anchor)
2679             gtk_tree_path_free (anchor);
2680         }
2681
2682       /* select */
2683       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2684       pre_val = tree_view->priv->vadjustment->value;
2685
2686       /* we only handle selection modifications on the first button press
2687        */
2688       if (event->type == GDK_BUTTON_PRESS)
2689         {
2690           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2691             tree_view->priv->ctrl_pressed = TRUE;
2692           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2693             tree_view->priv->shift_pressed = TRUE;
2694
2695           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2696           if (focus_cell)
2697             gtk_tree_view_column_focus_cell (column, focus_cell);
2698
2699           if (event->state & GDK_CONTROL_MASK)
2700             {
2701               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2702               gtk_tree_view_real_toggle_cursor_row (tree_view);
2703             }
2704           else if (event->state & GDK_SHIFT_MASK)
2705             {
2706               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2707               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2708             }
2709           else
2710             {
2711               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2712             }
2713
2714           tree_view->priv->ctrl_pressed = FALSE;
2715           tree_view->priv->shift_pressed = FALSE;
2716         }
2717
2718       /* the treeview may have been scrolled because of _set_cursor,
2719        * correct here
2720        */
2721
2722       aft_val = tree_view->priv->vadjustment->value;
2723       dval = pre_val - aft_val;
2724
2725       cell_area.y += dval;
2726       background_area.y += dval;
2727
2728       /* Save press to possibly begin a drag
2729        */
2730       if (!column_handled_click &&
2731           !tree_view->priv->in_grab &&
2732           tree_view->priv->pressed_button < 0)
2733         {
2734           tree_view->priv->pressed_button = event->button;
2735           tree_view->priv->press_start_x = event->x;
2736           tree_view->priv->press_start_y = event->y;
2737
2738           if (tree_view->priv->rubber_banding_enable
2739               && !node_selected
2740               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2741             {
2742               tree_view->priv->press_start_y += tree_view->priv->dy;
2743               tree_view->priv->rubber_band_x = event->x;
2744               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2745               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2746
2747               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2748                 tree_view->priv->rubber_band_ctrl = TRUE;
2749               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2750                 tree_view->priv->rubber_band_shift = TRUE;
2751             }
2752         }
2753
2754       /* Test if a double click happened on the same row. */
2755       if (event->button == 1)
2756         {
2757           /* We also handle triple clicks here, because a user could have done
2758            * a first click and a second double click on different rows.
2759            */
2760           if ((event->type == GDK_2BUTTON_PRESS
2761                || event->type == GDK_3BUTTON_PRESS)
2762               && tree_view->priv->last_button_press)
2763             {
2764               GtkTreePath *lsc;
2765
2766               lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
2767
2768               if (lsc)
2769                 {
2770                   row_double_click = !gtk_tree_path_compare (lsc, path);
2771                   gtk_tree_path_free (lsc);
2772                 }
2773             }
2774
2775           if (row_double_click)
2776             {
2777               if (tree_view->priv->last_button_press)
2778                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2779               if (tree_view->priv->last_button_press_2)
2780                 gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
2781               tree_view->priv->last_button_press = NULL;
2782               tree_view->priv->last_button_press_2 = NULL;
2783             }
2784           else
2785             {
2786               if (tree_view->priv->last_button_press)
2787                 gtk_tree_row_reference_free (tree_view->priv->last_button_press);
2788               tree_view->priv->last_button_press = tree_view->priv->last_button_press_2;
2789               tree_view->priv->last_button_press_2 = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
2790             }
2791         }
2792
2793       if (row_double_click)
2794         {
2795           gtk_grab_remove (widget);
2796           gtk_tree_view_row_activated (tree_view, path, column);
2797
2798           if (tree_view->priv->pressed_button == event->button)
2799             tree_view->priv->pressed_button = -1;
2800         }
2801
2802       gtk_tree_path_free (path);
2803
2804       /* If we activated the row through a double click we don't want to grab
2805        * focus back, as moving focus to another widget is pretty common.
2806        */
2807       if (!row_double_click)
2808         grab_focus_and_unset_draw_keyfocus (tree_view);
2809
2810       return TRUE;
2811     }
2812
2813   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2814    */
2815   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2816     {
2817       column = list->data;
2818       if (event->window == column->window &&
2819           column->resizable &&
2820           column->window)
2821         {
2822           gpointer drag_data;
2823
2824           if (event->type == GDK_2BUTTON_PRESS &&
2825               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2826             {
2827               column->use_resized_width = FALSE;
2828               _gtk_tree_view_column_autosize (tree_view, column);
2829               return TRUE;
2830             }
2831
2832           if (gdk_pointer_grab (column->window, FALSE,
2833                                 GDK_POINTER_MOTION_HINT_MASK |
2834                                 GDK_BUTTON1_MOTION_MASK |
2835                                 GDK_BUTTON_RELEASE_MASK,
2836                                 NULL, NULL, event->time))
2837             return FALSE;
2838
2839           gtk_grab_add (widget);
2840           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2841           column->resized_width = column->width;
2842
2843           /* block attached dnd signal handler */
2844           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2845           if (drag_data)
2846             g_signal_handlers_block_matched (widget,
2847                                              G_SIGNAL_MATCH_DATA,
2848                                              0, 0, NULL, NULL,
2849                                              drag_data);
2850
2851           tree_view->priv->drag_pos = i;
2852           tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
2853
2854           if (!GTK_WIDGET_HAS_FOCUS (widget))
2855             gtk_widget_grab_focus (widget);
2856
2857           return TRUE;
2858         }
2859     }
2860   return FALSE;
2861 }
2862
2863 /* GtkWidget::button_release_event helper */
2864 static gboolean
2865 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2866                                           GdkEventButton *event)
2867 {
2868   GtkTreeView *tree_view;
2869   gboolean rtl;
2870
2871   tree_view = GTK_TREE_VIEW (widget);
2872
2873   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2874   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2875   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2876
2877   /* Move the button back */
2878   g_object_ref (tree_view->priv->drag_column->button);
2879   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2880   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2881   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2882   g_object_unref (tree_view->priv->drag_column->button);
2883   gtk_widget_queue_resize (widget);
2884   if (tree_view->priv->drag_column->resizable)
2885     {
2886       gdk_window_raise (tree_view->priv->drag_column->window);
2887       gdk_window_show (tree_view->priv->drag_column->window);
2888     }
2889   else
2890     gdk_window_hide (tree_view->priv->drag_column->window);
2891
2892   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2893
2894   if (rtl)
2895     {
2896       if (tree_view->priv->cur_reorder &&
2897           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2898         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2899                                          tree_view->priv->cur_reorder->right_column);
2900     }
2901   else
2902     {
2903       if (tree_view->priv->cur_reorder &&
2904           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2905         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2906                                          tree_view->priv->cur_reorder->left_column);
2907     }
2908   tree_view->priv->drag_column = NULL;
2909   gdk_window_hide (tree_view->priv->drag_window);
2910
2911   g_list_foreach (tree_view->priv->column_drag_info, (GFunc) g_free, NULL);
2912   g_list_free (tree_view->priv->column_drag_info);
2913   tree_view->priv->column_drag_info = NULL;
2914   tree_view->priv->cur_reorder = NULL;
2915
2916   if (tree_view->priv->drag_highlight_window)
2917     gdk_window_hide (tree_view->priv->drag_highlight_window);
2918
2919   /* Reset our flags */
2920   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
2921   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
2922
2923   return TRUE;
2924 }
2925
2926 /* GtkWidget::button_release_event helper */
2927 static gboolean
2928 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
2929                                             GdkEventButton *event)
2930 {
2931   GtkTreeView *tree_view;
2932   gpointer drag_data;
2933
2934   tree_view = GTK_TREE_VIEW (widget);
2935
2936   tree_view->priv->drag_pos = -1;
2937
2938   /* unblock attached dnd signal handler */
2939   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2940   if (drag_data)
2941     g_signal_handlers_unblock_matched (widget,
2942                                        G_SIGNAL_MATCH_DATA,
2943                                        0, 0, NULL, NULL,
2944                                        drag_data);
2945
2946   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2947   gtk_grab_remove (widget);
2948   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
2949                               event->time);
2950   return TRUE;
2951 }
2952
2953 static gboolean
2954 gtk_tree_view_button_release (GtkWidget      *widget,
2955                               GdkEventButton *event)
2956 {
2957   GtkTreeView *tree_view;
2958
2959   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
2960   g_return_val_if_fail (event != NULL, FALSE);
2961
2962   tree_view = GTK_TREE_VIEW (widget);
2963
2964   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2965     return gtk_tree_view_button_release_drag_column (widget, event);
2966
2967   if (tree_view->priv->rubber_band_status)
2968     gtk_tree_view_stop_rubber_band (tree_view);
2969
2970   if (tree_view->priv->pressed_button == event->button)
2971     tree_view->priv->pressed_button = -1;
2972
2973   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
2974     return gtk_tree_view_button_release_column_resize (widget, event);
2975
2976   if (tree_view->priv->button_pressed_node == NULL)
2977     return FALSE;
2978
2979   if (event->button == 1)
2980     {
2981       gtk_grab_remove (widget);
2982       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
2983           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
2984         {
2985           GtkTreePath *path = NULL;
2986
2987           path = _gtk_tree_view_find_path (tree_view,
2988                                            tree_view->priv->button_pressed_tree,
2989                                            tree_view->priv->button_pressed_node);
2990           /* Actually activate the node */
2991           if (tree_view->priv->button_pressed_node->children == NULL)
2992             gtk_tree_view_real_expand_row (tree_view, path,
2993                                            tree_view->priv->button_pressed_tree,
2994                                            tree_view->priv->button_pressed_node,
2995                                            FALSE, TRUE);
2996           else
2997             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
2998                                              tree_view->priv->button_pressed_tree,
2999                                              tree_view->priv->button_pressed_node, TRUE);
3000           gtk_tree_path_free (path);
3001         }
3002
3003       tree_view->priv->button_pressed_tree = NULL;
3004       tree_view->priv->button_pressed_node = NULL;
3005     }
3006
3007   return TRUE;
3008 }
3009
3010 static gboolean
3011 gtk_tree_view_grab_broken (GtkWidget          *widget,
3012                            GdkEventGrabBroken *event)
3013 {
3014   GtkTreeView *tree_view;
3015
3016   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
3017   g_return_val_if_fail (event != NULL, FALSE);
3018
3019   tree_view = GTK_TREE_VIEW (widget);
3020
3021   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3022     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3023
3024   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3025     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3026
3027   return TRUE;
3028 }
3029
3030 #if 0
3031 static gboolean
3032 gtk_tree_view_configure (GtkWidget *widget,
3033                          GdkEventConfigure *event)
3034 {
3035   GtkTreeView *tree_view;
3036
3037   tree_view = GTK_TREE_VIEW (widget);
3038   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3039
3040   return FALSE;
3041 }
3042 #endif
3043
3044 /* GtkWidget::motion_event function set.
3045  */
3046
3047 static gboolean
3048 coords_are_over_arrow (GtkTreeView *tree_view,
3049                        GtkRBTree   *tree,
3050                        GtkRBNode   *node,
3051                        /* these are in bin window coords */
3052                        gint         x,
3053                        gint         y)
3054 {
3055   GdkRectangle arrow;
3056   gint x2;
3057
3058   if (!GTK_WIDGET_REALIZED (tree_view))
3059     return FALSE;
3060
3061   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3062     return FALSE;
3063
3064   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3065
3066   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3067
3068   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3069
3070   arrow.width = x2 - arrow.x;
3071
3072   return (x >= arrow.x &&
3073           x < (arrow.x + arrow.width) &&
3074           y >= arrow.y &&
3075           y < (arrow.y + arrow.height));
3076 }
3077
3078 static gboolean
3079 auto_expand_timeout (gpointer data)
3080 {
3081   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3082   GtkTreePath *path;
3083
3084   if (tree_view->priv->prelight_node)
3085     {
3086       path = _gtk_tree_view_find_path (tree_view,
3087                                        tree_view->priv->prelight_tree,
3088                                        tree_view->priv->prelight_node);   
3089
3090       if (tree_view->priv->prelight_node->children)
3091         gtk_tree_view_collapse_row (tree_view, path);
3092       else
3093         gtk_tree_view_expand_row (tree_view, path, FALSE);
3094
3095       gtk_tree_path_free (path);
3096     }
3097
3098   tree_view->priv->auto_expand_timeout = 0;
3099
3100   return FALSE;
3101 }
3102
3103 static void
3104 remove_auto_expand_timeout (GtkTreeView *tree_view)
3105 {
3106   if (tree_view->priv->auto_expand_timeout != 0)
3107     {
3108       g_source_remove (tree_view->priv->auto_expand_timeout);
3109       tree_view->priv->auto_expand_timeout = 0;
3110     }
3111 }
3112
3113 static void
3114 do_prelight (GtkTreeView *tree_view,
3115              GtkRBTree   *tree,
3116              GtkRBNode   *node,
3117              /* these are in bin_window coords */
3118              gint         x,
3119              gint         y)
3120 {
3121   if (tree_view->priv->prelight_tree == tree &&
3122       tree_view->priv->prelight_node == node)
3123     {
3124       /*  We are still on the same node,
3125           but we might need to take care of the arrow  */
3126
3127       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3128         {
3129           gboolean over_arrow;
3130           gboolean flag_set;
3131
3132           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3133           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3134                                              GTK_TREE_VIEW_ARROW_PRELIT);
3135
3136           if (over_arrow != flag_set)
3137             {
3138               if (over_arrow)
3139                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3140                                         GTK_TREE_VIEW_ARROW_PRELIT);
3141               else
3142                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3143                                           GTK_TREE_VIEW_ARROW_PRELIT);
3144
3145               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3146             }
3147         }
3148
3149       return;
3150     }
3151
3152   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3153     {
3154       /*  Unprelight the old node and arrow  */
3155
3156       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3157                              GTK_RBNODE_IS_PRELIT);
3158
3159       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3160           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3161         {
3162           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3163           
3164           gtk_tree_view_draw_arrow (tree_view,
3165                                     tree_view->priv->prelight_tree,
3166                                     tree_view->priv->prelight_node,
3167                                     x,
3168                                     y);
3169         }
3170
3171       _gtk_tree_view_queue_draw_node (tree_view,
3172                                       tree_view->priv->prelight_tree,
3173                                       tree_view->priv->prelight_node,
3174                                       NULL);
3175     }
3176
3177
3178   if (tree_view->priv->hover_expand)
3179     remove_auto_expand_timeout (tree_view);
3180
3181   /*  Set the new prelight values  */
3182   tree_view->priv->prelight_node = node;
3183   tree_view->priv->prelight_tree = tree;
3184
3185   if (!node || !tree)
3186     return;
3187
3188   /*  Prelight the new node and arrow  */
3189
3190   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3191       && coords_are_over_arrow (tree_view, tree, node, x, y))
3192     {
3193       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3194
3195       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3196     }
3197
3198   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3199
3200   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3201
3202   if (tree_view->priv->hover_expand)
3203     {
3204       tree_view->priv->auto_expand_timeout = 
3205         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3206     }
3207 }
3208
3209 static void
3210 prelight_or_select (GtkTreeView *tree_view,
3211                     GtkRBTree   *tree,
3212                     GtkRBNode   *node,
3213                     /* these are in bin_window coords */
3214                     gint         x,
3215                     gint         y)
3216 {
3217   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3218   
3219   if (tree_view->priv->hover_selection &&
3220       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3221       !(tree_view->priv->edited_column &&
3222         tree_view->priv->edited_column->editable_widget))
3223     {
3224       if (node)
3225         {
3226           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3227             {
3228               GtkTreePath *path;
3229               
3230               path = _gtk_tree_view_find_path (tree_view, tree, node);
3231               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3232               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3233                 {
3234                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3235                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3236                 }
3237               gtk_tree_path_free (path);
3238             }
3239         }
3240
3241       else if (mode == GTK_SELECTION_SINGLE)
3242         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3243     }
3244
3245     do_prelight (tree_view, tree, node, x, y);
3246 }
3247
3248 static void
3249 ensure_unprelighted (GtkTreeView *tree_view)
3250 {
3251   do_prelight (tree_view,
3252                NULL, NULL,
3253                -1000, -1000); /* coords not possibly over an arrow */
3254
3255   g_assert (tree_view->priv->prelight_node == NULL);
3256 }
3257
3258
3259
3260
3261 /* Our motion arrow is either a box (in the case of the original spot)
3262  * or an arrow.  It is expander_size wide.
3263  */
3264 /*
3265  * 11111111111111
3266  * 01111111111110
3267  * 00111111111100
3268  * 00011111111000
3269  * 00001111110000
3270  * 00000111100000
3271  * 00000111100000
3272  * 00000111100000
3273  * ~ ~ ~ ~ ~ ~ ~
3274  * 00000111100000
3275  * 00000111100000
3276  * 00000111100000
3277  * 00001111110000
3278  * 00011111111000
3279  * 00111111111100
3280  * 01111111111110
3281  * 11111111111111
3282  */
3283
3284 static void
3285 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3286 {
3287   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3288   GtkWidget *widget = GTK_WIDGET (tree_view);
3289   GdkBitmap *mask = NULL;
3290   gint x;
3291   gint y;
3292   gint width;
3293   gint height;
3294   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3295   GdkWindowAttr attributes;
3296   guint attributes_mask;
3297
3298   if (!reorder ||
3299       reorder->left_column == tree_view->priv->drag_column ||
3300       reorder->right_column == tree_view->priv->drag_column)
3301     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3302   else if (reorder->left_column || reorder->right_column)
3303     {
3304       GdkRectangle visible_rect;
3305       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3306       if (reorder->left_column)
3307         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
3308       else
3309         x = reorder->right_column->button->allocation.x;
3310
3311       if (x < visible_rect.x)
3312         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3313       else if (x > visible_rect.x + visible_rect.width)
3314         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3315       else
3316         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3317     }
3318
3319   /* We want to draw the rectangle over the initial location. */
3320   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3321     {
3322       GdkGC *gc;
3323       GdkColor col;
3324
3325       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3326         {
3327           if (tree_view->priv->drag_highlight_window)
3328             {
3329               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3330                                         NULL);
3331               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3332             }
3333
3334           attributes.window_type = GDK_WINDOW_CHILD;
3335           attributes.wclass = GDK_INPUT_OUTPUT;
3336           attributes.x = tree_view->priv->drag_column_x;
3337           attributes.y = 0;
3338           width = attributes.width = tree_view->priv->drag_column->button->allocation.width;
3339           height = attributes.height = tree_view->priv->drag_column->button->allocation.height;
3340           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3341           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3342           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3343           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3344           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3345           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3346
3347           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3348           gc = gdk_gc_new (mask);
3349           col.pixel = 1;
3350           gdk_gc_set_foreground (gc, &col);
3351           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3352           col.pixel = 0;
3353           gdk_gc_set_foreground(gc, &col);
3354           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
3355           g_object_unref (gc);
3356
3357           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3358                                          mask, 0, 0);
3359           if (mask) g_object_unref (mask);
3360           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3361         }
3362     }
3363   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3364     {
3365       gint i, j = 1;
3366       GdkGC *gc;
3367       GdkColor col;
3368
3369       width = tree_view->priv->expander_size;
3370
3371       /* Get x, y, width, height of arrow */
3372       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3373       if (reorder->left_column)
3374         {
3375           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
3376           height = reorder->left_column->button->allocation.height;
3377         }
3378       else
3379         {
3380           x += reorder->right_column->button->allocation.x - width/2;
3381           height = reorder->right_column->button->allocation.height;
3382         }
3383       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3384       height += tree_view->priv->expander_size;
3385
3386       /* Create the new window */
3387       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3388         {
3389           if (tree_view->priv->drag_highlight_window)
3390             {
3391               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3392                                         NULL);
3393               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3394             }
3395
3396           attributes.window_type = GDK_WINDOW_TEMP;
3397           attributes.wclass = GDK_INPUT_OUTPUT;
3398           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3399           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3400           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3401           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3402           attributes.x = x;
3403           attributes.y = y;
3404           attributes.width = width;
3405           attributes.height = height;
3406           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3407                                                                    &attributes, attributes_mask);
3408           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3409
3410           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3411           gc = gdk_gc_new (mask);
3412           col.pixel = 1;
3413           gdk_gc_set_foreground (gc, &col);
3414           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3415
3416           /* Draw the 2 arrows as per above */
3417           col.pixel = 0;
3418           gdk_gc_set_foreground (gc, &col);
3419           for (i = 0; i < width; i ++)
3420             {
3421               if (i == (width/2 - 1))
3422                 continue;
3423               gdk_draw_line (mask, gc, i, j, i, height - j);
3424               if (i < (width/2 - 1))
3425                 j++;
3426               else
3427                 j--;
3428             }
3429           g_object_unref (gc);
3430           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3431                                          mask, 0, 0);
3432           if (mask) g_object_unref (mask);
3433         }
3434
3435       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3436       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3437     }
3438   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3439            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3440     {
3441       gint i, j = 1;
3442       GdkGC *gc;
3443       GdkColor col;
3444
3445       width = tree_view->priv->expander_size;
3446
3447       /* Get x, y, width, height of arrow */
3448       width = width/2; /* remember, the arrow only takes half the available width */
3449       gdk_window_get_origin (widget->window, &x, &y);
3450       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3451         x += widget->allocation.width - width;
3452
3453       if (reorder->left_column)
3454         height = reorder->left_column->button->allocation.height;
3455       else
3456         height = reorder->right_column->button->allocation.height;
3457
3458       y -= tree_view->priv->expander_size;
3459       height += 2*tree_view->priv->expander_size;
3460
3461       /* Create the new window */
3462       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3463           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3464         {
3465           if (tree_view->priv->drag_highlight_window)
3466             {
3467               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3468                                         NULL);
3469               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3470             }
3471
3472           attributes.window_type = GDK_WINDOW_TEMP;
3473           attributes.wclass = GDK_INPUT_OUTPUT;
3474           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3475           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3476           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3477           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3478           attributes.x = x;
3479           attributes.y = y;
3480           attributes.width = width;
3481           attributes.height = height;
3482           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3483           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3484
3485           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3486           gc = gdk_gc_new (mask);
3487           col.pixel = 1;
3488           gdk_gc_set_foreground (gc, &col);
3489           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3490
3491           /* Draw the 2 arrows as per above */
3492           col.pixel = 0;
3493           gdk_gc_set_foreground (gc, &col);
3494           j = tree_view->priv->expander_size;
3495           for (i = 0; i < width; i ++)
3496             {
3497               gint k;
3498               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3499                 k = width - i - 1;
3500               else
3501                 k = i;
3502               gdk_draw_line (mask, gc, k, j, k, height - j);
3503               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
3504               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
3505               j--;
3506             }
3507           g_object_unref (gc);
3508           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3509                                          mask, 0, 0);
3510           if (mask) g_object_unref (mask);
3511         }
3512
3513       tree_view->priv->drag_column_window_state = arrow_type;
3514       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3515    }
3516   else
3517     {
3518       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3519       gdk_window_hide (tree_view->priv->drag_highlight_window);
3520       return;
3521     }
3522
3523   gdk_window_show (tree_view->priv->drag_highlight_window);
3524   gdk_window_raise (tree_view->priv->drag_highlight_window);
3525 }
3526
3527 static gboolean
3528 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3529                                     GdkEventMotion *event)
3530 {
3531   gint x;
3532   gint new_width;
3533   GtkTreeViewColumn *column;
3534   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3535
3536   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3537
3538   if (event->is_hint || event->window != widget->window)
3539     gtk_widget_get_pointer (widget, &x, NULL);
3540   else
3541     x = event->x;
3542
3543   if (tree_view->priv->hadjustment)
3544     x += tree_view->priv->hadjustment->value;
3545
3546   new_width = gtk_tree_view_new_column_width (tree_view,
3547                                               tree_view->priv->drag_pos, &x);
3548   if (x != tree_view->priv->x_drag &&
3549       (new_width != column->fixed_width))
3550     {
3551       column->use_resized_width = TRUE;
3552       column->resized_width = new_width;
3553       gtk_widget_queue_resize (widget);
3554     }
3555
3556   return FALSE;
3557 }
3558
3559
3560 static void
3561 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3562 {
3563   GtkTreeViewColumnReorder *reorder = NULL;
3564   GList *list;
3565   gint mouse_x;
3566
3567   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3568   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3569     {
3570       reorder = (GtkTreeViewColumnReorder *) list->data;
3571       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3572         break;
3573       reorder = NULL;
3574     }
3575
3576   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3577       return;*/
3578
3579   tree_view->priv->cur_reorder = reorder;
3580   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3581 }
3582
3583 static void
3584 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3585 {
3586   GdkRectangle visible_rect;
3587   gint y;
3588   gint offset;
3589   gfloat value;
3590
3591   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3592   y += tree_view->priv->dy;
3593
3594   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3595
3596   /* see if we are near the edge. */
3597   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3598   if (offset > 0)
3599     {
3600       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3601       if (offset < 0)
3602         return;
3603     }
3604
3605   value = CLAMP (tree_view->priv->vadjustment->value + offset, 0.0,
3606                  tree_view->priv->vadjustment->upper - tree_view->priv->vadjustment->page_size);
3607   gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
3608 }
3609
3610 static gboolean
3611 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3612 {
3613   GdkRectangle visible_rect;
3614   gint x;
3615   gint offset;
3616   gfloat value;
3617
3618   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3619
3620   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3621
3622   /* See if we are near the edge. */
3623   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3624   if (offset > 0)
3625     {
3626       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3627       if (offset < 0)
3628         return TRUE;
3629     }
3630   offset = offset/3;
3631
3632   value = CLAMP (tree_view->priv->hadjustment->value + offset,
3633                  0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
3634   gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
3635
3636   return TRUE;
3637
3638 }
3639
3640 static gboolean
3641 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3642                                   GdkEventMotion *event)
3643 {
3644   GtkTreeView *tree_view = (GtkTreeView *) widget;
3645   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3646   gint x, y;
3647
3648   /* Sanity Check */
3649   if ((column == NULL) ||
3650       (event->window != tree_view->priv->drag_window))
3651     return FALSE;
3652
3653   /* Handle moving the header */
3654   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3655   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3656              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
3657   gdk_window_move (tree_view->priv->drag_window, x, y);
3658   
3659   /* autoscroll, if needed */
3660   gtk_tree_view_horizontal_autoscroll (tree_view);
3661   /* Update the current reorder position and arrow; */
3662   gtk_tree_view_update_current_reorder (tree_view);
3663
3664   return TRUE;
3665 }
3666
3667 static void
3668 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3669 {
3670   remove_scroll_timeout (tree_view);
3671   gtk_grab_remove (GTK_WIDGET (tree_view));
3672
3673   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3674
3675   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3676     {
3677       GtkTreePath *tmp_path;
3678
3679       /* The anchor path should be set to the start path */
3680       tmp_path = _gtk_tree_view_find_path (tree_view,
3681                                            tree_view->priv->rubber_band_start_tree,
3682                                            tree_view->priv->rubber_band_start_node);
3683
3684       if (tree_view->priv->anchor)
3685         gtk_tree_row_reference_free (tree_view->priv->anchor);
3686
3687       tree_view->priv->anchor =
3688         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3689                                           tree_view->priv->model,
3690                                           tmp_path);
3691
3692       gtk_tree_path_free (tmp_path);
3693
3694       /* ... and the cursor to the end path */
3695       tmp_path = _gtk_tree_view_find_path (tree_view,
3696                                            tree_view->priv->rubber_band_end_tree,
3697                                            tree_view->priv->rubber_band_end_node);
3698       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3699       gtk_tree_path_free (tmp_path);
3700
3701       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3702     }
3703
3704   /* Clear status variables */
3705   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3706   tree_view->priv->rubber_band_shift = 0;
3707   tree_view->priv->rubber_band_ctrl = 0;
3708
3709   tree_view->priv->rubber_band_start_node = NULL;
3710   tree_view->priv->rubber_band_start_tree = NULL;
3711   tree_view->priv->rubber_band_end_node = NULL;
3712   tree_view->priv->rubber_band_end_tree = NULL;
3713 }
3714
3715 static void
3716 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3717                                                  GtkRBTree   *start_tree,
3718                                                  GtkRBNode   *start_node,
3719                                                  GtkRBTree   *end_tree,
3720                                                  GtkRBNode   *end_node,
3721                                                  gboolean     select,
3722                                                  gboolean     skip_start,
3723                                                  gboolean     skip_end)
3724 {
3725   if (start_node == end_node)
3726     return;
3727
3728   /* We skip the first node and jump inside the loop */
3729   if (skip_start)
3730     goto skip_first;
3731
3732   do
3733     {
3734       /* Small optimization by assuming insensitive nodes are never
3735        * selected.
3736        */
3737       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3738         {
3739           GtkTreePath *path;
3740           gboolean selectable;
3741
3742           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3743           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3744           gtk_tree_path_free (path);
3745
3746           if (!selectable)
3747             goto node_not_selectable;
3748         }
3749
3750       if (select)
3751         {
3752           if (tree_view->priv->rubber_band_shift)
3753             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3754           else if (tree_view->priv->rubber_band_ctrl)
3755             {
3756               /* Toggle the selection state */
3757               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3758                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3759               else
3760                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3761             }
3762           else
3763             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3764         }
3765       else
3766         {
3767           /* Mirror the above */
3768           if (tree_view->priv->rubber_band_shift)
3769             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3770           else if (tree_view->priv->rubber_band_ctrl)
3771             {
3772               /* Toggle the selection state */
3773               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3774                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3775               else
3776                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3777             }
3778           else
3779             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3780         }
3781
3782       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3783
3784 node_not_selectable:
3785       if (start_node == end_node)
3786         break;
3787
3788 skip_first:
3789
3790       if (start_node->children)
3791         {
3792           start_tree = start_node->children;
3793           start_node = start_tree->root;
3794           while (start_node->left != start_tree->nil)
3795             start_node = start_node->left;
3796         }
3797       else
3798         {
3799           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3800
3801           if (!start_tree)
3802             /* Ran out of tree */
3803             break;
3804         }
3805
3806       if (skip_end && start_node == end_node)
3807         break;
3808     }
3809   while (TRUE);
3810 }
3811
3812 static void
3813 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3814 {
3815   GtkRBTree *start_tree, *end_tree;
3816   GtkRBNode *start_node, *end_node;
3817
3818   _gtk_rbtree_find_offset (tree_view->priv->tree, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_tree, &start_node);
3819   _gtk_rbtree_find_offset (tree_view->priv->tree, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_tree, &end_node);
3820
3821   /* Handle the start area first */
3822   if (!tree_view->priv->rubber_band_start_node)
3823     {
3824       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3825                                                        start_tree,
3826                                                        start_node,
3827                                                        end_tree,
3828                                                        end_node,
3829                                                        TRUE,
3830                                                        FALSE,
3831                                                        FALSE);
3832     }
3833   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3834            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3835     {
3836       /* New node is above the old one; selection became bigger */
3837       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3838                                                        start_tree,
3839                                                        start_node,
3840                                                        tree_view->priv->rubber_band_start_tree,
3841                                                        tree_view->priv->rubber_band_start_node,
3842                                                        TRUE,
3843                                                        FALSE,
3844                                                        TRUE);
3845     }
3846   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3847            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3848     {
3849       /* New node is below the old one; selection became smaller */
3850       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3851                                                        tree_view->priv->rubber_band_start_tree,
3852                                                        tree_view->priv->rubber_band_start_node,
3853                                                        start_tree,
3854                                                        start_node,
3855                                                        FALSE,
3856                                                        FALSE,
3857                                                        TRUE);
3858     }
3859
3860   tree_view->priv->rubber_band_start_tree = start_tree;
3861   tree_view->priv->rubber_band_start_node = start_node;
3862
3863   /* Next, handle the end area */
3864   if (!tree_view->priv->rubber_band_end_node)
3865     {
3866       /* In the event this happens, start_node was also NULL; this case is
3867        * handled above.
3868        */
3869     }
3870   else if (!end_node)
3871     {
3872       /* Find the last node in the tree */
3873       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3874                                &end_tree, &end_node);
3875
3876       /* Selection reached end of the tree */
3877       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3878                                                        tree_view->priv->rubber_band_end_tree,
3879                                                        tree_view->priv->rubber_band_end_node,
3880                                                        end_tree,
3881                                                        end_node,
3882                                                        TRUE,
3883                                                        TRUE,
3884                                                        FALSE);
3885     }
3886   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3887            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3888     {
3889       /* New node is below the old one; selection became bigger */
3890       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3891                                                        tree_view->priv->rubber_band_end_tree,
3892                                                        tree_view->priv->rubber_band_end_node,
3893                                                        end_tree,
3894                                                        end_node,
3895                                                        TRUE,
3896                                                        TRUE,
3897                                                        FALSE);
3898     }
3899   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
3900            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3901     {
3902       /* New node is above the old one; selection became smaller */
3903       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3904                                                        end_tree,
3905                                                        end_node,
3906                                                        tree_view->priv->rubber_band_end_tree,
3907                                                        tree_view->priv->rubber_band_end_node,
3908                                                        FALSE,
3909                                                        TRUE,
3910                                                        FALSE);
3911     }
3912
3913   tree_view->priv->rubber_band_end_tree = end_tree;
3914   tree_view->priv->rubber_band_end_node = end_node;
3915 }
3916
3917 static void
3918 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
3919 {
3920   gint x, y;
3921   GdkRectangle old_area;
3922   GdkRectangle new_area;
3923   GdkRectangle common;
3924   GdkRegion *invalid_region;
3925
3926   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
3927   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
3928   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
3929   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
3930
3931   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
3932
3933   x = MAX (x, 0);
3934   y = MAX (y, 0) + tree_view->priv->dy;
3935
3936   new_area.x = MIN (tree_view->priv->press_start_x, x);
3937   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
3938   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
3939   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
3940
3941   invalid_region = gdk_region_rectangle (&old_area);
3942   gdk_region_union_with_rect (invalid_region, &new_area);
3943
3944   gdk_rectangle_intersect (&old_area, &new_area, &common);
3945   if (common.width > 2 && common.height > 2)
3946     {
3947       GdkRegion *common_region;
3948
3949       /* make sure the border is invalidated */
3950       common.x += 1;
3951       common.y += 1;
3952       common.width -= 2;
3953       common.height -= 2;
3954
3955       common_region = gdk_region_rectangle (&common);
3956
3957       gdk_region_subtract (invalid_region, common_region);
3958       gdk_region_destroy (common_region);
3959     }
3960
3961   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
3962
3963   gdk_region_destroy (invalid_region);
3964
3965   tree_view->priv->rubber_band_x = x;
3966   tree_view->priv->rubber_band_y = y;
3967
3968   gtk_tree_view_update_rubber_band_selection (tree_view);
3969 }
3970
3971 static void
3972 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
3973                                 GdkRectangle *area)
3974 {
3975   cairo_t *cr;
3976   GdkRectangle rect;
3977   GdkRectangle rubber_rect;
3978
3979   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
3980   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
3981   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
3982   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
3983
3984   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
3985     return;
3986
3987   cr = gdk_cairo_create (tree_view->priv->bin_window);
3988   cairo_set_line_width (cr, 1.0);
3989
3990   cairo_set_source_rgba (cr,
3991                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
3992                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
3993                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
3994                          .25);
3995
3996   gdk_cairo_rectangle (cr, &rect);
3997   cairo_clip (cr);
3998   cairo_paint (cr);
3999
4000   cairo_set_source_rgb (cr,
4001                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4002                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4003                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
4004
4005   cairo_rectangle (cr,
4006                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4007                    rubber_rect.width - 1, rubber_rect.height - 1);
4008   cairo_stroke (cr);
4009
4010   cairo_destroy (cr);
4011 }
4012
4013 static gboolean
4014 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4015                                  GdkEventMotion *event)
4016 {
4017   GtkTreeView *tree_view;
4018   GtkRBTree *tree;
4019   GtkRBNode *node;
4020   gint new_y;
4021
4022   tree_view = (GtkTreeView *) widget;
4023
4024   if (tree_view->priv->tree == NULL)
4025     return FALSE;
4026
4027   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4028     {
4029       gtk_grab_add (GTK_WIDGET (tree_view));
4030       gtk_tree_view_update_rubber_band (tree_view);
4031
4032       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4033     }
4034   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4035     {
4036       gtk_tree_view_update_rubber_band (tree_view);
4037
4038       add_scroll_timeout (tree_view);
4039     }
4040
4041   /* only check for an initiated drag when a button is pressed */
4042   if (tree_view->priv->pressed_button >= 0
4043       && !tree_view->priv->rubber_band_status)
4044     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4045
4046   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4047   if (new_y < 0)
4048     new_y = 0;
4049
4050   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4051
4052   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4053   if ((tree_view->priv->button_pressed_node != NULL) &&
4054       (tree_view->priv->button_pressed_node != node))
4055     node = NULL;
4056
4057   prelight_or_select (tree_view, tree, node, event->x, event->y);
4058
4059   return TRUE;
4060 }
4061
4062 static gboolean
4063 gtk_tree_view_motion (GtkWidget      *widget,
4064                       GdkEventMotion *event)
4065 {
4066   GtkTreeView *tree_view;
4067
4068   tree_view = (GtkTreeView *) widget;
4069
4070   /* Resizing a column */
4071   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4072     return gtk_tree_view_motion_resize_column (widget, event);
4073
4074   /* Drag column */
4075   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4076     return gtk_tree_view_motion_drag_column (widget, event);
4077
4078   /* Sanity check it */
4079   if (event->window == tree_view->priv->bin_window)
4080     return gtk_tree_view_motion_bin_window (widget, event);
4081
4082   return FALSE;
4083 }
4084
4085 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4086  * the tree is empty.
4087  */
4088 static void
4089 invalidate_empty_focus (GtkTreeView *tree_view)
4090 {
4091   GdkRectangle area;
4092
4093   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4094     return;
4095
4096   area.x = 0;
4097   area.y = 0;
4098   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4099   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4100 }
4101
4102 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4103  * is empty.
4104  */
4105 static void
4106 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4107 {
4108   gint w, h;
4109
4110   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4111     return;
4112
4113   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4114
4115   w -= 2;
4116   h -= 2;
4117
4118   if (w > 0 && h > 0)
4119     gtk_paint_focus (GTK_WIDGET (tree_view)->style,
4120                      tree_view->priv->bin_window,
4121                      GTK_WIDGET_STATE (tree_view),
4122                      clip_area,
4123                      GTK_WIDGET (tree_view),
4124                      NULL,
4125                      1, 1, w, h);
4126 }
4127
4128 static void
4129 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4130                                GdkEventExpose *event,
4131                                gint            n_visible_columns)
4132 {
4133   GList *list = tree_view->priv->columns;
4134   gint i = 0;
4135   gint current_x = 0;
4136
4137   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4138       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4139     return;
4140
4141   /* Only draw the lines for visible rows and columns */
4142   for (list = tree_view->priv->columns; list; list = list->next, i++)
4143     {
4144       GtkTreeViewColumn *column = list->data;
4145
4146       /* We don't want a line for the last column */
4147       if (i == n_visible_columns - 1)
4148         break;
4149
4150       if (! column->visible)
4151         continue;
4152
4153       current_x += column->width;
4154
4155       gdk_draw_line (event->window,
4156                      tree_view->priv->grid_line_gc,
4157                      current_x - 1, 0,
4158                      current_x - 1, tree_view->priv->height);
4159     }
4160 }
4161
4162 /* Warning: Very scary function.
4163  * Modify at your own risk
4164  *
4165  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4166  * FIXME: It's not...
4167  */
4168 static gboolean
4169 gtk_tree_view_bin_expose (GtkWidget      *widget,
4170                           GdkEventExpose *event)
4171 {
4172   GtkTreeView *tree_view;
4173   GtkTreePath *path;
4174   GtkRBTree *tree;
4175   GList *list;
4176   GtkRBNode *node;
4177   GtkRBNode *cursor = NULL;
4178   GtkRBTree *cursor_tree = NULL;
4179   GtkRBNode *drag_highlight = NULL;
4180   GtkRBTree *drag_highlight_tree = NULL;
4181   GtkTreeIter iter;
4182   gint new_y;
4183   gint y_offset, cell_offset;
4184   gint max_height;
4185   gint depth;
4186   GdkRectangle background_area;
4187   GdkRectangle cell_area;
4188   guint flags;
4189   gint highlight_x;
4190   gint expander_cell_width;
4191   gint bin_window_width;
4192   gint bin_window_height;
4193   GtkTreePath *cursor_path;
4194   GtkTreePath *drag_dest_path;
4195   GList *first_column, *last_column;
4196   gint vertical_separator;
4197   gint horizontal_separator;
4198   gint focus_line_width;
4199   gboolean allow_rules;
4200   gboolean has_special_cell;
4201   gboolean rtl;
4202   gint n_visible_columns;
4203   gint pointer_x, pointer_y;
4204   gint grid_line_width;
4205   gboolean got_pointer = FALSE;
4206   gboolean row_ending_details;
4207   gboolean draw_vgrid_lines, draw_hgrid_lines;
4208
4209   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
4210
4211   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4212
4213   tree_view = GTK_TREE_VIEW (widget);
4214
4215   gtk_widget_style_get (widget,
4216                         "horizontal-separator", &horizontal_separator,
4217                         "vertical-separator", &vertical_separator,
4218                         "allow-rules", &allow_rules,
4219                         "focus-line-width", &focus_line_width,
4220                         "row-ending-details", &row_ending_details,
4221                         NULL);
4222
4223   if (tree_view->priv->tree == NULL)
4224     {
4225       draw_empty_focus (tree_view, &event->area);
4226       return TRUE;
4227     }
4228
4229   /* clip event->area to the visible area */
4230   if (event->area.height < 0)
4231     return TRUE;
4232
4233   validate_visible_area (tree_view);
4234
4235   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4236
4237   if (new_y < 0)
4238     new_y = 0;
4239   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4240   gdk_drawable_get_size (tree_view->priv->bin_window,
4241                          &bin_window_width, &bin_window_height);
4242
4243   if (tree_view->priv->height < bin_window_height)
4244     {
4245       gtk_paint_flat_box (widget->style,
4246                           event->window,
4247                           widget->state,
4248                           GTK_SHADOW_NONE,
4249                           &event->area,
4250                           widget,
4251                           "cell_even",
4252                           0, tree_view->priv->height,
4253                           bin_window_width,
4254                           bin_window_height - tree_view->priv->height);
4255     }
4256
4257   if (node == NULL)
4258     return TRUE;
4259
4260   /* find the path for the node */
4261   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4262                                    tree,
4263                                    node);
4264   gtk_tree_model_get_iter (tree_view->priv->model,
4265                            &iter,
4266                            path);
4267   depth = gtk_tree_path_get_depth (path);
4268   gtk_tree_path_free (path);
4269   
4270   cursor_path = NULL;
4271   drag_dest_path = NULL;
4272
4273   if (tree_view->priv->cursor)
4274     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4275
4276   if (cursor_path)
4277     _gtk_tree_view_find_node (tree_view, cursor_path,
4278                               &cursor_tree, &cursor);
4279
4280   if (tree_view->priv->drag_dest_row)
4281     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4282
4283   if (drag_dest_path)
4284     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4285                               &drag_highlight_tree, &drag_highlight);
4286
4287   draw_vgrid_lines =
4288     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4289     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4290   draw_hgrid_lines =
4291     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4292     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4293
4294   if (draw_vgrid_lines || draw_hgrid_lines)
4295     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4296   
4297   n_visible_columns = 0;
4298   for (list = tree_view->priv->columns; list; list = list->next)
4299     {
4300       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4301         continue;
4302       n_visible_columns ++;
4303     }
4304
4305   /* Find the last column */
4306   for (last_column = g_list_last (tree_view->priv->columns);
4307        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4308        last_column = last_column->prev)
4309     ;
4310
4311   /* and the first */
4312   for (first_column = g_list_first (tree_view->priv->columns);
4313        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4314        first_column = first_column->next)
4315     ;
4316
4317   /* Actually process the expose event.  To do this, we want to
4318    * start at the first node of the event, and walk the tree in
4319    * order, drawing each successive node.
4320    */
4321
4322   do
4323     {
4324       gboolean parity;
4325       gboolean is_separator = FALSE;
4326       gboolean is_first = FALSE;
4327       gboolean is_last = FALSE;
4328       
4329       is_separator = row_is_separator (tree_view, &iter, NULL);
4330
4331       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4332
4333       cell_offset = 0;
4334       highlight_x = 0; /* should match x coord of first cell */
4335       expander_cell_width = 0;
4336
4337       background_area.y = y_offset + event->area.y;
4338       background_area.height = max_height;
4339
4340       flags = 0;
4341
4342       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4343         flags |= GTK_CELL_RENDERER_PRELIT;
4344
4345       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4346         flags |= GTK_CELL_RENDERER_SELECTED;
4347
4348       parity = _gtk_rbtree_node_find_parity (tree, node);
4349
4350       /* we *need* to set cell data on all cells before the call
4351        * to _has_special_cell, else _has_special_cell() does not
4352        * return a correct value.
4353        */
4354       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4355            list;
4356            list = (rtl ? list->prev : list->next))
4357         {
4358           GtkTreeViewColumn *column = list->data;
4359           gtk_tree_view_column_cell_set_cell_data (column,
4360                                                    tree_view->priv->model,
4361                                                    &iter,
4362                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4363                                                    node->children?TRUE:FALSE);
4364         }
4365
4366       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4367
4368       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4369            list;
4370            list = (rtl ? list->prev : list->next))
4371         {
4372           GtkTreeViewColumn *column = list->data;
4373           const gchar *detail = NULL;
4374           GtkStateType state;
4375
4376           if (!column->visible)
4377             continue;
4378
4379           if (cell_offset > event->area.x + event->area.width ||
4380               cell_offset + column->width < event->area.x)
4381             {
4382               cell_offset += column->width;
4383               continue;
4384             }
4385
4386           if (column->show_sort_indicator)
4387             flags |= GTK_CELL_RENDERER_SORTED;
4388           else
4389             flags &= ~GTK_CELL_RENDERER_SORTED;
4390
4391           if (cursor == node)
4392             flags |= GTK_CELL_RENDERER_FOCUSED;
4393           else
4394             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4395
4396           background_area.x = cell_offset;
4397           background_area.width = column->width;
4398
4399           cell_area = background_area;
4400           cell_area.y += vertical_separator / 2;
4401           cell_area.x += horizontal_separator / 2;
4402           cell_area.height -= vertical_separator;
4403           cell_area.width -= horizontal_separator;
4404
4405           if (draw_vgrid_lines)
4406             {
4407               if (list == first_column)
4408                 {
4409                   cell_area.width -= grid_line_width / 2;
4410                 }
4411               else if (list == last_column)
4412                 {
4413                   cell_area.x += grid_line_width / 2;
4414                   cell_area.width -= grid_line_width / 2;
4415                 }
4416               else
4417                 {
4418                   cell_area.x += grid_line_width / 2;
4419                   cell_area.width -= grid_line_width;
4420                 }
4421             }
4422
4423           if (draw_hgrid_lines)
4424             {
4425               cell_area.y += grid_line_width / 2;
4426               cell_area.height -= grid_line_width;
4427             }
4428
4429           if (gdk_region_rect_in (event->region, &background_area) == GDK_OVERLAP_RECTANGLE_OUT)
4430             {
4431               cell_offset += column->width;
4432               continue;
4433             }
4434
4435           gtk_tree_view_column_cell_set_cell_data (column,
4436                                                    tree_view->priv->model,
4437                                                    &iter,
4438                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4439                                                    node->children?TRUE:FALSE);
4440
4441           /* Select the detail for drawing the cell.  relevant
4442            * factors are parity, sortedness, and whether to
4443            * display rules.
4444            */
4445           if (allow_rules && tree_view->priv->has_rules)
4446             {
4447               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4448                   n_visible_columns >= 3)
4449                 {
4450                   if (parity)
4451                     detail = "cell_odd_ruled_sorted";
4452                   else
4453                     detail = "cell_even_ruled_sorted";
4454                 }
4455               else
4456                 {
4457                   if (parity)
4458                     detail = "cell_odd_ruled";
4459                   else
4460                     detail = "cell_even_ruled";
4461                 }
4462             }
4463           else
4464             {
4465               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4466                   n_visible_columns >= 3)
4467                 {
4468                   if (parity)
4469                     detail = "cell_odd_sorted";
4470                   else
4471                     detail = "cell_even_sorted";
4472                 }
4473               else
4474                 {
4475                   if (parity)
4476                     detail = "cell_odd";
4477                   else
4478                     detail = "cell_even";
4479                 }
4480             }
4481
4482           g_assert (detail);
4483
4484           if (widget->state == GTK_STATE_INSENSITIVE)
4485             state = GTK_STATE_INSENSITIVE;          
4486           else if (flags & GTK_CELL_RENDERER_SELECTED)
4487             state = GTK_STATE_SELECTED;
4488           else
4489             state = GTK_STATE_NORMAL;
4490
4491           /* Draw background */
4492           if (row_ending_details)
4493             {
4494               char new_detail[128];
4495
4496               is_first = (rtl ? !list->next : !list->prev);
4497               is_last = (rtl ? !list->prev : !list->next);
4498
4499               /* (I don't like the snprintfs either, but couldn't find a
4500                * less messy way).
4501                */
4502               if (is_first && is_last)
4503                 g_snprintf (new_detail, 127, "%s", detail);
4504               else if (is_first)
4505                 g_snprintf (new_detail, 127, "%s_start", detail);
4506               else if (is_last)
4507                 g_snprintf (new_detail, 127, "%s_end", detail);
4508               else
4509                 g_snprintf (new_detail, 128, "%s_middle", detail);
4510
4511               gtk_paint_flat_box (widget->style,
4512                                   event->window,
4513                                   state,
4514                                   GTK_SHADOW_NONE,
4515                                   &event->area,
4516                                   widget,
4517                                   new_detail,
4518                                   background_area.x,
4519                                   background_area.y,
4520                                   background_area.width,
4521                                   background_area.height);
4522             }
4523           else
4524             {
4525               gtk_paint_flat_box (widget->style,
4526                                   event->window,
4527                                   state,
4528                                   GTK_SHADOW_NONE,
4529                                   &event->area,
4530                                   widget,
4531                                   detail,
4532                                   background_area.x,
4533                                   background_area.y,
4534                                   background_area.width,
4535                                   background_area.height);
4536             }
4537
4538           if (draw_hgrid_lines)
4539             {
4540               if (background_area.y > 0)
4541                 gdk_draw_line (event->window,
4542                                tree_view->priv->grid_line_gc,
4543                                background_area.x, background_area.y,
4544                                background_area.x + background_area.width,
4545                                background_area.y);
4546
4547               if (y_offset + max_height >= event->area.height)
4548                 gdk_draw_line (event->window,
4549                                tree_view->priv->grid_line_gc,
4550                                background_area.x, background_area.y + max_height,
4551                                background_area.x + background_area.width,
4552                                background_area.y + max_height);
4553             }
4554
4555           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4556               tree_view->priv->tree_lines_enabled)
4557             {
4558               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4559                   && depth > 1)
4560                 {
4561                   gdk_draw_line (event->window,
4562                                  tree_view->priv->tree_line_gc,
4563                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4564                                  background_area.y + background_area.height / 2,
4565                                  background_area.x + tree_view->priv->expander_size * (depth - 1.1),
4566                                  background_area.y + background_area.height / 2);
4567                 }
4568               else if (depth > 1)
4569                 {
4570                   gdk_draw_line (event->window,
4571                                  tree_view->priv->tree_line_gc,
4572                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4573                                  background_area.y + background_area.height / 2,
4574                                  background_area.x + tree_view->priv->expander_size * (depth - 0.5),
4575                                  background_area.y + background_area.height / 2);
4576                 }
4577
4578               if (depth > 1)
4579                 {
4580                   gint i;
4581                   GtkRBNode *tmp_node;
4582                   GtkRBTree *tmp_tree;
4583
4584                   if (!_gtk_rbtree_next (tree, node))
4585                     gdk_draw_line (event->window,
4586                                    tree_view->priv->tree_line_gc,
4587                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4588                                    background_area.y,
4589                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4590                                    background_area.y + background_area.height / 2);
4591                   else
4592                     gdk_draw_line (event->window,
4593                                    tree_view->priv->tree_line_gc,
4594                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4595                                    background_area.y,
4596                                    background_area.x + tree_view->priv->expander_size * (depth - 1.5),
4597                                    background_area.y + background_area.height);
4598
4599                   tmp_node = tree->parent_node;
4600                   tmp_tree = tree->parent_tree;
4601
4602                   for (i = depth - 2; i > 0; i--)
4603                     {
4604                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4605                         gdk_draw_line (event->window,
4606                                        tree_view->priv->tree_line_gc,
4607                                        background_area.x + tree_view->priv->expander_size * (i - 0.5),
4608                                        background_area.y,
4609                                        background_area.x + tree_view->priv->expander_size * (i - 0.5),
4610                                        background_area.y + background_area.height);
4611
4612                       tmp_node = tmp_tree->parent_node;
4613                       tmp_tree = tmp_tree->parent_tree;
4614                     }
4615                 }
4616             }
4617
4618           if (gtk_tree_view_is_expander_column (tree_view, column))
4619             {
4620               if (!rtl)
4621                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4622               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4623
4624               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4625                 {
4626                   if (!rtl)
4627                     cell_area.x += depth * tree_view->priv->expander_size;
4628                   cell_area.width -= depth * tree_view->priv->expander_size;
4629                 }
4630
4631               /* If we have an expander column, the highlight underline
4632                * starts with that column, so that it indicates which
4633                * level of the tree we're dropping at.
4634                */
4635               highlight_x = cell_area.x;
4636               expander_cell_width = cell_area.width;
4637
4638               if (is_separator)
4639                 gtk_paint_hline (widget->style,
4640                                  event->window,
4641                                  state,
4642                                  &cell_area,
4643                                  widget,
4644                                  NULL,
4645                                  cell_area.x,
4646                                  cell_area.x + cell_area.width,
4647                                  cell_area.y + cell_area.height / 2);
4648               else
4649                 _gtk_tree_view_column_cell_render (column,
4650                                                    event->window,
4651                                                    &background_area,
4652                                                    &cell_area,
4653                                                    &event->area,
4654                                                    flags);
4655               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4656                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4657                 {
4658                   if (!got_pointer)
4659                     {
4660                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4661                                               &pointer_x, &pointer_y, NULL);
4662                       got_pointer = TRUE;
4663                     }
4664
4665                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4666                                             tree,
4667                                             node,
4668                                             pointer_x, pointer_y);
4669                 }
4670             }
4671           else
4672             {
4673               if (is_separator)
4674                 gtk_paint_hline (widget->style,
4675                                  event->window,
4676                                  state,
4677                                  &cell_area,
4678                                  widget,
4679                                  NULL,
4680                                  cell_area.x,
4681                                  cell_area.x + cell_area.width,
4682                                  cell_area.y + cell_area.height / 2);
4683               else
4684                 _gtk_tree_view_column_cell_render (column,
4685                                                    event->window,
4686                                                    &background_area,
4687                                                    &cell_area,
4688                                                    &event->area,
4689                                                    flags);
4690             }
4691           if (node == cursor && has_special_cell &&
4692               ((column == tree_view->priv->focus_column &&
4693                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4694                 GTK_WIDGET_HAS_FOCUS (widget)) ||
4695                (column == tree_view->priv->edited_column)))
4696             {
4697               _gtk_tree_view_column_cell_draw_focus (column,
4698                                                      event->window,
4699                                                      &background_area,
4700                                                      &cell_area,
4701                                                      &event->area,
4702                                                      flags);
4703             }
4704           cell_offset += column->width;
4705         }
4706
4707       if (node == drag_highlight)
4708         {
4709           /* Draw indicator for the drop
4710            */
4711           gint highlight_y = -1;
4712           GtkRBTree *tree = NULL;
4713           GtkRBNode *node = NULL;
4714           gint width;
4715
4716           switch (tree_view->priv->drag_dest_pos)
4717             {
4718             case GTK_TREE_VIEW_DROP_BEFORE:
4719               highlight_y = background_area.y - 1;
4720               if (highlight_y < 0)
4721                       highlight_y = 0;
4722               break;
4723
4724             case GTK_TREE_VIEW_DROP_AFTER:
4725               highlight_y = background_area.y + background_area.height - 1;
4726               break;
4727
4728             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4729             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4730               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4731
4732               if (tree == NULL)
4733                 break;
4734               gdk_drawable_get_size (tree_view->priv->bin_window,
4735                                      &width, NULL);
4736
4737               if (row_ending_details)
4738                 gtk_paint_focus (widget->style,
4739                                  tree_view->priv->bin_window,
4740                                  GTK_WIDGET_STATE (widget),
4741                                  &event->area,
4742                                  widget,
4743                                  (is_first
4744                                   ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4745                                   : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4746                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4747                                  - focus_line_width / 2,
4748                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4749                                - focus_line_width + 1);
4750               else
4751                 gtk_paint_focus (widget->style,
4752                                  tree_view->priv->bin_window,
4753                                  GTK_WIDGET_STATE (widget),
4754                                  &event->area,
4755                                  widget,
4756                                  "treeview-drop-indicator",
4757                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4758                                  - focus_line_width / 2,
4759                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4760                                  - focus_line_width + 1);
4761               break;
4762             }
4763
4764           if (highlight_y >= 0)
4765             {
4766               gdk_draw_line (event->window,
4767                              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
4768                              rtl ? highlight_x + expander_cell_width : highlight_x,
4769                              highlight_y,
4770                              rtl ? 0 : bin_window_width,
4771                              highlight_y);
4772             }
4773         }
4774
4775       /* draw the big row-spanning focus rectangle, if needed */
4776       if (!has_special_cell && node == cursor &&
4777           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4778           GTK_WIDGET_HAS_FOCUS (widget))
4779         {
4780           gint tmp_y, tmp_height;
4781           gint width;
4782           GtkStateType focus_rect_state;
4783
4784           focus_rect_state =
4785             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4786             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4787              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4788               GTK_STATE_NORMAL));
4789
4790           gdk_drawable_get_size (tree_view->priv->bin_window,
4791                                  &width, NULL);
4792           
4793           if (draw_hgrid_lines)
4794             {
4795               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4796               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4797             }
4798           else
4799             {
4800               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4801               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4802             }
4803
4804           if (row_ending_details)
4805             gtk_paint_focus (widget->style,
4806                              tree_view->priv->bin_window,
4807                              focus_rect_state,
4808                              &event->area,
4809                              widget,
4810                              (is_first
4811                               ? (is_last ? "treeview" : "treeview-left" )
4812                               : (is_last ? "treeview-right" : "treeview-middle" )),
4813                              0, tmp_y,
4814                              width, tmp_height);
4815           else
4816             gtk_paint_focus (widget->style,
4817                              tree_view->priv->bin_window,
4818                              focus_rect_state,
4819                              &event->area,
4820                              widget,
4821                              "treeview",
4822                              0, tmp_y,
4823                              width, tmp_height);
4824         }
4825
4826       y_offset += max_height;
4827       if (node->children)
4828         {
4829           GtkTreeIter parent = iter;
4830           gboolean has_child;
4831
4832           tree = node->children;
4833           node = tree->root;
4834
4835           g_assert (node != tree->nil);
4836
4837           while (node->left != tree->nil)
4838             node = node->left;
4839           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4840                                                     &iter,
4841                                                     &parent);
4842           depth++;
4843
4844           /* Sanity Check! */
4845           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4846         }
4847       else
4848         {
4849           gboolean done = FALSE;
4850
4851           do
4852             {
4853               node = _gtk_rbtree_next (tree, node);
4854               if (node != NULL)
4855                 {
4856                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4857                   done = TRUE;
4858
4859                   /* Sanity Check! */
4860                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4861                 }
4862               else
4863                 {
4864                   GtkTreeIter parent_iter = iter;
4865                   gboolean has_parent;
4866
4867                   node = tree->parent_node;
4868                   tree = tree->parent_tree;
4869                   if (tree == NULL)
4870                     /* we should go to done to free some memory */
4871                     goto done;
4872                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4873                                                            &iter,
4874                                                            &parent_iter);
4875                   depth--;
4876
4877                   /* Sanity check */
4878                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
4879                 }
4880             }
4881           while (!done);
4882         }
4883     }
4884   while (y_offset < event->area.height);
4885
4886 done:
4887   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
4888
4889  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4890    {
4891      GdkRectangle *rectangles;
4892      gint n_rectangles;
4893
4894      gdk_region_get_rectangles (event->region,
4895                                 &rectangles,
4896                                 &n_rectangles);
4897
4898      while (n_rectangles--)
4899        gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
4900
4901      g_free (rectangles);
4902    }
4903
4904   if (cursor_path)
4905     gtk_tree_path_free (cursor_path);
4906
4907   if (drag_dest_path)
4908     gtk_tree_path_free (drag_dest_path);
4909
4910   return FALSE;
4911 }
4912
4913 static gboolean
4914 gtk_tree_view_expose (GtkWidget      *widget,
4915                       GdkEventExpose *event)
4916 {
4917   GtkTreeView *tree_view;
4918
4919   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
4920
4921   tree_view = GTK_TREE_VIEW (widget);
4922
4923   if (event->window == tree_view->priv->bin_window)
4924     {
4925       gboolean retval;
4926       GList *tmp_list;
4927
4928       retval = gtk_tree_view_bin_expose (widget, event);
4929
4930       /* We can't just chain up to Container::expose as it will try to send the
4931        * event to the headers, so we handle propagating it to our children
4932        * (eg. widgets being edited) ourselves.
4933        */
4934       tmp_list = tree_view->priv->children;
4935       while (tmp_list)
4936         {
4937           GtkTreeViewChild *child = tmp_list->data;
4938           tmp_list = tmp_list->next;
4939
4940           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
4941         }
4942
4943       return retval;
4944     }
4945
4946   else if (event->window == tree_view->priv->header_window)
4947     {
4948       GList *list;
4949       
4950       for (list = tree_view->priv->columns; list != NULL; list = list->next)
4951         {
4952           GtkTreeViewColumn *column = list->data;
4953
4954           if (column == tree_view->priv->drag_column)
4955             continue;
4956
4957           if (column->visible)
4958             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4959                                             column->button,
4960                                             event);
4961         }
4962     }
4963   else if (event->window == tree_view->priv->drag_window)
4964     {
4965       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4966                                       tree_view->priv->drag_column->button,
4967                                       event);
4968     }
4969   return TRUE;
4970 }
4971
4972 enum
4973 {
4974   DROP_HOME,
4975   DROP_RIGHT,
4976   DROP_LEFT,
4977   DROP_END
4978 };
4979
4980 /* returns 0x1 when no column has been found -- yes it's hackish */
4981 static GtkTreeViewColumn *
4982 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
4983                                GtkTreeViewColumn *column,
4984                                gint               drop_position)
4985 {
4986   GtkTreeViewColumn *left_column = NULL;
4987   GtkTreeViewColumn *cur_column = NULL;
4988   GList *tmp_list;
4989
4990   if (!column->reorderable)
4991     return (GtkTreeViewColumn *)0x1;
4992
4993   switch (drop_position)
4994     {
4995       case DROP_HOME:
4996         /* find first column where we can drop */
4997         tmp_list = tree_view->priv->columns;
4998         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
4999           return (GtkTreeViewColumn *)0x1;
5000
5001         while (tmp_list)
5002           {
5003             g_assert (tmp_list);
5004
5005             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5006             tmp_list = tmp_list->next;
5007
5008             if (left_column && left_column->visible == FALSE)
5009               continue;
5010
5011             if (!tree_view->priv->column_drop_func)
5012               return left_column;
5013
5014             if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5015               {
5016                 left_column = cur_column;
5017                 continue;
5018               }
5019
5020             return left_column;
5021           }
5022
5023         if (!tree_view->priv->column_drop_func)
5024           return left_column;
5025
5026         if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5027           return left_column;
5028         else
5029           return (GtkTreeViewColumn *)0x1;
5030         break;
5031
5032       case DROP_RIGHT:
5033         /* find first column after column where we can drop */
5034         tmp_list = tree_view->priv->columns;
5035
5036         for (; tmp_list; tmp_list = tmp_list->next)
5037           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5038             break;
5039
5040         if (!tmp_list || !tmp_list->next)
5041           return (GtkTreeViewColumn *)0x1;
5042
5043         tmp_list = tmp_list->next;
5044         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5045         tmp_list = tmp_list->next;
5046
5047         while (tmp_list)
5048           {
5049             g_assert (tmp_list);
5050
5051             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5052             tmp_list = tmp_list->next;
5053
5054             if (left_column && left_column->visible == FALSE)
5055               {
5056                 left_column = cur_column;
5057                 if (tmp_list)
5058                   tmp_list = tmp_list->next;
5059                 continue;
5060               }
5061
5062             if (!tree_view->priv->column_drop_func)
5063               return left_column;
5064
5065             if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5066               {
5067                 left_column = cur_column;
5068                 continue;
5069               }
5070
5071             return left_column;
5072           }
5073
5074         if (!tree_view->priv->column_drop_func)
5075           return left_column;
5076
5077         if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5078           return left_column;
5079         else
5080           return (GtkTreeViewColumn *)0x1;
5081         break;
5082
5083       case DROP_LEFT:
5084         /* find first column before column where we can drop */
5085         tmp_list = tree_view->priv->columns;
5086
5087         for (; tmp_list; tmp_list = tmp_list->next)
5088           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5089             break;
5090
5091         if (!tmp_list || !tmp_list->prev)
5092           return (GtkTreeViewColumn *)0x1;
5093
5094         tmp_list = tmp_list->prev;
5095         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5096         tmp_list = tmp_list->prev;
5097
5098         while (tmp_list)
5099           {
5100             g_assert (tmp_list);
5101
5102             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5103
5104             if (left_column && !left_column->visible)
5105               {
5106                 /*if (!tmp_list->prev)
5107                   return (GtkTreeViewColumn *)0x1;
5108                   */
5109 /*
5110                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5111                 tmp_list = tmp_list->prev->prev;
5112                 continue;*/
5113
5114                 cur_column = left_column;
5115                 if (tmp_list)
5116                   tmp_list = tmp_list->prev;
5117                 continue;
5118               }
5119
5120             if (!tree_view->priv->column_drop_func)
5121               return left_column;
5122
5123             if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5124               return left_column;
5125
5126             cur_column = left_column;
5127             tmp_list = tmp_list->prev;
5128           }
5129
5130         if (!tree_view->priv->column_drop_func)
5131           return NULL;
5132
5133         if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5134           return NULL;
5135         else
5136           return (GtkTreeViewColumn *)0x1;
5137         break;
5138
5139       case DROP_END:
5140         /* same as DROP_HOME case, but doing it backwards */
5141         tmp_list = g_list_last (tree_view->priv->columns);
5142         cur_column = NULL;
5143
5144         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5145           return (GtkTreeViewColumn *)0x1;
5146
5147         while (tmp_list)
5148           {
5149             g_assert (tmp_list);
5150
5151             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5152
5153             if (left_column && !left_column->visible)
5154               {
5155                 cur_column = left_column;
5156                 tmp_list = tmp_list->prev;
5157               }
5158
5159             if (!tree_view->priv->column_drop_func)
5160               return left_column;
5161
5162             if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5163               return left_column;
5164
5165             cur_column = left_column;
5166             tmp_list = tmp_list->prev;
5167           }
5168
5169         if (!tree_view->priv->column_drop_func)
5170           return NULL;
5171
5172         if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5173           return NULL;
5174         else
5175           return (GtkTreeViewColumn *)0x1;
5176         break;
5177     }
5178
5179   return (GtkTreeViewColumn *)0x1;
5180 }
5181
5182 static gboolean
5183 gtk_tree_view_key_press (GtkWidget   *widget,
5184                          GdkEventKey *event)
5185 {
5186   GtkTreeView *tree_view = (GtkTreeView *) widget;
5187
5188   if (tree_view->priv->rubber_band_status)
5189     {
5190       if (event->keyval == GDK_Escape)
5191         gtk_tree_view_stop_rubber_band (tree_view);
5192
5193       return TRUE;
5194     }
5195
5196   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5197     {
5198       if (event->keyval == GDK_Escape)
5199         {
5200           tree_view->priv->cur_reorder = NULL;
5201           gtk_tree_view_button_release_drag_column (widget, NULL);
5202         }
5203       return TRUE;
5204     }
5205
5206   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5207     {
5208       GList *focus_column;
5209       gboolean rtl;
5210
5211       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5212
5213       for (focus_column = tree_view->priv->columns;
5214            focus_column;
5215            focus_column = focus_column->next)
5216         {
5217           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5218
5219           if (GTK_WIDGET_HAS_FOCUS (column->button))
5220             break;
5221         }
5222
5223       if (focus_column &&
5224           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5225           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5226            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
5227         {
5228           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5229
5230           if (!column->resizable)
5231             {
5232               gtk_widget_error_bell (widget);
5233               return TRUE;
5234             }
5235
5236           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5237               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5238             {
5239               gint old_width = column->resized_width;
5240
5241               column->resized_width = MAX (column->resized_width,
5242                                            column->width);
5243               column->resized_width -= 2;
5244               if (column->resized_width < 0)
5245                 column->resized_width = 0;
5246
5247               if (column->min_width == -1)
5248                 column->resized_width = MAX (column->button->requisition.width,
5249                                              column->resized_width);
5250               else
5251                 column->resized_width = MAX (column->min_width,
5252                                              column->resized_width);
5253
5254               if (column->max_width != -1)
5255                 column->resized_width = MIN (column->resized_width,
5256                                              column->max_width);
5257
5258               column->use_resized_width = TRUE;
5259
5260               if (column->resized_width != old_width)
5261                 gtk_widget_queue_resize (widget);
5262               else
5263                 gtk_widget_error_bell (widget);
5264             }
5265           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5266                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5267             {
5268               gint old_width = column->resized_width;
5269
5270               column->resized_width = MAX (column->resized_width,
5271                                            column->width);
5272               column->resized_width += 2;
5273
5274               if (column->max_width != -1)
5275                 column->resized_width = MIN (column->resized_width,
5276                                              column->max_width);
5277
5278               column->use_resized_width = TRUE;
5279
5280               if (column->resized_width != old_width)
5281                 gtk_widget_queue_resize (widget);
5282               else
5283                 gtk_widget_error_bell (widget);
5284             }
5285
5286           return TRUE;
5287         }
5288
5289       if (focus_column &&
5290           (event->state & GDK_MOD1_MASK) &&
5291           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5292            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
5293            || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
5294            || event->keyval == GDK_End || event->keyval == GDK_KP_End))
5295         {
5296           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5297
5298           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5299               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5300             {
5301               GtkTreeViewColumn *col;
5302               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5303               if (col != (GtkTreeViewColumn *)0x1)
5304                 gtk_tree_view_move_column_after (tree_view, column, col);
5305               else
5306                 gtk_widget_error_bell (widget);
5307             }
5308           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5309                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5310             {
5311               GtkTreeViewColumn *col;
5312               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5313               if (col != (GtkTreeViewColumn *)0x1)
5314                 gtk_tree_view_move_column_after (tree_view, column, col);
5315               else
5316                 gtk_widget_error_bell (widget);
5317             }
5318           else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
5319             {
5320               GtkTreeViewColumn *col;
5321               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5322               if (col != (GtkTreeViewColumn *)0x1)
5323                 gtk_tree_view_move_column_after (tree_view, column, col);
5324               else
5325                 gtk_widget_error_bell (widget);
5326             }
5327           else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
5328             {
5329               GtkTreeViewColumn *col;
5330               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5331               if (col != (GtkTreeViewColumn *)0x1)
5332                 gtk_tree_view_move_column_after (tree_view, column, col);
5333               else
5334                 gtk_widget_error_bell (widget);
5335             }
5336
5337           return TRUE;
5338         }
5339     }
5340
5341   /* Chain up to the parent class.  It handles the keybindings. */
5342   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5343     return TRUE;
5344
5345   /* We pass the event to the search_entry.  If its text changes, then we start
5346    * the typeahead find capabilities. */
5347   if (GTK_WIDGET_HAS_FOCUS (tree_view)
5348       && tree_view->priv->enable_search
5349       && !tree_view->priv->search_custom_entry_set)
5350     {
5351       GdkEvent *new_event;
5352       char *old_text;
5353       const char *new_text;
5354       gboolean retval;
5355       GdkScreen *screen;
5356       gboolean text_modified;
5357       gulong popup_menu_id;
5358
5359       gtk_tree_view_ensure_interactive_directory (tree_view);
5360
5361       /* Make a copy of the current text */
5362       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5363       new_event = gdk_event_copy ((GdkEvent *) event);
5364       g_object_unref (((GdkEventKey *) new_event)->window);
5365       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5366       gtk_widget_realize (tree_view->priv->search_window);
5367
5368       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5369                                         "popup_menu", G_CALLBACK (gtk_true), NULL);
5370
5371       /* Move the entry off screen */
5372       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5373       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5374                        gdk_screen_get_width (screen) + 1,
5375                        gdk_screen_get_height (screen) + 1);
5376       gtk_widget_show (tree_view->priv->search_window);
5377
5378       /* Send the event to the window.  If the preedit_changed signal is emitted
5379        * during this event, we will set priv->imcontext_changed  */
5380       tree_view->priv->imcontext_changed = FALSE;
5381       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5382       gdk_event_free (new_event);
5383       gtk_widget_hide (tree_view->priv->search_window);
5384
5385       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5386                                    popup_menu_id);
5387
5388       /* We check to make sure that the entry tried to handle the text, and that
5389        * the text has changed.
5390        */
5391       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5392       text_modified = strcmp (old_text, new_text) != 0;
5393       g_free (old_text);
5394       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5395           (retval && text_modified))               /* ...or the text was modified */
5396         {
5397           if (gtk_tree_view_real_start_interactive_search (tree_view, FALSE))
5398             {
5399               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5400               return TRUE;
5401             }
5402           else
5403             {
5404               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5405               return FALSE;
5406             }
5407         }
5408     }
5409
5410   return FALSE;
5411 }
5412
5413 static gboolean
5414 gtk_tree_view_key_release (GtkWidget   *widget,
5415                            GdkEventKey *event)
5416 {
5417   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5418
5419   if (tree_view->priv->rubber_band_status)
5420     return TRUE;
5421
5422   return (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event) (widget, event);
5423 }
5424
5425 /* FIXME Is this function necessary? Can I get an enter_notify event
5426  * w/o either an expose event or a mouse motion event?
5427  */
5428 static gboolean
5429 gtk_tree_view_enter_notify (GtkWidget        *widget,
5430                             GdkEventCrossing *event)
5431 {
5432   GtkTreeView *tree_view;
5433   GtkRBTree *tree;
5434   GtkRBNode *node;
5435   gint new_y;
5436
5437   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
5438
5439   tree_view = GTK_TREE_VIEW (widget);
5440
5441   /* Sanity check it */
5442   if (event->window != tree_view->priv->bin_window)
5443     return FALSE;
5444
5445   if (tree_view->priv->tree == NULL)
5446     return FALSE;
5447
5448   /* find the node internally */
5449   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5450   if (new_y < 0)
5451     new_y = 0;
5452   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5453
5454   if ((tree_view->priv->button_pressed_node == NULL) ||
5455       (tree_view->priv->button_pressed_node == node))
5456     prelight_or_select (tree_view, tree, node, event->x, event->y);
5457
5458   return TRUE;
5459 }
5460
5461 static gboolean
5462 gtk_tree_view_leave_notify (GtkWidget        *widget,
5463                             GdkEventCrossing *event)
5464 {
5465   GtkTreeView *tree_view;
5466
5467   if (event->mode == GDK_CROSSING_GRAB)
5468     return TRUE;
5469
5470   tree_view = GTK_TREE_VIEW (widget);
5471
5472   if (tree_view->priv->prelight_node)
5473     _gtk_tree_view_queue_draw_node (tree_view,
5474                                    tree_view->priv->prelight_tree,
5475                                    tree_view->priv->prelight_node,
5476                                    NULL);
5477
5478   prelight_or_select (tree_view,
5479                       NULL, NULL,
5480                       -1000, -1000); /* coords not possibly over an arrow */
5481
5482   return TRUE;
5483 }
5484
5485
5486 static gint
5487 gtk_tree_view_focus_out (GtkWidget     *widget,
5488                          GdkEventFocus *event)
5489 {
5490   GtkTreeView *tree_view;
5491
5492   tree_view = GTK_TREE_VIEW (widget);
5493
5494   gtk_widget_queue_draw (widget);
5495
5496   /* destroy interactive search dialog */
5497   if (tree_view->priv->search_window)
5498     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
5499
5500   return FALSE;
5501 }
5502
5503
5504 /* Incremental Reflow
5505  */
5506
5507 static void
5508 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5509                                  GtkRBTree   *tree,
5510                                  GtkRBNode   *node)
5511 {
5512   gint y;
5513
5514   y = _gtk_rbtree_node_find_offset (tree, node)
5515     - tree_view->priv->vadjustment->value
5516     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5517
5518   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5519                               0, y,
5520                               GTK_WIDGET (tree_view)->allocation.width,
5521                               GTK_RBNODE_GET_HEIGHT (node));
5522 }
5523
5524 static gboolean
5525 node_is_visible (GtkTreeView *tree_view,
5526                  GtkRBTree   *tree,
5527                  GtkRBNode   *node)
5528 {
5529   int y;
5530   int height;
5531
5532   y = _gtk_rbtree_node_find_offset (tree, node);
5533   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5534
5535   if (y >= tree_view->priv->vadjustment->value &&
5536       y + height <= (tree_view->priv->vadjustment->value
5537                      + tree_view->priv->vadjustment->page_size))
5538     return TRUE;
5539
5540   return FALSE;
5541 }
5542
5543 /* Returns TRUE if it updated the size
5544  */
5545 static gboolean
5546 validate_row (GtkTreeView *tree_view,
5547               GtkRBTree   *tree,
5548               GtkRBNode   *node,
5549               GtkTreeIter *iter,
5550               GtkTreePath *path)
5551 {
5552   GtkTreeViewColumn *column;
5553   GList *list, *first_column, *last_column;
5554   gint height = 0;
5555   gint horizontal_separator;
5556   gint vertical_separator;
5557   gint focus_line_width;
5558   gint depth = gtk_tree_path_get_depth (path);
5559   gboolean retval = FALSE;
5560   gboolean is_separator = FALSE;
5561   gboolean draw_vgrid_lines, draw_hgrid_lines;
5562   gint focus_pad;
5563   gint grid_line_width;
5564
5565   /* double check the row needs validating */
5566   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5567       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5568     return FALSE;
5569
5570   is_separator = row_is_separator (tree_view, iter, NULL);
5571
5572   gtk_widget_style_get (GTK_WIDGET (tree_view),
5573                         "focus-padding", &focus_pad,
5574                         "focus-line-width", &focus_line_width,
5575                         "horizontal-separator", &horizontal_separator,
5576                         "vertical-separator", &vertical_separator,
5577                         "grid-line-width", &grid_line_width,
5578                         NULL);
5579   
5580   draw_vgrid_lines =
5581     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5582     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5583   draw_hgrid_lines =
5584     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5585     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5586
5587   for (last_column = g_list_last (tree_view->priv->columns);
5588        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5589        last_column = last_column->prev)
5590     ;
5591
5592   for (first_column = g_list_first (tree_view->priv->columns);
5593        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5594        first_column = first_column->next)
5595     ;
5596
5597   for (list = tree_view->priv->columns; list; list = list->next)
5598     {
5599       gint tmp_width;
5600       gint tmp_height;
5601
5602       column = list->data;
5603
5604       if (! column->visible)
5605         continue;
5606
5607       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5608         continue;
5609
5610       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5611                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5612                                                node->children?TRUE:FALSE);
5613       gtk_tree_view_column_cell_get_size (column,
5614                                           NULL, NULL, NULL,
5615                                           &tmp_width, &tmp_height);
5616
5617       if (!is_separator)
5618         {
5619           tmp_height += vertical_separator;
5620           height = MAX (height, tmp_height);
5621           height = MAX (height, tree_view->priv->expander_size);
5622         }
5623       else
5624         height = 2 + 2 * focus_pad;
5625
5626       if (gtk_tree_view_is_expander_column (tree_view, column))
5627         {
5628           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5629
5630           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5631             tmp_width += depth * tree_view->priv->expander_size;
5632         }
5633       else
5634         tmp_width = tmp_width + horizontal_separator;
5635
5636       if (draw_vgrid_lines)
5637         {
5638           if (list->data == first_column || list->data == last_column)
5639             tmp_width += grid_line_width / 2.0;
5640           else
5641             tmp_width += grid_line_width;
5642         }
5643
5644       if (tmp_width > column->requested_width)
5645         {
5646           retval = TRUE;
5647           column->requested_width = tmp_width;
5648         }
5649     }
5650
5651   if (draw_hgrid_lines)
5652     height += grid_line_width;
5653
5654   if (height != GTK_RBNODE_GET_HEIGHT (node))
5655     {
5656       retval = TRUE;
5657       _gtk_rbtree_node_set_height (tree, node, height);
5658     }
5659   _gtk_rbtree_node_mark_valid (tree, node);
5660
5661   return retval;
5662 }
5663
5664
5665 static void
5666 validate_visible_area (GtkTreeView *tree_view)
5667 {
5668   GtkTreePath *path = NULL;
5669   GtkTreePath *above_path = NULL;
5670   GtkTreeIter iter;
5671   GtkRBTree *tree = NULL;
5672   GtkRBNode *node = NULL;
5673   gboolean need_redraw = FALSE;
5674   gboolean size_changed = FALSE;
5675   gint total_height;
5676   gint area_above = 0;
5677   gint area_below = 0;
5678
5679   if (tree_view->priv->tree == NULL)
5680     return;
5681
5682   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5683       tree_view->priv->scroll_to_path == NULL)
5684     return;
5685
5686   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5687
5688   if (total_height == 0)
5689     return;
5690
5691   /* First, we check to see if we need to scroll anywhere
5692    */
5693   if (tree_view->priv->scroll_to_path)
5694     {
5695       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5696       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5697         {
5698           /* we are going to scroll, and will update dy */
5699           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5700           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5701               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5702             {
5703               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5704               if (validate_row (tree_view, tree, node, &iter, path))
5705                 size_changed = TRUE;
5706             }
5707
5708           if (tree_view->priv->scroll_to_use_align)
5709             {
5710               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5711               area_above = (total_height - height) *
5712                 tree_view->priv->scroll_to_row_align;
5713               area_below = total_height - area_above - height;
5714               area_above = MAX (area_above, 0);
5715               area_below = MAX (area_below, 0);
5716             }
5717           else
5718             {
5719               /* two cases:
5720                * 1) row not visible
5721                * 2) row visible
5722                */
5723               gint dy;
5724               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5725
5726               dy = _gtk_rbtree_node_find_offset (tree, node);
5727
5728               if (dy >= tree_view->priv->vadjustment->value &&
5729                   dy + height <= (tree_view->priv->vadjustment->value
5730                                   + tree_view->priv->vadjustment->page_size))
5731                 {
5732                   /* row visible: keep the row at the same position */
5733                   area_above = dy - tree_view->priv->vadjustment->value;
5734                   area_below = (tree_view->priv->vadjustment->value +
5735                                 tree_view->priv->vadjustment->page_size)
5736                                - dy - height;
5737                 }
5738               else
5739                 {
5740                   /* row not visible */
5741                   if (dy >= 0
5742                       && dy + height <= tree_view->priv->vadjustment->page_size)
5743                     {
5744                       /* row at the beginning -- fixed */
5745                       area_above = dy;
5746                       area_below = tree_view->priv->vadjustment->page_size
5747                                    - area_above - height;
5748                     }
5749                   else if (dy >= (tree_view->priv->vadjustment->upper -
5750                                   tree_view->priv->vadjustment->page_size))
5751                     {
5752                       /* row at the end -- fixed */
5753                       area_above = dy - (tree_view->priv->vadjustment->upper -
5754                                    tree_view->priv->vadjustment->page_size);
5755                       area_below = tree_view->priv->vadjustment->page_size -
5756                                    area_above - height;
5757
5758                       if (area_below < 0)
5759                         {
5760                           area_above = tree_view->priv->vadjustment->page_size - height;
5761                           area_below = 0;
5762                         }
5763                     }
5764                   else
5765                     {
5766                       /* row somewhere in the middle, bring it to the top
5767                        * of the view
5768                        */
5769                       area_above = 0;
5770                       area_below = total_height - height;
5771                     }
5772                 }
5773             }
5774         }
5775       else
5776         /* the scroll to isn't valid; ignore it.
5777          */
5778         {
5779           if (tree_view->priv->scroll_to_path && !path)
5780             {
5781               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5782               tree_view->priv->scroll_to_path = NULL;
5783             }
5784           if (path)
5785             gtk_tree_path_free (path);
5786           path = NULL;
5787         }      
5788     }
5789
5790   /* We didn't have a scroll_to set, so we just handle things normally
5791    */
5792   if (path == NULL)
5793     {
5794       gint offset;
5795
5796       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5797                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5798                                         &tree, &node);
5799       if (node == NULL)
5800         {
5801           /* In this case, nothing has been validated */
5802           path = gtk_tree_path_new_first ();
5803           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5804         }
5805       else
5806         {
5807           path = _gtk_tree_view_find_path (tree_view, tree, node);
5808           total_height += offset;
5809         }
5810
5811       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5812
5813       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5814           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5815         {
5816           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5817           if (validate_row (tree_view, tree, node, &iter, path))
5818             size_changed = TRUE;
5819         }
5820       area_above = 0;
5821       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5822     }
5823
5824   above_path = gtk_tree_path_copy (path);
5825
5826   /* if we do not validate any row above the new top_row, we will make sure
5827    * that the row immediately above top_row has been validated. (if we do not
5828    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5829    * when invalidated that row's height will be zero. and this will mess up
5830    * scrolling).
5831    */
5832   if (area_above == 0)
5833     {
5834       GtkRBTree *tmptree;
5835       GtkRBNode *tmpnode;
5836
5837       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5838       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5839
5840       if (tmpnode)
5841         {
5842           GtkTreePath *tmppath;
5843           GtkTreeIter tmpiter;
5844
5845           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5846           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5847
5848           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
5849               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
5850             {
5851               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
5852               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
5853                 size_changed = TRUE;
5854             }
5855
5856           gtk_tree_path_free (tmppath);
5857         }
5858     }
5859
5860   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
5861    * backwards is much slower then forward, as there is no iter_prev function.
5862    * We go forwards first in case we run out of tree.  Then we go backwards to
5863    * fill out the top.
5864    */
5865   while (node && area_below > 0)
5866     {
5867       if (node->children)
5868         {
5869           GtkTreeIter parent = iter;
5870           gboolean has_child;
5871
5872           tree = node->children;
5873           node = tree->root;
5874
5875           g_assert (node != tree->nil);
5876
5877           while (node->left != tree->nil)
5878             node = node->left;
5879           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5880                                                     &iter,
5881                                                     &parent);
5882           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
5883           gtk_tree_path_down (path);
5884         }
5885       else
5886         {
5887           gboolean done = FALSE;
5888           do
5889             {
5890               node = _gtk_rbtree_next (tree, node);
5891               if (node != NULL)
5892                 {
5893                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5894                   done = TRUE;
5895                   gtk_tree_path_next (path);
5896
5897                   /* Sanity Check! */
5898                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
5899                 }
5900               else
5901                 {
5902                   GtkTreeIter parent_iter = iter;
5903                   gboolean has_parent;
5904
5905                   node = tree->parent_node;
5906                   tree = tree->parent_tree;
5907                   if (tree == NULL)
5908                     break;
5909                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5910                                                            &iter,
5911                                                            &parent_iter);
5912                   gtk_tree_path_up (path);
5913
5914                   /* Sanity check */
5915                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
5916                 }
5917             }
5918           while (!done);
5919         }
5920
5921       if (!node)
5922         break;
5923
5924       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5925           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5926         {
5927           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5928           if (validate_row (tree_view, tree, node, &iter, path))
5929               size_changed = TRUE;
5930         }
5931
5932       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5933     }
5934   gtk_tree_path_free (path);
5935
5936   /* If we ran out of tree, and have extra area_below left, we need to add it
5937    * to area_above */
5938   if (area_below > 0)
5939     area_above += area_below;
5940
5941   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
5942
5943   /* We walk backwards */
5944   while (area_above > 0)
5945     {
5946       _gtk_rbtree_prev_full (tree, node, &tree, &node);
5947       if (! gtk_tree_path_prev (above_path) && node != NULL)
5948         {
5949           gtk_tree_path_free (above_path);
5950           above_path = _gtk_tree_view_find_path (tree_view, tree, node);
5951         }
5952       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
5953
5954       if (node == NULL)
5955         break;
5956
5957       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5958           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5959         {
5960           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5961           if (validate_row (tree_view, tree, node, &iter, above_path))
5962             size_changed = TRUE;
5963         }
5964       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5965     }
5966
5967   /* if we scrolled to a path, we need to set the dy here,
5968    * and sync the top row accordingly
5969    */
5970   if (tree_view->priv->scroll_to_path)
5971     {
5972       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
5973       gtk_tree_view_top_row_to_dy (tree_view);
5974
5975       need_redraw = TRUE;
5976     }
5977   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
5978     {
5979       /* when we are not scrolling, we should never set dy to something
5980        * else than zero. we update top_row to be in sync with dy = 0.
5981        */
5982       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
5983       gtk_tree_view_dy_to_top_row (tree_view);
5984     }
5985   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
5986     {
5987       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
5988       gtk_tree_view_dy_to_top_row (tree_view);
5989     }
5990   else
5991     gtk_tree_view_top_row_to_dy (tree_view);
5992
5993   /* update width/height and queue a resize */
5994   if (size_changed)
5995     {
5996       GtkRequisition requisition;
5997
5998       /* We temporarily guess a size, under the assumption that it will be the
5999        * same when we get our next size_allocate.  If we don't do this, we'll be
6000        * in an inconsistent state if we call top_row_to_dy. */
6001
6002       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6003       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6004       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6005       gtk_adjustment_changed (tree_view->priv->hadjustment);
6006       gtk_adjustment_changed (tree_view->priv->vadjustment);
6007       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6008     }
6009
6010   if (tree_view->priv->scroll_to_path)
6011     {
6012       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6013       tree_view->priv->scroll_to_path = NULL;
6014     }
6015
6016   if (above_path)
6017     gtk_tree_path_free (above_path);
6018
6019   if (tree_view->priv->scroll_to_column)
6020     {
6021       tree_view->priv->scroll_to_column = NULL;
6022     }
6023   if (need_redraw)
6024     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6025 }
6026
6027 static void
6028 initialize_fixed_height_mode (GtkTreeView *tree_view)
6029 {
6030   if (!tree_view->priv->tree)
6031     return;
6032
6033   if (tree_view->priv->fixed_height < 0)
6034     {
6035       GtkTreeIter iter;
6036       GtkTreePath *path;
6037
6038       GtkRBTree *tree = NULL;
6039       GtkRBNode *node = NULL;
6040
6041       tree = tree_view->priv->tree;
6042       node = tree->root;
6043
6044       path = _gtk_tree_view_find_path (tree_view, tree, node);
6045       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6046
6047       validate_row (tree_view, tree, node, &iter, path);
6048
6049       gtk_tree_path_free (path);
6050
6051       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6052     }
6053
6054    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6055                                  tree_view->priv->fixed_height, TRUE);
6056 }
6057
6058 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6059  * the left-most uninvalidated node.  We then try walking right, validating
6060  * nodes.  Once we find a valid node, we repeat the previous process of finding
6061  * the first invalid node.
6062  */
6063
6064 static gboolean
6065 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6066 {
6067   GtkRBTree *tree = NULL;
6068   GtkRBNode *node = NULL;
6069   gboolean validated_area = FALSE;
6070   gint retval = TRUE;
6071   GtkTreePath *path = NULL;
6072   GtkTreeIter iter;
6073   gint i = 0;
6074
6075   gint prev_height = -1;
6076   gboolean fixed_height = TRUE;
6077
6078   g_assert (tree_view);
6079
6080   if (tree_view->priv->tree == NULL)
6081       return FALSE;
6082
6083   if (tree_view->priv->fixed_height_mode)
6084     {
6085       if (tree_view->priv->fixed_height < 0)
6086         initialize_fixed_height_mode (tree_view);
6087
6088       return FALSE;
6089     }
6090
6091   do
6092     {
6093       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6094         {
6095           retval = FALSE;
6096           goto done;
6097         }
6098
6099       if (path != NULL)
6100         {
6101           node = _gtk_rbtree_next (tree, node);
6102           if (node != NULL)
6103             {
6104               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6105               gtk_tree_path_next (path);
6106             }
6107           else
6108             {
6109               gtk_tree_path_free (path);
6110               path = NULL;
6111             }
6112         }
6113
6114       if (path == NULL)
6115         {
6116           tree = tree_view->priv->tree;
6117           node = tree_view->priv->tree->root;
6118
6119           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6120
6121           do
6122             {
6123               if (node->left != tree->nil &&
6124                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6125                 {
6126                   node = node->left;
6127                 }
6128               else if (node->right != tree->nil &&
6129                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6130                 {
6131                   node = node->right;
6132                 }
6133               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6134                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6135                 {
6136                   break;
6137                 }
6138               else if (node->children != NULL)
6139                 {
6140                   tree = node->children;
6141                   node = tree->root;
6142                 }
6143               else
6144                 /* RBTree corruption!  All bad */
6145                 g_assert_not_reached ();
6146             }
6147           while (TRUE);
6148           path = _gtk_tree_view_find_path (tree_view, tree, node);
6149           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6150         }
6151
6152       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6153                        validated_area;
6154
6155       if (!tree_view->priv->fixed_height_check)
6156         {
6157           gint height;
6158
6159           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6160           if (prev_height < 0)
6161             prev_height = height;
6162           else if (prev_height != height)
6163             fixed_height = FALSE;
6164         }
6165
6166       i++;
6167     }
6168   while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
6169
6170   if (!tree_view->priv->fixed_height_check)
6171    {
6172      if (fixed_height)
6173        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6174
6175      tree_view->priv->fixed_height_check = 1;
6176    }
6177   
6178  done:
6179   if (validated_area)
6180     {
6181       GtkRequisition requisition;
6182       /* We temporarily guess a size, under the assumption that it will be the
6183        * same when we get our next size_allocate.  If we don't do this, we'll be
6184        * in an inconsistent state when we call top_row_to_dy. */
6185
6186       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6187       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6188       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6189       gtk_adjustment_changed (tree_view->priv->hadjustment);
6190       gtk_adjustment_changed (tree_view->priv->vadjustment);
6191
6192       if (queue_resize)
6193         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6194     }
6195
6196   if (path) gtk_tree_path_free (path);
6197
6198   return retval;
6199 }
6200
6201 static gboolean
6202 validate_rows (GtkTreeView *tree_view)
6203 {
6204   gboolean retval;
6205   
6206   retval = do_validate_rows (tree_view, TRUE);
6207   
6208   if (! retval && tree_view->priv->validate_rows_timer)
6209     {
6210       g_source_remove (tree_view->priv->validate_rows_timer);
6211       tree_view->priv->validate_rows_timer = 0;
6212     }
6213
6214   return retval;
6215 }
6216
6217 static gboolean
6218 validate_rows_handler (GtkTreeView *tree_view)
6219 {
6220   gboolean retval;
6221
6222   retval = do_validate_rows (tree_view, TRUE);
6223   if (! retval && tree_view->priv->validate_rows_timer)
6224     {
6225       g_source_remove (tree_view->priv->validate_rows_timer);
6226       tree_view->priv->validate_rows_timer = 0;
6227     }
6228
6229   return retval;
6230 }
6231
6232 static gboolean
6233 do_presize_handler (GtkTreeView *tree_view)
6234 {
6235   if (tree_view->priv->mark_rows_col_dirty)
6236     {
6237       if (tree_view->priv->tree)
6238         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6239       tree_view->priv->mark_rows_col_dirty = FALSE;
6240     }
6241   validate_visible_area (tree_view);
6242   tree_view->priv->presize_handler_timer = 0;
6243
6244   if (tree_view->priv->fixed_height_mode)
6245     {
6246       GtkRequisition requisition;
6247
6248       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6249
6250       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6251       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6252       gtk_adjustment_changed (tree_view->priv->hadjustment);
6253       gtk_adjustment_changed (tree_view->priv->vadjustment);
6254       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6255     }
6256                    
6257   return FALSE;
6258 }
6259
6260 static gboolean
6261 presize_handler_callback (gpointer data)
6262 {
6263   do_presize_handler (GTK_TREE_VIEW (data));
6264                    
6265   return FALSE;
6266 }
6267
6268 static void
6269 install_presize_handler (GtkTreeView *tree_view)
6270 {
6271   if (! GTK_WIDGET_REALIZED (tree_view))
6272     return;
6273
6274   if (! tree_view->priv->presize_handler_timer)
6275     {
6276       tree_view->priv->presize_handler_timer =
6277         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6278     }
6279   if (! tree_view->priv->validate_rows_timer)
6280     {
6281       tree_view->priv->validate_rows_timer =
6282         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6283     }
6284 }
6285
6286 static gboolean
6287 scroll_sync_handler (GtkTreeView *tree_view)
6288 {
6289   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6290     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6291   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6292     gtk_tree_view_top_row_to_dy (tree_view);
6293   else
6294     gtk_tree_view_dy_to_top_row (tree_view);
6295
6296   tree_view->priv->scroll_sync_timer = 0;
6297
6298   return FALSE;
6299 }
6300
6301 static void
6302 install_scroll_sync_handler (GtkTreeView *tree_view)
6303 {
6304   if (! GTK_WIDGET_REALIZED (tree_view))
6305     return;
6306
6307   if (!tree_view->priv->scroll_sync_timer)
6308     {
6309       tree_view->priv->scroll_sync_timer =
6310         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6311     }
6312 }
6313
6314 static void
6315 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6316                            GtkTreePath *path,
6317                            gint         offset)
6318 {
6319   gtk_tree_row_reference_free (tree_view->priv->top_row);
6320
6321   if (!path)
6322     {
6323       tree_view->priv->top_row = NULL;
6324       tree_view->priv->top_row_dy = 0;
6325     }
6326   else
6327     {
6328       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6329       tree_view->priv->top_row_dy = offset;
6330     }
6331 }
6332
6333 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6334  * it's set to be NULL, and top_row_dy is 0;
6335  */
6336 static void
6337 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6338 {
6339   gint offset;
6340   GtkTreePath *path;
6341   GtkRBTree *tree;
6342   GtkRBNode *node;
6343
6344   if (tree_view->priv->tree == NULL)
6345     {
6346       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6347     }
6348   else
6349     {
6350       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6351                                         tree_view->priv->dy,
6352                                         &tree, &node);
6353
6354       if (tree == NULL)
6355         {
6356           tree_view->priv->top_row = NULL;
6357           tree_view->priv->top_row_dy = 0;
6358         }
6359       else
6360         {
6361           path = _gtk_tree_view_find_path (tree_view, tree, node);
6362           gtk_tree_view_set_top_row (tree_view, path, offset);
6363           gtk_tree_path_free (path);
6364         }
6365     }
6366 }
6367
6368 static void
6369 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6370 {
6371   GtkTreePath *path;
6372   GtkRBTree *tree;
6373   GtkRBNode *node;
6374   int new_dy;
6375
6376   if (tree_view->priv->top_row)
6377     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6378   else
6379     path = NULL;
6380
6381   if (!path)
6382     tree = NULL;
6383   else
6384     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6385
6386   if (path)
6387     gtk_tree_path_free (path);
6388
6389   if (tree == NULL)
6390     {
6391       /* keep dy and set new toprow */
6392       gtk_tree_row_reference_free (tree_view->priv->top_row);
6393       tree_view->priv->top_row = NULL;
6394       tree_view->priv->top_row_dy = 0;
6395       /* DO NOT install the idle handler */
6396       gtk_tree_view_dy_to_top_row (tree_view);
6397       return;
6398     }
6399
6400   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6401       < tree_view->priv->top_row_dy)
6402     {
6403       /* new top row -- do NOT install the idle handler */
6404       gtk_tree_view_dy_to_top_row (tree_view);
6405       return;
6406     }
6407
6408   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6409   new_dy += tree_view->priv->top_row_dy;
6410
6411   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6412     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6413
6414   new_dy = MAX (0, new_dy);
6415
6416   tree_view->priv->in_top_row_to_dy = TRUE;
6417   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6418   tree_view->priv->in_top_row_to_dy = FALSE;
6419 }
6420
6421
6422 void
6423 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6424 {
6425   tree_view->priv->mark_rows_col_dirty = TRUE;
6426
6427   install_presize_handler (tree_view);
6428 }
6429
6430 /*
6431  * This function works synchronously (due to the while (validate_rows...)
6432  * loop).
6433  *
6434  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6435  * here. You now need to check that yourself.
6436  */
6437 void
6438 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6439                                 GtkTreeViewColumn *column)
6440 {
6441   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6442   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6443
6444   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6445
6446   do_presize_handler (tree_view);
6447   while (validate_rows (tree_view));
6448
6449   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6450 }
6451
6452 /* Drag-and-drop */
6453
6454 static void
6455 set_source_row (GdkDragContext *context,
6456                 GtkTreeModel   *model,
6457                 GtkTreePath    *source_row)
6458 {
6459   g_object_set_data_full (G_OBJECT (context),
6460                           I_("gtk-tree-view-source-row"),
6461                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6462                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6463 }
6464
6465 static GtkTreePath*
6466 get_source_row (GdkDragContext *context)
6467 {
6468   GtkTreeRowReference *ref =
6469     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6470
6471   if (ref)
6472     return gtk_tree_row_reference_get_path (ref);
6473   else
6474     return NULL;
6475 }
6476
6477 typedef struct
6478 {
6479   GtkTreeRowReference *dest_row;
6480   gboolean             path_down_mode;
6481   gboolean             empty_view_drop;
6482   gboolean             drop_append_mode;
6483 }
6484 DestRow;
6485
6486 static void
6487 dest_row_free (gpointer data)
6488 {
6489   DestRow *dr = (DestRow *)data;
6490
6491   gtk_tree_row_reference_free (dr->dest_row);
6492   g_free (dr);
6493 }
6494
6495
6496 static void
6497 set_dest_row (GdkDragContext *context,
6498               GtkTreeModel   *model,
6499               GtkTreePath    *dest_row,
6500               gboolean        path_down_mode,
6501               gboolean        empty_view_drop,
6502               gboolean        drop_append_mode)
6503 {
6504   DestRow *dr;
6505
6506   if (!dest_row)
6507     {
6508       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6509                               NULL, NULL);
6510       return;
6511     }
6512
6513   dr = g_new0 (DestRow, 1);
6514
6515   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6516   dr->path_down_mode = path_down_mode;
6517   dr->empty_view_drop = empty_view_drop;
6518   dr->drop_append_mode = drop_append_mode;
6519
6520   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6521                           dr, (GDestroyNotify) dest_row_free);
6522 }
6523
6524 static GtkTreePath*
6525 get_dest_row (GdkDragContext *context,
6526               gboolean       *path_down_mode)
6527 {
6528   DestRow *dr =
6529     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6530
6531   if (dr)
6532     {
6533       GtkTreePath *path = NULL;
6534
6535       if (path_down_mode)
6536         *path_down_mode = dr->path_down_mode;
6537
6538       if (dr->dest_row)
6539         path = gtk_tree_row_reference_get_path (dr->dest_row);
6540       else if (dr->empty_view_drop)
6541         path = gtk_tree_path_new_from_indices (0, -1);
6542       else
6543         path = NULL;
6544
6545       if (path && dr->drop_append_mode)
6546         gtk_tree_path_next (path);
6547
6548       return path;
6549     }
6550   else
6551     return NULL;
6552 }
6553
6554 /* Get/set whether drag_motion requested the drag data and
6555  * drag_data_received should thus not actually insert the data,
6556  * since the data doesn't result from a drop.
6557  */
6558 static void
6559 set_status_pending (GdkDragContext *context,
6560                     GdkDragAction   suggested_action)
6561 {
6562   g_object_set_data (G_OBJECT (context),
6563                      I_("gtk-tree-view-status-pending"),
6564                      GINT_TO_POINTER (suggested_action));
6565 }
6566
6567 static GdkDragAction
6568 get_status_pending (GdkDragContext *context)
6569 {
6570   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6571                                              "gtk-tree-view-status-pending"));
6572 }
6573
6574 static TreeViewDragInfo*
6575 get_info (GtkTreeView *tree_view)
6576 {
6577   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6578 }
6579
6580 static void
6581 clear_source_info (TreeViewDragInfo *di)
6582 {
6583   if (di->source_target_list)
6584     gtk_target_list_unref (di->source_target_list);
6585
6586   di->source_target_list = NULL;
6587 }
6588
6589 static void
6590 clear_dest_info (TreeViewDragInfo *di)
6591 {
6592   if (di->dest_target_list)
6593     gtk_target_list_unref (di->dest_target_list);
6594
6595   di->dest_target_list = NULL;
6596 }
6597
6598 static void
6599 destroy_info (TreeViewDragInfo *di)
6600 {
6601   clear_source_info (di);
6602   clear_dest_info (di);
6603   g_free (di);
6604 }
6605
6606 static TreeViewDragInfo*
6607 ensure_info (GtkTreeView *tree_view)
6608 {
6609   TreeViewDragInfo *di;
6610
6611   di = get_info (tree_view);
6612
6613   if (di == NULL)
6614     {
6615       di = g_new0 (TreeViewDragInfo, 1);
6616
6617       g_object_set_data_full (G_OBJECT (tree_view),
6618                               I_("gtk-tree-view-drag-info"),
6619                               di,
6620                               (GDestroyNotify) destroy_info);
6621     }
6622
6623   return di;
6624 }
6625
6626 static void
6627 remove_info (GtkTreeView *tree_view)
6628 {
6629   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6630 }
6631
6632 #if 0
6633 static gint
6634 drag_scan_timeout (gpointer data)
6635 {
6636   GtkTreeView *tree_view;
6637   gint x, y;
6638   GdkModifierType state;
6639   GtkTreePath *path = NULL;
6640   GtkTreeViewColumn *column = NULL;
6641   GdkRectangle visible_rect;
6642
6643   GDK_THREADS_ENTER ();
6644
6645   tree_view = GTK_TREE_VIEW (data);
6646
6647   gdk_window_get_pointer (tree_view->priv->bin_window,
6648                           &x, &y, &state);
6649
6650   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6651
6652   /* See if we are near the edge. */
6653   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6654       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6655       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6656       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6657     {
6658       gtk_tree_view_get_path_at_pos (tree_view,
6659                                      tree_view->priv->bin_window,
6660                                      x, y,
6661                                      &path,
6662                                      &column,
6663                                      NULL,
6664                                      NULL);
6665
6666       if (path != NULL)
6667         {
6668           gtk_tree_view_scroll_to_cell (tree_view,
6669                                         path,
6670                                         column,
6671                                         TRUE,
6672                                         0.5, 0.5);
6673
6674           gtk_tree_path_free (path);
6675         }
6676     }
6677
6678   GDK_THREADS_LEAVE ();
6679
6680   return TRUE;
6681 }
6682 #endif /* 0 */
6683
6684 static void
6685 add_scroll_timeout (GtkTreeView *tree_view)
6686 {
6687   if (tree_view->priv->scroll_timeout == 0)
6688     {
6689       tree_view->priv->scroll_timeout =
6690         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6691     }
6692 }
6693
6694 static void
6695 remove_scroll_timeout (GtkTreeView *tree_view)
6696 {
6697   if (tree_view->priv->scroll_timeout != 0)
6698     {
6699       g_source_remove (tree_view->priv->scroll_timeout);
6700       tree_view->priv->scroll_timeout = 0;
6701     }
6702 }
6703
6704 static gboolean
6705 check_model_dnd (GtkTreeModel *model,
6706                  GType         required_iface,
6707                  const gchar  *signal)
6708 {
6709   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6710     {
6711       g_warning ("You must override the default '%s' handler "
6712                  "on GtkTreeView when using models that don't support "
6713                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6714                  "is to connect to '%s' and call "
6715                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6716                  "the default handler from running. Look at the source code "
6717                  "for the default handler in gtktreeview.c to get an idea what "
6718                  "your handler should do. (gtktreeview.c is in the GTK source "
6719                  "code.) If you're using GTK from a language other than C, "
6720                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6721                  signal, g_type_name (required_iface), signal);
6722       return FALSE;
6723     }
6724   else
6725     return TRUE;
6726 }
6727
6728 static void
6729 remove_open_timeout (GtkTreeView *tree_view)
6730 {
6731   if (tree_view->priv->open_dest_timeout != 0)
6732     {
6733       g_source_remove (tree_view->priv->open_dest_timeout);
6734       tree_view->priv->open_dest_timeout = 0;
6735     }
6736 }
6737
6738
6739 static gint
6740 open_row_timeout (gpointer data)
6741 {
6742   GtkTreeView *tree_view = data;
6743   GtkTreePath *dest_path = NULL;
6744   GtkTreeViewDropPosition pos;
6745   gboolean result = FALSE;
6746
6747   gtk_tree_view_get_drag_dest_row (tree_view,
6748                                    &dest_path,
6749                                    &pos);
6750
6751   if (dest_path &&
6752       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6753        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6754     {
6755       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6756       tree_view->priv->open_dest_timeout = 0;
6757
6758       gtk_tree_path_free (dest_path);
6759     }
6760   else
6761     {
6762       if (dest_path)
6763         gtk_tree_path_free (dest_path);
6764
6765       result = TRUE;
6766     }
6767
6768   return result;
6769 }
6770
6771 static gboolean
6772 scroll_row_timeout (gpointer data)
6773 {
6774   GtkTreeView *tree_view = data;
6775
6776   gtk_tree_view_vertical_autoscroll (tree_view);
6777
6778   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6779     gtk_tree_view_update_rubber_band (tree_view);
6780
6781   return TRUE;
6782 }
6783
6784 /* Returns TRUE if event should not be propagated to parent widgets */
6785 static gboolean
6786 set_destination_row (GtkTreeView    *tree_view,
6787                      GdkDragContext *context,
6788                      /* coordinates relative to the widget */
6789                      gint            x,
6790                      gint            y,
6791                      GdkDragAction  *suggested_action,
6792                      GdkAtom        *target)
6793 {
6794   GtkTreePath *path = NULL;
6795   GtkTreeViewDropPosition pos;
6796   GtkTreeViewDropPosition old_pos;
6797   TreeViewDragInfo *di;
6798   GtkWidget *widget;
6799   GtkTreePath *old_dest_path = NULL;
6800   gboolean can_drop = FALSE;
6801
6802   *suggested_action = 0;
6803   *target = GDK_NONE;
6804
6805   widget = GTK_WIDGET (tree_view);
6806
6807   di = get_info (tree_view);
6808
6809   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6810     {
6811       /* someone unset us as a drag dest, note that if
6812        * we return FALSE drag_leave isn't called
6813        */
6814
6815       gtk_tree_view_set_drag_dest_row (tree_view,
6816                                        NULL,
6817                                        GTK_TREE_VIEW_DROP_BEFORE);
6818
6819       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6820       remove_open_timeout (GTK_TREE_VIEW (widget));
6821
6822       return FALSE; /* no longer a drop site */
6823     }
6824
6825   *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
6826   if (*target == GDK_NONE)
6827     {
6828       return FALSE;
6829     }
6830
6831   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6832                                           x, y,
6833                                           &path,
6834                                           &pos))
6835     {
6836       gint n_children;
6837       GtkTreeModel *model;
6838
6839       remove_open_timeout (tree_view);
6840
6841       /* the row got dropped on empty space, let's setup a special case
6842        */
6843
6844       if (path)
6845         gtk_tree_path_free (path);
6846
6847       model = gtk_tree_view_get_model (tree_view);
6848
6849       n_children = gtk_tree_model_iter_n_children (model, NULL);
6850       if (n_children)
6851         {
6852           pos = GTK_TREE_VIEW_DROP_AFTER;
6853           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6854         }
6855       else
6856         {
6857           pos = GTK_TREE_VIEW_DROP_BEFORE;
6858           path = gtk_tree_path_new_from_indices (0, -1);
6859         }
6860
6861       can_drop = TRUE;
6862
6863       goto out;
6864     }
6865
6866   g_assert (path);
6867
6868   /* If we left the current row's "open" zone, unset the timeout for
6869    * opening the row
6870    */
6871   gtk_tree_view_get_drag_dest_row (tree_view,
6872                                    &old_dest_path,
6873                                    &old_pos);
6874
6875   if (old_dest_path &&
6876       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
6877        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6878          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
6879     remove_open_timeout (tree_view);
6880
6881   if (old_dest_path)
6882     gtk_tree_path_free (old_dest_path);
6883
6884   if (TRUE /* FIXME if the location droppable predicate */)
6885     {
6886       can_drop = TRUE;
6887     }
6888
6889 out:
6890   if (can_drop)
6891     {
6892       GtkWidget *source_widget;
6893
6894       *suggested_action = context->suggested_action;
6895       source_widget = gtk_drag_get_source_widget (context);
6896
6897       if (source_widget == widget)
6898         {
6899           /* Default to MOVE, unless the user has
6900            * pressed ctrl or shift to affect available actions
6901            */
6902           if ((context->actions & GDK_ACTION_MOVE) != 0)
6903             *suggested_action = GDK_ACTION_MOVE;
6904         }
6905
6906       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6907                                        path, pos);
6908     }
6909   else
6910     {
6911       /* can't drop here */
6912       remove_open_timeout (tree_view);
6913
6914       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6915                                        NULL,
6916                                        GTK_TREE_VIEW_DROP_BEFORE);
6917     }
6918
6919   if (path)
6920     gtk_tree_path_free (path);
6921
6922   return TRUE;
6923 }
6924
6925 static GtkTreePath*
6926 get_logical_dest_row (GtkTreeView *tree_view,
6927                       gboolean    *path_down_mode,
6928                       gboolean    *drop_append_mode)
6929 {
6930   /* adjust path to point to the row the drop goes in front of */
6931   GtkTreePath *path = NULL;
6932   GtkTreeViewDropPosition pos;
6933
6934   g_return_val_if_fail (path_down_mode != NULL, NULL);
6935   g_return_val_if_fail (drop_append_mode != NULL, NULL);
6936
6937   *path_down_mode = FALSE;
6938   *drop_append_mode = 0;
6939
6940   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6941
6942   if (path == NULL)
6943     return NULL;
6944
6945   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
6946     ; /* do nothing */
6947   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
6948            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
6949     *path_down_mode = TRUE;
6950   else
6951     {
6952       GtkTreeIter iter;
6953       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
6954
6955       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
6956
6957       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6958           !gtk_tree_model_iter_next (model, &iter))
6959         *drop_append_mode = 1;
6960       else
6961         {
6962           *drop_append_mode = 0;
6963           gtk_tree_path_next (path);
6964         }
6965     }
6966
6967   return path;
6968 }
6969
6970 static gboolean
6971 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
6972                                         GdkEventMotion   *event)
6973 {
6974   GdkDragContext *context;
6975   TreeViewDragInfo *di;
6976   GtkTreePath *path = NULL;
6977   gint button;
6978   gint cell_x, cell_y;
6979   GtkTreeModel *model;
6980   gboolean retval = FALSE;
6981
6982   di = get_info (tree_view);
6983
6984   if (di == NULL || !di->source_set)
6985     goto out;
6986
6987   if (tree_view->priv->pressed_button < 0)
6988     goto out;
6989
6990   if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
6991                                  tree_view->priv->press_start_x,
6992                                  tree_view->priv->press_start_y,
6993                                  event->x, event->y))
6994     goto out;
6995
6996   model = gtk_tree_view_get_model (tree_view);
6997
6998   if (model == NULL)
6999     goto out;
7000
7001   button = tree_view->priv->pressed_button;
7002   tree_view->priv->pressed_button = -1;
7003
7004   gtk_tree_view_get_path_at_pos (tree_view,
7005                                  tree_view->priv->press_start_x,
7006                                  tree_view->priv->press_start_y,
7007                                  &path,
7008                                  NULL,
7009                                  &cell_x,
7010                                  &cell_y);
7011
7012   if (path == NULL)
7013     goto out;
7014
7015   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7016       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7017                                            path))
7018     goto out;
7019
7020   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7021     goto out;
7022
7023   /* Now we can begin the drag */
7024
7025   retval = TRUE;
7026
7027   context = gtk_drag_begin (GTK_WIDGET (tree_view),
7028                             di->source_target_list,
7029                             di->source_actions,
7030                             button,
7031                             (GdkEvent*)event);
7032
7033   set_source_row (context, model, path);
7034
7035  out:
7036   if (path)
7037     gtk_tree_path_free (path);
7038
7039   return retval;
7040 }
7041
7042
7043 static void
7044 gtk_tree_view_drag_begin (GtkWidget      *widget,
7045                           GdkDragContext *context)
7046 {
7047   GtkTreeView *tree_view;
7048   GtkTreePath *path = NULL;
7049   gint cell_x, cell_y;
7050   GdkPixmap *row_pix;
7051   TreeViewDragInfo *di;
7052
7053   tree_view = GTK_TREE_VIEW (widget);
7054
7055   /* if the user uses a custom DND source impl, we don't set the icon here */
7056   di = get_info (tree_view);
7057
7058   if (di == NULL || !di->source_set)
7059     return;
7060
7061   gtk_tree_view_get_path_at_pos (tree_view,
7062                                  tree_view->priv->press_start_x,
7063                                  tree_view->priv->press_start_y,
7064                                  &path,
7065                                  NULL,
7066                                  &cell_x,
7067                                  &cell_y);
7068
7069   g_return_if_fail (path != NULL);
7070
7071   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7072                                                 path);
7073
7074   gtk_drag_set_icon_pixmap (context,
7075                             gdk_drawable_get_colormap (row_pix),
7076                             row_pix,
7077                             NULL,
7078                             /* the + 1 is for the black border in the icon */
7079                             tree_view->priv->press_start_x + 1,
7080                             cell_y + 1);
7081
7082   g_object_unref (row_pix);
7083   gtk_tree_path_free (path);
7084 }
7085
7086 static void
7087 gtk_tree_view_drag_end (GtkWidget      *widget,
7088                         GdkDragContext *context)
7089 {
7090   /* do nothing */
7091 }
7092
7093 /* Default signal implementations for the drag signals */
7094 static void
7095 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7096                              GdkDragContext   *context,
7097                              GtkSelectionData *selection_data,
7098                              guint             info,
7099                              guint             time)
7100 {
7101   GtkTreeView *tree_view;
7102   GtkTreeModel *model;
7103   TreeViewDragInfo *di;
7104   GtkTreePath *source_row;
7105
7106   tree_view = GTK_TREE_VIEW (widget);
7107
7108   model = gtk_tree_view_get_model (tree_view);
7109
7110   if (model == NULL)
7111     return;
7112
7113   di = get_info (GTK_TREE_VIEW (widget));
7114
7115   if (di == NULL)
7116     return;
7117
7118   source_row = get_source_row (context);
7119
7120   if (source_row == NULL)
7121     return;
7122
7123   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7124    * any model; for DragSource models there are some other targets
7125    * we also support.
7126    */
7127
7128   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7129       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7130                                           source_row,
7131                                           selection_data))
7132     goto done;
7133
7134   /* If drag_data_get does nothing, try providing row data. */
7135   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7136     {
7137       gtk_tree_set_row_drag_data (selection_data,
7138                                   model,
7139                                   source_row);
7140     }
7141
7142  done:
7143   gtk_tree_path_free (source_row);
7144 }
7145
7146
7147 static void
7148 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7149                                 GdkDragContext *context)
7150 {
7151   TreeViewDragInfo *di;
7152   GtkTreeModel *model;
7153   GtkTreeView *tree_view;
7154   GtkTreePath *source_row;
7155
7156   tree_view = GTK_TREE_VIEW (widget);
7157   model = gtk_tree_view_get_model (tree_view);
7158
7159   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7160     return;
7161
7162   di = get_info (tree_view);
7163
7164   if (di == NULL)
7165     return;
7166
7167   source_row = get_source_row (context);
7168
7169   if (source_row == NULL)
7170     return;
7171
7172   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7173                                          source_row);
7174
7175   gtk_tree_path_free (source_row);
7176
7177   set_source_row (context, NULL, NULL);
7178 }
7179
7180 static void
7181 gtk_tree_view_drag_leave (GtkWidget      *widget,
7182                           GdkDragContext *context,
7183                           guint             time)
7184 {
7185   /* unset any highlight row */
7186   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7187                                    NULL,
7188                                    GTK_TREE_VIEW_DROP_BEFORE);
7189
7190   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7191   remove_open_timeout (GTK_TREE_VIEW (widget));
7192 }
7193
7194
7195 static gboolean
7196 gtk_tree_view_drag_motion (GtkWidget        *widget,
7197                            GdkDragContext   *context,
7198                            /* coordinates relative to the widget */
7199                            gint              x,
7200                            gint              y,
7201                            guint             time)
7202 {
7203   gboolean empty;
7204   GtkTreePath *path = NULL;
7205   GtkTreeViewDropPosition pos;
7206   GtkTreeView *tree_view;
7207   GdkDragAction suggested_action = 0;
7208   GdkAtom target;
7209
7210   tree_view = GTK_TREE_VIEW (widget);
7211
7212   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7213     return FALSE;
7214
7215   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7216
7217   /* we only know this *after* set_desination_row */
7218   empty = tree_view->priv->empty_view_drop;
7219
7220   if (path == NULL && !empty)
7221     {
7222       /* Can't drop here. */
7223       gdk_drag_status (context, 0, time);
7224     }
7225   else
7226     {
7227       if (tree_view->priv->open_dest_timeout == 0 &&
7228           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7229            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7230         {
7231           tree_view->priv->open_dest_timeout =
7232             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7233         }
7234       else
7235         {
7236           add_scroll_timeout (tree_view);
7237         }
7238
7239       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7240         {
7241           /* Request data so we can use the source row when
7242            * determining whether to accept the drop
7243            */
7244           set_status_pending (context, suggested_action);
7245           gtk_drag_get_data (widget, context, target, time);
7246         }
7247       else
7248         {
7249           set_status_pending (context, 0);
7250           gdk_drag_status (context, suggested_action, time);
7251         }
7252     }
7253
7254   if (path)
7255     gtk_tree_path_free (path);
7256
7257   return TRUE;
7258 }
7259
7260
7261 static gboolean
7262 gtk_tree_view_drag_drop (GtkWidget        *widget,
7263                          GdkDragContext   *context,
7264                          /* coordinates relative to the widget */
7265                          gint              x,
7266                          gint              y,
7267                          guint             time)
7268 {
7269   GtkTreeView *tree_view;
7270   GtkTreePath *path;
7271   GdkDragAction suggested_action = 0;
7272   GdkAtom target = GDK_NONE;
7273   TreeViewDragInfo *di;
7274   GtkTreeModel *model;
7275   gboolean path_down_mode;
7276   gboolean drop_append_mode;
7277
7278   tree_view = GTK_TREE_VIEW (widget);
7279
7280   model = gtk_tree_view_get_model (tree_view);
7281
7282   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7283   remove_open_timeout (GTK_TREE_VIEW (widget));
7284
7285   di = get_info (tree_view);
7286
7287   if (di == NULL)
7288     return FALSE;
7289
7290   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7291     return FALSE;
7292
7293   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7294     return FALSE;
7295
7296   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7297
7298   if (target != GDK_NONE && path != NULL)
7299     {
7300       /* in case a motion had requested drag data, change things so we
7301        * treat drag data receives as a drop.
7302        */
7303       set_status_pending (context, 0);
7304       set_dest_row (context, model, path,
7305                     path_down_mode, tree_view->priv->empty_view_drop,
7306                     drop_append_mode);
7307     }
7308
7309   if (path)
7310     gtk_tree_path_free (path);
7311
7312   /* Unset this thing */
7313   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7314                                    NULL,
7315                                    GTK_TREE_VIEW_DROP_BEFORE);
7316
7317   if (target != GDK_NONE)
7318     {
7319       gtk_drag_get_data (widget, context, target, time);
7320       return TRUE;
7321     }
7322   else
7323     return FALSE;
7324 }
7325
7326 static void
7327 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7328                                   GdkDragContext   *context,
7329                                   /* coordinates relative to the widget */
7330                                   gint              x,
7331                                   gint              y,
7332                                   GtkSelectionData *selection_data,
7333                                   guint             info,
7334                                   guint             time)
7335 {
7336   GtkTreePath *path;
7337   TreeViewDragInfo *di;
7338   gboolean accepted = FALSE;
7339   GtkTreeModel *model;
7340   GtkTreeView *tree_view;
7341   GtkTreePath *dest_row;
7342   GdkDragAction suggested_action;
7343   gboolean path_down_mode;
7344   gboolean drop_append_mode;
7345
7346   tree_view = GTK_TREE_VIEW (widget);
7347
7348   model = gtk_tree_view_get_model (tree_view);
7349
7350   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7351     return;
7352
7353   di = get_info (tree_view);
7354
7355   if (di == NULL)
7356     return;
7357
7358   suggested_action = get_status_pending (context);
7359
7360   if (suggested_action)
7361     {
7362       /* We are getting this data due to a request in drag_motion,
7363        * rather than due to a request in drag_drop, so we are just
7364        * supposed to call drag_status, not actually paste in the
7365        * data.
7366        */
7367       path = get_logical_dest_row (tree_view, &path_down_mode,
7368                                    &drop_append_mode);
7369
7370       if (path == NULL)
7371         suggested_action = 0;
7372       else if (path_down_mode)
7373         gtk_tree_path_down (path);
7374
7375       if (suggested_action)
7376         {
7377           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7378                                                      path,
7379                                                      selection_data))
7380             {
7381               if (path_down_mode)
7382                 {
7383                   path_down_mode = FALSE;
7384                   gtk_tree_path_up (path);
7385
7386                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7387                                                              path,
7388                                                              selection_data))
7389                     suggested_action = 0;
7390                 }
7391               else
7392                 suggested_action = 0;
7393             }
7394         }
7395
7396       gdk_drag_status (context, suggested_action, time);
7397
7398       if (path)
7399         gtk_tree_path_free (path);
7400
7401       /* If you can't drop, remove user drop indicator until the next motion */
7402       if (suggested_action == 0)
7403         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7404                                          NULL,
7405                                          GTK_TREE_VIEW_DROP_BEFORE);
7406
7407       return;
7408     }
7409
7410   dest_row = get_dest_row (context, &path_down_mode);
7411
7412   if (dest_row == NULL)
7413     return;
7414
7415   if (selection_data->length >= 0)
7416     {
7417       if (path_down_mode)
7418         {
7419           gtk_tree_path_down (dest_row);
7420           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7421                                                      dest_row, selection_data))
7422             gtk_tree_path_up (dest_row);
7423         }
7424     }
7425
7426   if (selection_data->length >= 0)
7427     {
7428       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7429                                                  dest_row,
7430                                                  selection_data))
7431         accepted = TRUE;
7432     }
7433
7434   gtk_drag_finish (context,
7435                    accepted,
7436                    (context->action == GDK_ACTION_MOVE),
7437                    time);
7438
7439   if (gtk_tree_path_get_depth (dest_row) == 1
7440       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7441     {
7442       /* special special case drag to "0", scroll to first item */
7443       if (!tree_view->priv->scroll_to_path)
7444         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7445     }
7446
7447   gtk_tree_path_free (dest_row);
7448
7449   /* drop dest_row */
7450   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7451 }
7452
7453
7454
7455 /* GtkContainer Methods
7456  */
7457
7458
7459 static void
7460 gtk_tree_view_remove (GtkContainer *container,
7461                       GtkWidget    *widget)
7462 {
7463   GtkTreeView *tree_view;
7464   GtkTreeViewChild *child = NULL;
7465   GList *tmp_list;
7466
7467   g_return_if_fail (GTK_IS_TREE_VIEW (container));
7468
7469   tree_view = GTK_TREE_VIEW (container);
7470
7471   tmp_list = tree_view->priv->children;
7472   while (tmp_list)
7473     {
7474       child = tmp_list->data;
7475       if (child->widget == widget)
7476         {
7477           gtk_widget_unparent (widget);
7478
7479           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7480           g_list_free_1 (tmp_list);
7481           g_free (child);
7482           return;
7483         }
7484
7485       tmp_list = tmp_list->next;
7486     }
7487
7488   tmp_list = tree_view->priv->columns;
7489
7490   while (tmp_list)
7491     {
7492       GtkTreeViewColumn *column;
7493       column = tmp_list->data;
7494       if (column->button == widget)
7495         {
7496           gtk_widget_unparent (widget);
7497           return;
7498         }
7499       tmp_list = tmp_list->next;
7500     }
7501 }
7502
7503 static void
7504 gtk_tree_view_forall (GtkContainer *container,
7505                       gboolean      include_internals,
7506                       GtkCallback   callback,
7507                       gpointer      callback_data)
7508 {
7509   GtkTreeView *tree_view;
7510   GtkTreeViewChild *child = NULL;
7511   GtkTreeViewColumn *column;
7512   GList *tmp_list;
7513
7514   g_return_if_fail (GTK_IS_TREE_VIEW (container));
7515   g_return_if_fail (callback != NULL);
7516
7517   tree_view = GTK_TREE_VIEW (container);
7518
7519   tmp_list = tree_view->priv->children;
7520   while (tmp_list)
7521     {
7522       child = tmp_list->data;
7523       tmp_list = tmp_list->next;
7524
7525       (* callback) (child->widget, callback_data);
7526     }
7527   if (include_internals == FALSE)
7528     return;
7529
7530   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7531     {
7532       column = tmp_list->data;
7533
7534       if (column->button)
7535         (* callback) (column->button, callback_data);
7536     }
7537 }
7538
7539 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7540  * cells. If so we draw one big row-spanning focus rectangle.
7541  */
7542 static gboolean
7543 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7544 {
7545   GList *list;
7546
7547   for (list = tree_view->priv->columns; list; list = list->next)
7548     {
7549       if (!((GtkTreeViewColumn *)list->data)->visible)
7550         continue;
7551       if (_gtk_tree_view_column_count_special_cells (list->data))
7552         return TRUE;
7553     }
7554
7555   return FALSE;
7556 }
7557
7558 static void
7559 column_sizing_notify (GObject    *object,
7560                       GParamSpec *pspec,
7561                       gpointer    data)
7562 {
7563   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7564
7565   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7566     /* disable fixed height mode */
7567     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7568 }
7569
7570 /**
7571  * gtk_tree_view_set_fixed_height_mode:
7572  * @tree_view: a #GtkTreeView 
7573  * @enable: %TRUE to enable fixed height mode
7574  * 
7575  * Enables or disables the fixed height mode of @tree_view. 
7576  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7577  * rows have the same height. 
7578  * Only enable this option if all rows are the same height and all
7579  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7580  *
7581  * Since: 2.6 
7582  **/
7583 void
7584 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7585                                      gboolean     enable)
7586 {
7587   GList *l;
7588   
7589   enable = enable != FALSE;
7590
7591   if (enable == tree_view->priv->fixed_height_mode)
7592     return;
7593
7594   if (!enable)
7595     {
7596       tree_view->priv->fixed_height_mode = 0;
7597       tree_view->priv->fixed_height = -1;
7598
7599       /* force a revalidation */
7600       install_presize_handler (tree_view);
7601     }
7602   else 
7603     {
7604       /* make sure all columns are of type FIXED */
7605       for (l = tree_view->priv->columns; l; l = l->next)
7606         {
7607           GtkTreeViewColumn *c = l->data;
7608           
7609           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7610         }
7611       
7612       /* yes, we really have to do this is in a separate loop */
7613       for (l = tree_view->priv->columns; l; l = l->next)
7614         g_signal_connect (l->data, "notify::sizing",
7615                           G_CALLBACK (column_sizing_notify), tree_view);
7616       
7617       tree_view->priv->fixed_height_mode = 1;
7618       tree_view->priv->fixed_height = -1;
7619       
7620       if (tree_view->priv->tree)
7621         initialize_fixed_height_mode (tree_view);
7622     }
7623
7624   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7625 }
7626
7627 /**
7628  * gtk_tree_view_get_fixed_height_mode:
7629  * @tree_view: a #GtkTreeView
7630  * 
7631  * Returns whether fixed height mode is turned on for @tree_view.
7632  * 
7633  * Return value: %TRUE if @tree_view is in fixed height mode
7634  * 
7635  * Since: 2.6
7636  **/
7637 gboolean
7638 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7639 {
7640   return tree_view->priv->fixed_height_mode;
7641 }
7642
7643 /* Returns TRUE if the focus is within the headers, after the focus operation is
7644  * done
7645  */
7646 static gboolean
7647 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7648                             GtkDirectionType  dir,
7649                             gboolean          clamp_column_visible)
7650 {
7651   GtkWidget *focus_child;
7652
7653   GList *last_column, *first_column;
7654   GList *tmp_list;
7655   gboolean rtl;
7656
7657   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7658     return FALSE;
7659
7660   focus_child = GTK_CONTAINER (tree_view)->focus_child;
7661
7662   first_column = tree_view->priv->columns;
7663   while (first_column)
7664     {
7665       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7666           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7667           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7668            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7669         break;
7670       first_column = first_column->next;
7671     }
7672
7673   /* No headers are visible, or are focusable.  We can't focus in or out.
7674    */
7675   if (first_column == NULL)
7676     return FALSE;
7677
7678   last_column = g_list_last (tree_view->priv->columns);
7679   while (last_column)
7680     {
7681       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7682           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7683           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7684            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7685         break;
7686       last_column = last_column->prev;
7687     }
7688
7689
7690   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7691
7692   switch (dir)
7693     {
7694     case GTK_DIR_TAB_BACKWARD:
7695     case GTK_DIR_TAB_FORWARD:
7696     case GTK_DIR_UP:
7697     case GTK_DIR_DOWN:
7698       if (focus_child == NULL)
7699         {
7700           if (tree_view->priv->focus_column != NULL)
7701             focus_child = tree_view->priv->focus_column->button;
7702           else
7703             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7704           gtk_widget_grab_focus (focus_child);
7705           break;
7706         }
7707       return FALSE;
7708
7709     case GTK_DIR_LEFT:
7710     case GTK_DIR_RIGHT:
7711       if (focus_child == NULL)
7712         {
7713           if (tree_view->priv->focus_column != NULL)
7714             focus_child = tree_view->priv->focus_column->button;
7715           else if (dir == GTK_DIR_LEFT)
7716             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7717           else
7718             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7719           gtk_widget_grab_focus (focus_child);
7720           break;
7721         }
7722
7723       if (gtk_widget_child_focus (focus_child, dir))
7724         {
7725           /* The focus moves inside the button. */
7726           /* This is probably a great example of bad UI */
7727           break;
7728         }
7729
7730       /* We need to move the focus among the row of buttons. */
7731       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7732         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7733           break;
7734
7735       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7736           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7737         {
7738           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7739           break;
7740         }
7741
7742       while (tmp_list)
7743         {
7744           GtkTreeViewColumn *column;
7745
7746           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7747             tmp_list = tmp_list->next;
7748           else
7749             tmp_list = tmp_list->prev;
7750
7751           if (tmp_list == NULL)
7752             {
7753               g_warning ("Internal button not found");
7754               break;
7755             }
7756           column = tmp_list->data;
7757           if (column->button &&
7758               column->visible &&
7759               GTK_WIDGET_CAN_FOCUS (column->button))
7760             {
7761               focus_child = column->button;
7762               gtk_widget_grab_focus (column->button);
7763               break;
7764             }
7765         }
7766       break;
7767     default:
7768       g_assert_not_reached ();
7769       break;
7770     }
7771
7772   /* if focus child is non-null, we assume it's been set to the current focus child
7773    */
7774   if (focus_child)
7775     {
7776       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7777         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7778           {
7779             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7780             break;
7781           }
7782
7783       if (clamp_column_visible)
7784         {
7785           gtk_tree_view_clamp_column_visible (tree_view,
7786                                               tree_view->priv->focus_column,
7787                                               FALSE);
7788         }
7789     }
7790
7791   return (focus_child != NULL);
7792 }
7793
7794 /* This function returns in 'path' the first focusable path, if the given path
7795  * is already focusable, it's the returned one.
7796  */
7797 static gboolean
7798 search_first_focusable_path (GtkTreeView  *tree_view,
7799                              GtkTreePath **path,
7800                              gboolean      search_forward,
7801                              GtkRBTree   **new_tree,
7802                              GtkRBNode   **new_node)
7803 {
7804   GtkRBTree *tree = NULL;
7805   GtkRBNode *node = NULL;
7806
7807   if (!path || !*path)
7808     return FALSE;
7809
7810   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7811
7812   if (!tree || !node)
7813     return FALSE;
7814
7815   while (node && row_is_separator (tree_view, NULL, *path))
7816     {
7817       if (search_forward)
7818         _gtk_rbtree_next_full (tree, node, &tree, &node);
7819       else
7820         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7821
7822       if (*path)
7823         gtk_tree_path_free (*path);
7824
7825       if (node)
7826         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7827       else
7828         *path = NULL;
7829     }
7830
7831   if (new_tree)
7832     *new_tree = tree;
7833
7834   if (new_node)
7835     *new_node = node;
7836
7837   return (*path != NULL);
7838 }
7839
7840 static gint
7841 gtk_tree_view_focus (GtkWidget        *widget,
7842                      GtkDirectionType  direction)
7843 {
7844   GtkTreeView *tree_view;
7845   GtkWidget *focus_child;
7846   GtkContainer *container;
7847
7848   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
7849   g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
7850
7851   container = GTK_CONTAINER (widget);
7852   tree_view = GTK_TREE_VIEW (widget);
7853
7854   if (!GTK_WIDGET_IS_SENSITIVE (container))
7855     return FALSE;
7856
7857   focus_child = container->focus_child;
7858
7859   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
7860   /* Case 1.  Headers currently have focus. */
7861   if (focus_child)
7862     {
7863       switch (direction)
7864         {
7865         case GTK_DIR_LEFT:
7866         case GTK_DIR_RIGHT:
7867           gtk_tree_view_header_focus (tree_view, direction, TRUE);
7868           return TRUE;
7869         case GTK_DIR_TAB_BACKWARD:
7870         case GTK_DIR_UP:
7871           return FALSE;
7872         case GTK_DIR_TAB_FORWARD:
7873         case GTK_DIR_DOWN:
7874           gtk_widget_grab_focus (widget);
7875           return TRUE;
7876         default:
7877           g_assert_not_reached ();
7878           return FALSE;
7879         }
7880     }
7881
7882   /* Case 2. We don't have focus at all. */
7883   if (!GTK_WIDGET_HAS_FOCUS (container))
7884     {
7885       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
7886         gtk_widget_grab_focus (widget);
7887       return TRUE;
7888     }
7889
7890   /* Case 3. We have focus already. */
7891   if (direction == GTK_DIR_TAB_BACKWARD)
7892     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
7893   else if (direction == GTK_DIR_TAB_FORWARD)
7894     return FALSE;
7895
7896   /* Other directions caught by the keybindings */
7897   gtk_widget_grab_focus (widget);
7898   return TRUE;
7899 }
7900
7901 static void
7902 gtk_tree_view_grab_focus (GtkWidget *widget)
7903 {
7904   (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus) (widget);
7905
7906   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
7907 }
7908
7909 static void
7910 gtk_tree_view_style_set (GtkWidget *widget,
7911                          GtkStyle *previous_style)
7912 {
7913   GtkTreeView *tree_view;
7914   GList *list;
7915   GtkTreeViewColumn *column;
7916
7917   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
7918
7919   tree_view = GTK_TREE_VIEW (widget);
7920
7921   if (GTK_WIDGET_REALIZED (widget))
7922     {
7923       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
7924       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
7925       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
7926
7927       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
7928       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
7929     }
7930
7931   gtk_widget_style_get (widget,
7932                         "expander-size", &tree_view->priv->expander_size,
7933                         NULL);
7934   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
7935
7936   for (list = tree_view->priv->columns; list; list = list->next)
7937     {
7938       column = list->data;
7939       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
7940     }
7941
7942   tree_view->priv->fixed_height = -1;
7943   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
7944
7945   gtk_widget_queue_resize (widget);
7946 }
7947
7948
7949 static void
7950 gtk_tree_view_set_focus_child (GtkContainer *container,
7951                                GtkWidget    *child)
7952 {
7953   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7954   GList *list;
7955
7956   for (list = tree_view->priv->columns; list; list = list->next)
7957     {
7958       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
7959         {
7960           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
7961           break;
7962         }
7963     }
7964
7965   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
7966 }
7967
7968 static void
7969 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
7970                                GtkAdjustment *hadj,
7971                                GtkAdjustment *vadj)
7972 {
7973   gboolean need_adjust = FALSE;
7974
7975   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7976
7977   if (hadj)
7978     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
7979   else
7980     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7981   if (vadj)
7982     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
7983   else
7984     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7985
7986   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
7987     {
7988       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
7989                                             gtk_tree_view_adjustment_changed,
7990                                             tree_view);
7991       g_object_unref (tree_view->priv->hadjustment);
7992     }
7993
7994   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
7995     {
7996       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
7997                                             gtk_tree_view_adjustment_changed,
7998                                             tree_view);
7999       g_object_unref (tree_view->priv->vadjustment);
8000     }
8001
8002   if (tree_view->priv->hadjustment != hadj)
8003     {
8004       tree_view->priv->hadjustment = hadj;
8005       g_object_ref_sink (tree_view->priv->hadjustment);
8006
8007       g_signal_connect (tree_view->priv->hadjustment, "value_changed",
8008                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8009                         tree_view);
8010       need_adjust = TRUE;
8011     }
8012
8013   if (tree_view->priv->vadjustment != vadj)
8014     {
8015       tree_view->priv->vadjustment = vadj;
8016       g_object_ref_sink (tree_view->priv->vadjustment);
8017
8018       g_signal_connect (tree_view->priv->vadjustment, "value_changed",
8019                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8020                         tree_view);
8021       need_adjust = TRUE;
8022     }
8023
8024   if (need_adjust)
8025     gtk_tree_view_adjustment_changed (NULL, tree_view);
8026 }
8027
8028
8029 static gboolean
8030 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8031                                 GtkMovementStep    step,
8032                                 gint               count)
8033 {
8034   GdkModifierType state;
8035
8036   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8037   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8038                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8039                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8040                         step == GTK_MOVEMENT_PAGES ||
8041                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8042
8043   if (tree_view->priv->tree == NULL)
8044     return FALSE;
8045   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
8046     return FALSE;
8047
8048   gtk_tree_view_stop_editing (tree_view, FALSE);
8049   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8050   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8051
8052   if (gtk_get_current_event_state (&state))
8053     {
8054       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8055         tree_view->priv->ctrl_pressed = TRUE;
8056       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8057         tree_view->priv->shift_pressed = TRUE;
8058     }
8059   /* else we assume not pressed */
8060
8061   switch (step)
8062     {
8063       /* currently we make no distinction.  When we go bi-di, we need to */
8064     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8065     case GTK_MOVEMENT_VISUAL_POSITIONS:
8066       gtk_tree_view_move_cursor_left_right (tree_view, count);
8067       break;
8068     case GTK_MOVEMENT_DISPLAY_LINES:
8069       gtk_tree_view_move_cursor_up_down (tree_view, count);
8070       break;
8071     case GTK_MOVEMENT_PAGES:
8072       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8073       break;
8074     case GTK_MOVEMENT_BUFFER_ENDS:
8075       gtk_tree_view_move_cursor_start_end (tree_view, count);
8076       break;
8077     default:
8078       g_assert_not_reached ();
8079     }
8080
8081   tree_view->priv->ctrl_pressed = FALSE;
8082   tree_view->priv->shift_pressed = FALSE;
8083
8084   return TRUE;
8085 }
8086
8087 static void
8088 gtk_tree_view_put (GtkTreeView *tree_view,
8089                    GtkWidget   *child_widget,
8090                    /* in bin_window coordinates */
8091                    gint         x,
8092                    gint         y,
8093                    gint         width,
8094                    gint         height)
8095 {
8096   GtkTreeViewChild *child;
8097   
8098   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8099   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8100
8101   child = g_new (GtkTreeViewChild, 1);
8102
8103   child->widget = child_widget;
8104   child->x = x;
8105   child->y = y;
8106   child->width = width;
8107   child->height = height;
8108
8109   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8110
8111   if (GTK_WIDGET_REALIZED (tree_view))
8112     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8113   
8114   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8115 }
8116
8117 void
8118 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8119                                   GtkWidget   *widget,
8120                                   /* in tree coordinates */
8121                                   gint         x,
8122                                   gint         y,
8123                                   gint         width,
8124                                   gint         height)
8125 {
8126   GtkTreeViewChild *child = NULL;
8127   GList *list;
8128   GdkRectangle allocation;
8129
8130   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8131   g_return_if_fail (GTK_IS_WIDGET (widget));
8132
8133   for (list = tree_view->priv->children; list; list = list->next)
8134     {
8135       if (((GtkTreeViewChild *)list->data)->widget == widget)
8136         {
8137           child = list->data;
8138           break;
8139         }
8140     }
8141   if (child == NULL)
8142     return;
8143
8144   allocation.x = child->x = x;
8145   allocation.y = child->y = y;
8146   allocation.width = child->width = width;
8147   allocation.height = child->height = height;
8148
8149   if (GTK_WIDGET_REALIZED (widget))
8150     gtk_widget_size_allocate (widget, &allocation);
8151 }
8152
8153
8154 /* TreeModel Callbacks
8155  */
8156
8157 static void
8158 gtk_tree_view_row_changed (GtkTreeModel *model,
8159                            GtkTreePath  *path,
8160                            GtkTreeIter  *iter,
8161                            gpointer      data)
8162 {
8163   GtkTreeView *tree_view = (GtkTreeView *)data;
8164   GtkRBTree *tree;
8165   GtkRBNode *node;
8166   gboolean free_path = FALSE;
8167   GList *list;
8168   GtkTreePath *cursor_path;
8169
8170   g_return_if_fail (path != NULL || iter != NULL);
8171
8172   if (tree_view->priv->cursor != NULL)
8173     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8174   else
8175     cursor_path = NULL;
8176
8177   if (tree_view->priv->edited_column &&
8178       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8179     gtk_tree_view_stop_editing (tree_view, TRUE);
8180
8181   if (cursor_path != NULL)
8182     gtk_tree_path_free (cursor_path);
8183
8184   if (path == NULL)
8185     {
8186       path = gtk_tree_model_get_path (model, iter);
8187       free_path = TRUE;
8188     }
8189   else if (iter == NULL)
8190     gtk_tree_model_get_iter (model, iter, path);
8191
8192   if (_gtk_tree_view_find_node (tree_view,
8193                                 path,
8194                                 &tree,
8195                                 &node))
8196     /* We aren't actually showing the node */
8197     goto done;
8198
8199   if (tree == NULL)
8200     goto done;
8201
8202   if (tree_view->priv->fixed_height_mode
8203       && tree_view->priv->fixed_height >= 0)
8204     {
8205       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8206       if (GTK_WIDGET_REALIZED (tree_view))
8207         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8208     }
8209   else
8210     {
8211       _gtk_rbtree_node_mark_invalid (tree, node);
8212       for (list = tree_view->priv->columns; list; list = list->next)
8213         {
8214           GtkTreeViewColumn *column;
8215
8216           column = list->data;
8217           if (! column->visible)
8218             continue;
8219
8220           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8221             {
8222               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8223             }
8224         }
8225     }
8226
8227  done:
8228   if (GTK_WIDGET_REALIZED (tree_view) && !tree_view->priv->fixed_height_mode)
8229     install_presize_handler (tree_view);
8230   if (free_path)
8231     gtk_tree_path_free (path);
8232 }
8233
8234 static void
8235 gtk_tree_view_row_inserted (GtkTreeModel *model,
8236                             GtkTreePath  *path,
8237                             GtkTreeIter  *iter,
8238                             gpointer      data)
8239 {
8240   GtkTreeView *tree_view = (GtkTreeView *) data;
8241   gint *indices;
8242   GtkRBTree *tmptree, *tree;
8243   GtkRBNode *tmpnode = NULL;
8244   gint depth;
8245   gint i = 0;
8246   gint height;
8247   gboolean free_path = FALSE;
8248   gboolean node_visible = TRUE;
8249
8250   g_return_if_fail (path != NULL || iter != NULL);
8251
8252   if (tree_view->priv->fixed_height_mode
8253       && tree_view->priv->fixed_height >= 0)
8254     height = tree_view->priv->fixed_height;
8255   else
8256     height = 0;
8257
8258   if (path == NULL)
8259     {
8260       path = gtk_tree_model_get_path (model, iter);
8261       free_path = TRUE;
8262     }
8263   else if (iter == NULL)
8264     gtk_tree_model_get_iter (model, iter, path);
8265
8266   if (tree_view->priv->tree == NULL)
8267     tree_view->priv->tree = _gtk_rbtree_new ();
8268
8269   tmptree = tree = tree_view->priv->tree;
8270
8271   /* Update all row-references */
8272   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8273   depth = gtk_tree_path_get_depth (path);
8274   indices = gtk_tree_path_get_indices (path);
8275
8276   /* First, find the parent tree */
8277   while (i < depth - 1)
8278     {
8279       if (tmptree == NULL)
8280         {
8281           /* We aren't showing the node */
8282           node_visible = FALSE;
8283           goto done;
8284         }
8285
8286       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8287       if (tmpnode == NULL)
8288         {
8289           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8290                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8291                      "before the parent was inserted.");
8292           goto done;
8293         }
8294       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8295         {
8296           /* FIXME enforce correct behavior on model, probably */
8297           /* In theory, the model should have emitted has_child_toggled here.  We
8298            * try to catch it anyway, just to be safe, in case the model hasn't.
8299            */
8300           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8301                                                            tree,
8302                                                            tmpnode);
8303           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8304           gtk_tree_path_free (tmppath);
8305           goto done;
8306         }
8307
8308       tmptree = tmpnode->children;
8309       tree = tmptree;
8310       i++;
8311     }
8312
8313   if (tree == NULL)
8314     {
8315       node_visible = FALSE;
8316       goto done;
8317     }
8318
8319   /* ref the node */
8320   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8321   if (indices[depth - 1] == 0)
8322     {
8323       tmpnode = _gtk_rbtree_find_count (tree, 1);
8324       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8325     }
8326   else
8327     {
8328       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8329       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8330     }
8331
8332  done:
8333   if (height > 0)
8334     {
8335       if (tree)
8336         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8337
8338       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8339         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8340       else
8341         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8342     }
8343   else
8344     install_presize_handler (tree_view);
8345   if (free_path)
8346     gtk_tree_path_free (path);
8347 }
8348
8349 static void
8350 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8351                                      GtkTreePath  *path,
8352                                      GtkTreeIter  *iter,
8353                                      gpointer      data)
8354 {
8355   GtkTreeView *tree_view = (GtkTreeView *)data;
8356   GtkTreeIter real_iter;
8357   gboolean has_child;
8358   GtkRBTree *tree;
8359   GtkRBNode *node;
8360   gboolean free_path = FALSE;
8361
8362   g_return_if_fail (path != NULL || iter != NULL);
8363
8364   if (iter)
8365     real_iter = *iter;
8366
8367   if (path == NULL)
8368     {
8369       path = gtk_tree_model_get_path (model, iter);
8370       free_path = TRUE;
8371     }
8372   else if (iter == NULL)
8373     gtk_tree_model_get_iter (model, &real_iter, path);
8374
8375   if (_gtk_tree_view_find_node (tree_view,
8376                                 path,
8377                                 &tree,
8378                                 &node))
8379     /* We aren't actually showing the node */
8380     goto done;
8381
8382   if (tree == NULL)
8383     goto done;
8384
8385   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8386   /* Sanity check.
8387    */
8388   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8389     goto done;
8390
8391   if (has_child)
8392     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8393   else
8394     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8395
8396   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8397     {
8398       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8399       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8400         {
8401           GList *list;
8402
8403           for (list = tree_view->priv->columns; list; list = list->next)
8404             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8405               {
8406                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8407                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8408                 break;
8409               }
8410         }
8411       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8412     }
8413   else
8414     {
8415       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8416     }
8417
8418  done:
8419   if (free_path)
8420     gtk_tree_path_free (path);
8421 }
8422
8423 static void
8424 count_children_helper (GtkRBTree *tree,
8425                        GtkRBNode *node,
8426                        gpointer   data)
8427 {
8428   if (node->children)
8429     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8430   (*((gint *)data))++;
8431 }
8432
8433 static void
8434 check_selection_helper (GtkRBTree *tree,
8435                         GtkRBNode *node,
8436                         gpointer   data)
8437 {
8438   gint *value = (gint *)data;
8439
8440   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8441
8442   if (node->children && !*value)
8443     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8444 }
8445
8446 static void
8447 gtk_tree_view_row_deleted (GtkTreeModel *model,
8448                            GtkTreePath  *path,
8449                            gpointer      data)
8450 {
8451   GtkTreeView *tree_view = (GtkTreeView *)data;
8452   GtkRBTree *tree;
8453   GtkRBNode *node;
8454   GList *list;
8455   gint selection_changed = FALSE;
8456
8457   g_return_if_fail (path != NULL);
8458
8459   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8460
8461   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8462     return;
8463
8464   if (tree == NULL)
8465     return;
8466
8467   /* check if the selection has been changed */
8468   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8469                         check_selection_helper, &selection_changed);
8470
8471   for (list = tree_view->priv->columns; list; list = list->next)
8472     if (((GtkTreeViewColumn *)list->data)->visible &&
8473         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8474       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8475
8476   /* Ensure we don't have a dangling pointer to a dead node */
8477   ensure_unprelighted (tree_view);
8478
8479   /* Cancel editting if we've started */
8480   gtk_tree_view_stop_editing (tree_view, TRUE);
8481
8482   /* If we have a node expanded/collapsed timeout, remove it */
8483   if (tree_view->priv->expand_collapse_timeout != 0)
8484     {
8485       g_source_remove (tree_view->priv->expand_collapse_timeout);
8486       tree_view->priv->expand_collapse_timeout = 0;
8487
8488       /* Reset node */
8489       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
8490       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
8491       tree_view->priv->expanded_collapsed_node = NULL;
8492     }
8493
8494   if (tree_view->priv->destroy_count_func)
8495     {
8496       gint child_count = 0;
8497       if (node->children)
8498         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8499       (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8500     }
8501
8502   if (tree->root->count == 1)
8503     {
8504       if (tree_view->priv->tree == tree)
8505         tree_view->priv->tree = NULL;
8506
8507       _gtk_rbtree_remove (tree);
8508     }
8509   else
8510     {
8511       _gtk_rbtree_remove_node (tree, node);
8512     }
8513
8514   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8515     {
8516       gtk_tree_row_reference_free (tree_view->priv->top_row);
8517       tree_view->priv->top_row = NULL;
8518     }
8519
8520   install_scroll_sync_handler (tree_view);
8521
8522   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8523
8524   if (selection_changed)
8525     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8526 }
8527
8528 static void
8529 cancel_arrow_animation (GtkTreeView *tree_view)
8530 {
8531   if (tree_view->priv->expand_collapse_timeout)
8532     {
8533       while (do_expand_collapse (tree_view));
8534
8535       g_source_remove (tree_view->priv->expand_collapse_timeout);
8536       tree_view->priv->expand_collapse_timeout = 0;
8537     }
8538 }
8539
8540 static void
8541 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8542                               GtkTreePath  *parent,
8543                               GtkTreeIter  *iter,
8544                               gint         *new_order,
8545                               gpointer      data)
8546 {
8547   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8548   GtkRBTree *tree;
8549   GtkRBNode *node;
8550   gint len;
8551
8552   len = gtk_tree_model_iter_n_children (model, iter);
8553
8554   if (len < 2)
8555     return;
8556
8557   gtk_tree_row_reference_reordered (G_OBJECT (data),
8558                                     parent,
8559                                     iter,
8560                                     new_order);
8561
8562   if (_gtk_tree_view_find_node (tree_view,
8563                                 parent,
8564                                 &tree,
8565                                 &node))
8566     return;
8567
8568   /* We need to special case the parent path */
8569   if (tree == NULL)
8570     tree = tree_view->priv->tree;
8571   else
8572     tree = node->children;
8573
8574   if (tree == NULL)
8575     return;
8576
8577   if (tree_view->priv->edited_column)
8578     gtk_tree_view_stop_editing (tree_view, TRUE);
8579
8580   /* we need to be unprelighted */
8581   ensure_unprelighted (tree_view);
8582
8583   /* clear the timeout */
8584   cancel_arrow_animation (tree_view);
8585   
8586   _gtk_rbtree_reorder (tree, new_order, len);
8587
8588   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8589
8590   gtk_tree_view_dy_to_top_row (tree_view);
8591 }
8592
8593
8594 /* Internal tree functions
8595  */
8596
8597
8598 static void
8599 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8600                                      GtkRBTree         *tree,
8601                                      GtkTreeViewColumn *column,
8602                                      gint              *x1,
8603                                      gint              *x2)
8604 {
8605   GtkTreeViewColumn *tmp_column = NULL;
8606   gint total_width;
8607   GList *list;
8608   gboolean rtl;
8609
8610   if (x1)
8611     *x1 = 0;
8612
8613   if (x2)
8614     *x2 = 0;
8615
8616   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8617
8618   total_width = 0;
8619   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8620        list;
8621        list = (rtl ? list->prev : list->next))
8622     {
8623       tmp_column = list->data;
8624
8625       if (tmp_column == column)
8626         break;
8627
8628       if (tmp_column->visible)
8629         total_width += tmp_column->width;
8630     }
8631
8632   if (tmp_column != column)
8633     {
8634       g_warning (G_STRLOC": passed-in column isn't in the tree");
8635       return;
8636     }
8637
8638   if (x1)
8639     *x1 = total_width;
8640
8641   if (x2)
8642     {
8643       if (column->visible)
8644         *x2 = total_width + column->width;
8645       else
8646         *x2 = total_width; /* width of 0 */
8647     }
8648 }
8649 static void
8650 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8651                                 GtkRBTree   *tree,
8652                                 gint        *x1,
8653                                 gint        *x2)
8654 {
8655   gint x_offset = 0;
8656   GList *list;
8657   GtkTreeViewColumn *tmp_column = NULL;
8658   gint total_width;
8659   gboolean indent_expanders;
8660   gboolean rtl;
8661
8662   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8663
8664   total_width = 0;
8665   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8666        list;
8667        list = (rtl ? list->prev : list->next))
8668     {
8669       tmp_column = list->data;
8670
8671       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8672         {
8673           if (rtl)
8674             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8675           else
8676             x_offset = total_width;
8677           break;
8678         }
8679
8680       if (tmp_column->visible)
8681         total_width += tmp_column->width;
8682     }
8683
8684   gtk_widget_style_get (GTK_WIDGET (tree_view),
8685                         "indent-expanders", &indent_expanders,
8686                         NULL);
8687
8688   if (indent_expanders)
8689     {
8690       if (rtl)
8691         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8692       else
8693         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8694     }
8695
8696   *x1 = x_offset;
8697   
8698   if (tmp_column && tmp_column->visible)
8699     /* +1 because x2 isn't included in the range. */
8700     *x2 = *x1 + tree_view->priv->expander_size + 1;
8701   else
8702     *x2 = *x1;
8703 }
8704
8705 static void
8706 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8707                           GtkRBTree   *tree,
8708                           GtkTreeIter *iter,
8709                           gint         depth,
8710                           gboolean     recurse)
8711 {
8712   GtkRBNode *temp = NULL;
8713   GtkTreePath *path = NULL;
8714   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8715
8716   do
8717     {
8718       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8719       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8720
8721       if (tree_view->priv->fixed_height > 0)
8722         {
8723           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8724             {
8725               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8726               _gtk_rbtree_node_mark_valid (tree, temp);
8727             }
8728         }
8729
8730       if (is_list)
8731         continue;
8732
8733       if (recurse)
8734         {
8735           GtkTreeIter child;
8736
8737           if (!path)
8738             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8739           else
8740             gtk_tree_path_next (path);
8741
8742           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8743             {
8744               gboolean expand;
8745
8746               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8747
8748               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8749                   && !expand)
8750                 {
8751                   temp->children = _gtk_rbtree_new ();
8752                   temp->children->parent_tree = tree;
8753                   temp->children->parent_node = temp;
8754                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8755                 }
8756             }
8757         }
8758
8759       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8760         {
8761           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8762             temp->flags ^= GTK_RBNODE_IS_PARENT;
8763         }
8764     }
8765   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8766
8767   if (path)
8768     gtk_tree_path_free (path);
8769 }
8770
8771 /* If height is non-NULL, then we set it to be the new height.  if it's all
8772  * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
8773  */
8774 static gboolean
8775 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
8776                                    GtkTreeIter *iter,
8777                                    gint         depth,
8778                                    gint        *height,
8779                                    GtkRBNode   *node)
8780 {
8781   GtkTreeViewColumn *column;
8782   GList *list;
8783   gboolean retval = FALSE;
8784   gint tmpheight;
8785   gint horizontal_separator;
8786
8787   gtk_widget_style_get (GTK_WIDGET (tree_view),
8788                         "horizontal-separator", &horizontal_separator,
8789                         NULL);
8790
8791   if (height)
8792     *height = -1;
8793
8794   for (list = tree_view->priv->columns; list; list = list->next)
8795     {
8796       gint width;
8797       column = list->data;
8798       if (column->dirty == TRUE)
8799         continue;
8800       if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
8801         continue;
8802       if (!column->visible)
8803         continue;
8804
8805       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
8806                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
8807                                                node->children?TRUE:FALSE);
8808
8809       if (height)
8810         {
8811           gtk_tree_view_column_cell_get_size (column,
8812                                               NULL, NULL, NULL,
8813                                               &width, &tmpheight);
8814           *height = MAX (*height, tmpheight);
8815         }
8816       else
8817         {
8818           gtk_tree_view_column_cell_get_size (column,
8819                                               NULL, NULL, NULL,
8820                                               &width, NULL);
8821         }
8822
8823       if (gtk_tree_view_is_expander_column (tree_view, column))
8824         {
8825           int tmp = 0;
8826
8827           tmp = horizontal_separator + width + (depth - 1) * tree_view->priv->level_indentation;
8828           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
8829             tmp += depth * tree_view->priv->expander_size;
8830
8831           if (tmp > column->requested_width)
8832             {
8833               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8834               retval = TRUE;
8835             }
8836         }
8837       else
8838         {
8839           if (horizontal_separator + width > column->requested_width)
8840             {
8841               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8842               retval = TRUE;
8843             }
8844         }
8845     }
8846
8847   return retval;
8848 }
8849
8850 static void
8851 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
8852                               GtkRBTree   *tree,
8853                               GtkTreeIter *iter,
8854                               gint         depth)
8855 {
8856   GtkRBNode *temp = tree->root;
8857   GtkTreeViewColumn *column;
8858   GList *list;
8859   GtkTreeIter child;
8860   gboolean is_all_dirty;
8861
8862   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
8863
8864   while (temp->left != tree->nil)
8865     temp = temp->left;
8866
8867   do
8868     {
8869       TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
8870       is_all_dirty = TRUE;
8871       for (list = tree_view->priv->columns; list; list = list->next)
8872         {
8873           column = list->data;
8874           if (column->dirty == FALSE)
8875             {
8876               is_all_dirty = FALSE;
8877               break;
8878             }
8879         }
8880
8881       if (is_all_dirty)
8882         return;
8883
8884       gtk_tree_view_discover_dirty_iter (tree_view,
8885                                          iter,
8886                                          depth,
8887                                          NULL,
8888                                          temp);
8889       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
8890           temp->children != NULL)
8891         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
8892       temp = _gtk_rbtree_next (tree, temp);
8893     }
8894   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8895 }
8896
8897
8898 /* Make sure the node is visible vertically */
8899 static void
8900 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8901                                   GtkRBTree   *tree,
8902                                   GtkRBNode   *node)
8903 {
8904   gint node_dy, height;
8905   GtkTreePath *path = NULL;
8906
8907   if (!GTK_WIDGET_REALIZED (tree_view))
8908     return;
8909
8910   /* just return if the node is visible, avoiding a costly expose */
8911   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8912   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8913   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8914       && node_dy >= tree_view->priv->vadjustment->value
8915       && node_dy + height <= (tree_view->priv->vadjustment->value
8916                               + tree_view->priv->vadjustment->page_size))
8917     return;
8918
8919   path = _gtk_tree_view_find_path (tree_view, tree, node);
8920   if (path)
8921     {
8922       /* We process updates because we want to clear old selected items when we scroll.
8923        * if this is removed, we get a "selection streak" at the bottom. */
8924       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8925       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8926       gtk_tree_path_free (path);
8927     }
8928 }
8929
8930 static void
8931 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8932                                     GtkTreeViewColumn *column,
8933                                     gboolean           focus_to_cell)
8934 {
8935   gint x, width;
8936
8937   if (column == NULL)
8938     return;
8939
8940   x = column->button->allocation.x;
8941   width = column->button->allocation.width;
8942
8943   if (width > tree_view->priv->hadjustment->page_size)
8944     {
8945       /* The column is larger than the horizontal page size.  If the
8946        * column has cells which can be focussed individually, then we make
8947        * sure the cell which gets focus is fully visible (if even the
8948        * focus cell is bigger than the page size, we make sure the
8949        * left-hand side of the cell is visible).
8950        *
8951        * If the column does not have those so-called special cells, we
8952        * make sure the left-hand side of the column is visible.
8953        */
8954
8955       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8956         {
8957           GtkTreePath *cursor_path;
8958           GdkRectangle background_area, cell_area, focus_area;
8959
8960           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8961
8962           gtk_tree_view_get_cell_area (tree_view,
8963                                        cursor_path, column, &cell_area);
8964           gtk_tree_view_get_background_area (tree_view,
8965                                              cursor_path, column,
8966                                              &background_area);
8967
8968           gtk_tree_path_free (cursor_path);
8969
8970           _gtk_tree_view_column_get_focus_area (column,
8971                                                 &background_area,
8972                                                 &cell_area,
8973                                                 &focus_area);
8974
8975           x = focus_area.x;
8976           width = focus_area.width;
8977
8978           if (width < tree_view->priv->hadjustment->page_size)
8979             {
8980               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8981                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8982                                           x + width - tree_view->priv->hadjustment->page_size);
8983               else if (tree_view->priv->hadjustment->value > x)
8984                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8985             }
8986         }
8987
8988       gtk_adjustment_set_value (tree_view->priv->hadjustment,
8989                                 CLAMP (x,
8990                                        tree_view->priv->hadjustment->lower,
8991                                        tree_view->priv->hadjustment->upper
8992                                        - tree_view->priv->hadjustment->page_size));
8993     }
8994   else
8995     {
8996       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8997           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8998                                     x + width - tree_view->priv->hadjustment->page_size);
8999       else if (tree_view->priv->hadjustment->value > x)
9000         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9001   }
9002 }
9003
9004 /* This function could be more efficient.  I'll optimize it if profiling seems
9005  * to imply that it is important */
9006 GtkTreePath *
9007 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9008                           GtkRBTree   *tree,
9009                           GtkRBNode   *node)
9010 {
9011   GtkTreePath *path;
9012   GtkRBTree *tmp_tree;
9013   GtkRBNode *tmp_node, *last;
9014   gint count;
9015
9016   path = gtk_tree_path_new ();
9017
9018   g_return_val_if_fail (node != NULL, path);
9019   g_return_val_if_fail (node != tree->nil, path);
9020
9021   count = 1 + node->left->count;
9022
9023   last = node;
9024   tmp_node = node->parent;
9025   tmp_tree = tree;
9026   while (tmp_tree)
9027     {
9028       while (tmp_node != tmp_tree->nil)
9029         {
9030           if (tmp_node->right == last)
9031             count += 1 + tmp_node->left->count;
9032           last = tmp_node;
9033           tmp_node = tmp_node->parent;
9034         }
9035       gtk_tree_path_prepend_index (path, count - 1);
9036       last = tmp_tree->parent_node;
9037       tmp_tree = tmp_tree->parent_tree;
9038       if (last)
9039         {
9040           count = 1 + last->left->count;
9041           tmp_node = last->parent;
9042         }
9043     }
9044   return path;
9045 }
9046
9047 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9048  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9049  * both set to NULL.
9050  */
9051 gboolean
9052 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9053                           GtkTreePath  *path,
9054                           GtkRBTree   **tree,
9055                           GtkRBNode   **node)
9056 {
9057   GtkRBNode *tmpnode = NULL;
9058   GtkRBTree *tmptree = tree_view->priv->tree;
9059   gint *indices = gtk_tree_path_get_indices (path);
9060   gint depth = gtk_tree_path_get_depth (path);
9061   gint i = 0;
9062
9063   *node = NULL;
9064   *tree = NULL;
9065
9066   if (depth == 0 || tmptree == NULL)
9067     return FALSE;
9068   do
9069     {
9070       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9071       ++i;
9072       if (tmpnode == NULL)
9073         {
9074           *tree = NULL;
9075           *node = NULL;
9076           return FALSE;
9077         }
9078       if (i >= depth)
9079         {
9080           *tree = tmptree;
9081           *node = tmpnode;
9082           return FALSE;
9083         }
9084       *tree = tmptree;
9085       *node = tmpnode;
9086       tmptree = tmpnode->children;
9087       if (tmptree == NULL)
9088         return TRUE;
9089     }
9090   while (1);
9091 }
9092
9093 static gboolean
9094 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9095                                   GtkTreeViewColumn *column)
9096 {
9097   GList *list;
9098
9099   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9100     return FALSE;
9101
9102   if (tree_view->priv->expander_column != NULL)
9103     {
9104       if (tree_view->priv->expander_column == column)
9105         return TRUE;
9106       return FALSE;
9107     }
9108   else
9109     {
9110       for (list = tree_view->priv->columns;
9111            list;
9112            list = list->next)
9113         if (((GtkTreeViewColumn *)list->data)->visible)
9114           break;
9115       if (list && list->data == column)
9116         return TRUE;
9117     }
9118   return FALSE;
9119 }
9120
9121 static void
9122 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9123                                 guint           keyval,
9124                                 guint           modmask,
9125                                 gboolean        add_shifted_binding,
9126                                 GtkMovementStep step,
9127                                 gint            count)
9128 {
9129   
9130   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9131                                 "move_cursor", 2,
9132                                 G_TYPE_ENUM, step,
9133                                 G_TYPE_INT, count);
9134
9135   if (add_shifted_binding)
9136     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9137                                   "move_cursor", 2,
9138                                   G_TYPE_ENUM, step,
9139                                   G_TYPE_INT, count);
9140
9141   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9142    return;
9143
9144   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9145                                 "move_cursor", 2,
9146                                 G_TYPE_ENUM, step,
9147                                 G_TYPE_INT, count);
9148
9149   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9150                                 "move_cursor", 2,
9151                                 G_TYPE_ENUM, step,
9152                                 G_TYPE_INT, count);
9153 }
9154
9155 static gint
9156 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9157                                  GtkTreeIter  *iter,
9158                                  GtkRBTree    *tree,
9159                                  GtkRBNode    *node)
9160 {
9161   gint retval = FALSE;
9162   do
9163     {
9164       g_return_val_if_fail (node != NULL, FALSE);
9165
9166       if (node->children)
9167         {
9168           GtkTreeIter child;
9169           GtkRBTree *new_tree;
9170           GtkRBNode *new_node;
9171
9172           new_tree = node->children;
9173           new_node = new_tree->root;
9174
9175           while (new_node && new_node->left != new_tree->nil)
9176             new_node = new_node->left;
9177
9178           if (!gtk_tree_model_iter_children (model, &child, iter))
9179             return FALSE;
9180
9181           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9182         }
9183
9184       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9185         retval = TRUE;
9186       gtk_tree_model_unref_node (model, iter);
9187       node = _gtk_rbtree_next (tree, node);
9188     }
9189   while (gtk_tree_model_iter_next (model, iter));
9190
9191   return retval;
9192 }
9193
9194 static gint
9195 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9196                                               GtkRBTree   *tree)
9197 {
9198   GtkTreeIter iter;
9199   GtkTreePath *path;
9200   GtkRBNode *node;
9201   gint retval;
9202
9203   if (!tree)
9204     return FALSE;
9205
9206   node = tree->root;
9207   while (node && node->left != tree->nil)
9208     node = node->left;
9209
9210   g_return_val_if_fail (node != NULL, FALSE);
9211   path = _gtk_tree_view_find_path (tree_view, tree, node);
9212   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9213                            &iter, path);
9214   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9215   gtk_tree_path_free (path);
9216
9217   return retval;
9218 }
9219
9220 static void
9221 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9222                                     GtkTreeViewColumn *column)
9223 {
9224   GtkTreeViewColumn *left_column;
9225   GtkTreeViewColumn *cur_column = NULL;
9226   GtkTreeViewColumnReorder *reorder;
9227   gboolean rtl;
9228   GList *tmp_list;
9229   gint left;
9230
9231   /* We want to precalculate the motion list such that we know what column slots
9232    * are available.
9233    */
9234   left_column = NULL;
9235   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9236
9237   /* First, identify all possible drop spots */
9238   if (rtl)
9239     tmp_list = g_list_last (tree_view->priv->columns);
9240   else
9241     tmp_list = g_list_first (tree_view->priv->columns);
9242
9243   while (tmp_list)
9244     {
9245       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9246       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9247
9248       if (cur_column->visible == FALSE)
9249         continue;
9250
9251       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9252       if (left_column != column && cur_column != column &&
9253           tree_view->priv->column_drop_func &&
9254           ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9255         {
9256           left_column = cur_column;
9257           continue;
9258         }
9259       reorder = g_new (GtkTreeViewColumnReorder, 1);
9260       reorder->left_column = left_column;
9261       left_column = reorder->right_column = cur_column;
9262
9263       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9264     }
9265
9266   /* Add the last one */
9267   if (tree_view->priv->column_drop_func == NULL ||
9268       ((left_column != column) &&
9269        (* tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9270     {
9271       reorder = g_new (GtkTreeViewColumnReorder, 1);
9272       reorder->left_column = left_column;
9273       reorder->right_column = NULL;
9274       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9275     }
9276
9277   /* We quickly check to see if it even makes sense to reorder columns. */
9278   /* If there is nothing that can be moved, then we return */
9279
9280   if (tree_view->priv->column_drag_info == NULL)
9281     return;
9282
9283   /* We know there are always 2 slots possbile, as you can always return column. */
9284   /* If that's all there is, return */
9285   if (tree_view->priv->column_drag_info->next == NULL || 
9286       (tree_view->priv->column_drag_info->next->next == NULL &&
9287        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9288        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9289     {
9290       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9291         g_free (tmp_list->data);
9292       g_list_free (tree_view->priv->column_drag_info);
9293       tree_view->priv->column_drag_info = NULL;
9294       return;
9295     }
9296   /* We fill in the ranges for the columns, now that we've isolated them */
9297   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9298
9299   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9300     {
9301       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9302
9303       reorder->left_align = left;
9304       if (tmp_list->next != NULL)
9305         {
9306           g_assert (tmp_list->next->data);
9307           left = reorder->right_align = (reorder->right_column->button->allocation.x +
9308                                          reorder->right_column->button->allocation.width +
9309                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
9310         }
9311       else
9312         {
9313           gint width;
9314
9315           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9316           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9317         }
9318     }
9319 }
9320
9321 void
9322 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9323                                   GtkTreeViewColumn *column)
9324 {
9325   GdkEvent *send_event;
9326   GtkAllocation allocation;
9327   gint x, y, width, height;
9328   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9329   GdkDisplay *display = gdk_screen_get_display (screen);
9330
9331   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9332   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9333
9334   gtk_tree_view_set_column_drag_info (tree_view, column);
9335
9336   if (tree_view->priv->column_drag_info == NULL)
9337     return;
9338
9339   if (tree_view->priv->drag_window == NULL)
9340     {
9341       GdkWindowAttr attributes;
9342       guint attributes_mask;
9343
9344       attributes.window_type = GDK_WINDOW_CHILD;
9345       attributes.wclass = GDK_INPUT_OUTPUT;
9346       attributes.x = column->button->allocation.x;
9347       attributes.y = 0;
9348       attributes.width = column->button->allocation.width;
9349       attributes.height = column->button->allocation.height;
9350       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9351       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
9352       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9353       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
9354
9355       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9356                                                      &attributes,
9357                                                      attributes_mask);
9358       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9359     }
9360
9361   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9362   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9363
9364   gtk_grab_remove (column->button);
9365
9366   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9367   send_event->crossing.send_event = TRUE;
9368   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9369   send_event->crossing.subwindow = NULL;
9370   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9371   send_event->crossing.time = GDK_CURRENT_TIME;
9372
9373   gtk_propagate_event (column->button, send_event);
9374   gdk_event_free (send_event);
9375
9376   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9377   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9378   send_event->button.send_event = TRUE;
9379   send_event->button.time = GDK_CURRENT_TIME;
9380   send_event->button.x = -1;
9381   send_event->button.y = -1;
9382   send_event->button.axes = NULL;
9383   send_event->button.state = 0;
9384   send_event->button.button = 1;
9385   send_event->button.device = gdk_display_get_core_pointer (display);
9386   send_event->button.x_root = 0;
9387   send_event->button.y_root = 0;
9388
9389   gtk_propagate_event (column->button, send_event);
9390   gdk_event_free (send_event);
9391
9392   /* Kids, don't try this at home */
9393   g_object_ref (column->button);
9394   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9395   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9396   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9397   g_object_unref (column->button);
9398
9399   tree_view->priv->drag_column_x = column->button->allocation.x;
9400   allocation = column->button->allocation;
9401   allocation.x = 0;
9402   gtk_widget_size_allocate (column->button, &allocation);
9403   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9404
9405   tree_view->priv->drag_column = column;
9406   gdk_window_show (tree_view->priv->drag_window);
9407
9408   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9409   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9410
9411   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9412   while (gtk_events_pending ())
9413     gtk_main_iteration ();
9414
9415   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9416   gdk_pointer_grab (tree_view->priv->drag_window,
9417                     FALSE,
9418                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9419                     NULL, NULL, GDK_CURRENT_TIME);
9420   gdk_keyboard_grab (tree_view->priv->drag_window,
9421                      FALSE,
9422                      GDK_CURRENT_TIME);
9423 }
9424
9425 static void
9426 gtk_tree_view_queue_draw_arrow (GtkTreeView      *tree_view,
9427                                 GtkRBTree        *tree,
9428                                 GtkRBNode        *node,
9429                                 GdkRectangle     *clip_rect)
9430 {
9431   GdkRectangle rect;
9432
9433   if (!GTK_WIDGET_REALIZED (tree_view))
9434     return;
9435
9436   rect.x = 0;
9437   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
9438
9439   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9440   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9441
9442   if (clip_rect)
9443     {
9444       GdkRectangle new_rect;
9445
9446       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9447
9448       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9449     }
9450   else
9451     {
9452       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9453     }
9454 }
9455
9456 void
9457 _gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
9458                                 GtkRBTree    *tree,
9459                                 GtkRBNode    *node,
9460                                 GdkRectangle *clip_rect)
9461 {
9462   GdkRectangle rect;
9463
9464   if (!GTK_WIDGET_REALIZED (tree_view))
9465     return;
9466
9467   rect.x = 0;
9468   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
9469
9470   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9471   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9472
9473   if (clip_rect)
9474     {
9475       GdkRectangle new_rect;
9476
9477       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9478
9479       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9480     }
9481   else
9482     {
9483       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9484     }
9485 }
9486
9487 static void
9488 gtk_tree_view_queue_draw_path (GtkTreeView      *tree_view,
9489                                GtkTreePath      *path,
9490                                GdkRectangle     *clip_rect)
9491 {
9492   GtkRBTree *tree = NULL;
9493   GtkRBNode *node = NULL;
9494
9495   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9496
9497   if (tree)
9498     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9499 }
9500
9501 /* x and y are the mouse position
9502  */
9503 static void
9504 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9505                           GtkRBTree   *tree,
9506                           GtkRBNode   *node,
9507                           /* in bin_window coordinates */
9508                           gint         x,
9509                           gint         y)
9510 {
9511   GdkRectangle area;
9512   GtkStateType state;
9513   GtkWidget *widget;
9514   gint x_offset = 0;
9515   gint x2;
9516   gint vertical_separator;
9517   gint expander_size;
9518   GtkExpanderStyle expander_style;
9519
9520   gtk_widget_style_get (GTK_WIDGET (tree_view),
9521                         "vertical-separator", &vertical_separator,
9522                         NULL);
9523   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9524
9525   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9526     return;
9527
9528   widget = GTK_WIDGET (tree_view);
9529
9530   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9531
9532   area.x = x_offset;
9533   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9534   area.width = expander_size + 2;
9535   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9536
9537   if (GTK_WIDGET_STATE (tree_view) == GTK_STATE_INSENSITIVE)
9538     {
9539       state = GTK_STATE_INSENSITIVE;
9540     }
9541   else if (node == tree_view->priv->button_pressed_node)
9542     {
9543       if (x >= area.x && x <= (area.x + area.width) &&
9544           y >= area.y && y <= (area.y + area.height))
9545         state = GTK_STATE_ACTIVE;
9546       else
9547         state = GTK_STATE_NORMAL;
9548     }
9549   else
9550     {
9551       if (node == tree_view->priv->prelight_node &&
9552           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9553         state = GTK_STATE_PRELIGHT;
9554       else
9555         state = GTK_STATE_NORMAL;
9556     }
9557
9558   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9559     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9560   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9561     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9562   else if (node->children != NULL)
9563     expander_style = GTK_EXPANDER_EXPANDED;
9564   else
9565     expander_style = GTK_EXPANDER_COLLAPSED;
9566
9567   gtk_paint_expander (widget->style,
9568                       tree_view->priv->bin_window,
9569                       state,
9570                       &area,
9571                       widget,
9572                       "treeview",
9573                       area.x + area.width / 2,
9574                       area.y + area.height / 2,
9575                       expander_style);
9576 }
9577
9578 static void
9579 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9580
9581 {
9582   GtkTreePath *cursor_path;
9583
9584   if ((tree_view->priv->tree == NULL) ||
9585       (! GTK_WIDGET_REALIZED (tree_view)))
9586     return;
9587
9588   cursor_path = NULL;
9589   if (tree_view->priv->cursor)
9590     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9591
9592   if (cursor_path == NULL)
9593     {
9594       /* Consult the selection before defaulting to the
9595        * first focusable element
9596        */
9597       GList *selected_rows;
9598       GtkTreeModel *model;
9599       GtkTreeSelection *selection;
9600
9601       selection = gtk_tree_view_get_selection (tree_view);
9602       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9603
9604       if (selected_rows)
9605         {
9606           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9607           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9608           g_list_free (selected_rows);
9609         }
9610       else
9611         {
9612           cursor_path = gtk_tree_path_new_first ();
9613           search_first_focusable_path (tree_view, &cursor_path,
9614                                        TRUE, NULL, NULL);
9615         }
9616
9617       gtk_tree_row_reference_free (tree_view->priv->cursor);
9618       tree_view->priv->cursor = NULL;
9619
9620       if (cursor_path)
9621         {
9622           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9623             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9624           else
9625             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9626         }
9627     }
9628
9629   if (cursor_path)
9630     {
9631       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9632
9633       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9634       gtk_tree_path_free (cursor_path);
9635
9636       if (tree_view->priv->focus_column == NULL)
9637         {
9638           GList *list;
9639           for (list = tree_view->priv->columns; list; list = list->next)
9640             {
9641               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9642                 {
9643                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9644                   break;
9645                 }
9646             }
9647         }
9648     }
9649 }
9650
9651 static void
9652 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9653                                    gint         count)
9654 {
9655   gint selection_count;
9656   GtkRBTree *cursor_tree = NULL;
9657   GtkRBNode *cursor_node = NULL;
9658   GtkRBTree *new_cursor_tree = NULL;
9659   GtkRBNode *new_cursor_node = NULL;
9660   GtkTreePath *cursor_path = NULL;
9661   gboolean grab_focus = TRUE;
9662   gboolean selectable;
9663
9664   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9665     return;
9666
9667   cursor_path = NULL;
9668   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9669     /* FIXME: we lost the cursor; should we get the first? */
9670     return;
9671
9672   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9673   _gtk_tree_view_find_node (tree_view, cursor_path,
9674                             &cursor_tree, &cursor_node);
9675
9676   if (cursor_tree == NULL)
9677     /* FIXME: we lost the cursor; should we get the first? */
9678     return;
9679
9680   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9681   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9682                                                       cursor_node,
9683                                                       cursor_path);
9684
9685   if (selection_count == 0
9686       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9687       && !tree_view->priv->ctrl_pressed
9688       && selectable)
9689     {
9690       /* Don't move the cursor, but just select the current node */
9691       new_cursor_tree = cursor_tree;
9692       new_cursor_node = cursor_node;
9693     }
9694   else
9695     {
9696       if (count == -1)
9697         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9698                                &new_cursor_tree, &new_cursor_node);
9699       else
9700         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9701                                &new_cursor_tree, &new_cursor_node);
9702     }
9703
9704   gtk_tree_path_free (cursor_path);
9705
9706   if (new_cursor_node)
9707     {
9708       cursor_path = _gtk_tree_view_find_path (tree_view,
9709                                               new_cursor_tree, new_cursor_node);
9710
9711       search_first_focusable_path (tree_view, &cursor_path,
9712                                    (count != -1),
9713                                    &new_cursor_tree,
9714                                    &new_cursor_node);
9715
9716       if (cursor_path)
9717         gtk_tree_path_free (cursor_path);
9718     }
9719
9720   /*
9721    * If the list has only one item and multi-selection is set then select
9722    * the row (if not yet selected).
9723    */
9724   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9725       new_cursor_node == NULL)
9726     {
9727       if (count == -1)
9728         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9729                                &new_cursor_tree, &new_cursor_node);
9730       else
9731         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9732                                &new_cursor_tree, &new_cursor_node);
9733
9734       if (new_cursor_node == NULL
9735           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9736         {
9737           new_cursor_node = cursor_node;
9738           new_cursor_tree = cursor_tree;
9739         }
9740       else
9741         {
9742           new_cursor_node = NULL;
9743         }
9744     }
9745
9746   if (new_cursor_node)
9747     {
9748       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9749       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9750       gtk_tree_path_free (cursor_path);
9751     }
9752   else
9753     {
9754       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9755
9756       if (!tree_view->priv->shift_pressed)
9757         {
9758           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9759                                           count < 0 ?
9760                                           GTK_DIR_UP : GTK_DIR_DOWN))
9761             {
9762               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9763
9764               if (toplevel)
9765                 gtk_widget_child_focus (toplevel,
9766                                         count < 0 ?
9767                                         GTK_DIR_TAB_BACKWARD :
9768                                         GTK_DIR_TAB_FORWARD);
9769
9770               grab_focus = FALSE;
9771             }
9772         }
9773       else
9774         {
9775           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9776         }
9777     }
9778
9779   if (grab_focus)
9780     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9781 }
9782
9783 static void
9784 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9785                                         gint         count)
9786 {
9787   GtkRBTree *cursor_tree = NULL;
9788   GtkRBNode *cursor_node = NULL;
9789   GtkTreePath *old_cursor_path = NULL;
9790   GtkTreePath *cursor_path = NULL;
9791   GtkRBTree *start_cursor_tree = NULL;
9792   GtkRBNode *start_cursor_node = NULL;
9793   gint y;
9794   gint window_y;
9795   gint vertical_separator;
9796
9797   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9798     return;
9799
9800   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9801     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9802   else
9803     /* This is sorta weird.  Focus in should give us a cursor */
9804     return;
9805
9806   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9807   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9808                             &cursor_tree, &cursor_node);
9809
9810   if (cursor_tree == NULL)
9811     {
9812       /* FIXME: we lost the cursor.  Should we try to get one? */
9813       gtk_tree_path_free (old_cursor_path);
9814       return;
9815     }
9816   g_return_if_fail (cursor_node != NULL);
9817
9818   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9819   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9820   y += tree_view->priv->cursor_offset;
9821   y += count * (int)tree_view->priv->vadjustment->page_increment;
9822   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9823
9824   if (y >= tree_view->priv->height)
9825     y = tree_view->priv->height - 1;
9826
9827   tree_view->priv->cursor_offset =
9828     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9829                              &cursor_tree, &cursor_node);
9830
9831   if (tree_view->priv->cursor_offset >= BACKGROUND_HEIGHT (cursor_node))
9832     {
9833       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9834                              &cursor_tree, &cursor_node);
9835       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9836     }
9837
9838   y -= tree_view->priv->cursor_offset;
9839   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9840
9841   start_cursor_tree = cursor_tree;
9842   start_cursor_node = cursor_node;
9843
9844   if (! search_first_focusable_path (tree_view, &cursor_path,
9845                                      (count != -1),
9846                                      &cursor_tree, &cursor_node))
9847     {
9848       /* It looks like we reached the end of the view without finding
9849        * a focusable row.  We will step backwards to find the last
9850        * focusable row.
9851        */
9852       cursor_tree = start_cursor_tree;
9853       cursor_node = start_cursor_node;
9854       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9855
9856       search_first_focusable_path (tree_view, &cursor_path,
9857                                    (count == -1),
9858                                    &cursor_tree, &cursor_node);
9859     }
9860
9861   if (!cursor_path)
9862     goto cleanup;
9863
9864   /* update y */
9865   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9866
9867   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9868
9869   y -= window_y;
9870   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9871   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9872   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9873
9874   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9875     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9876
9877 cleanup:
9878   gtk_tree_path_free (old_cursor_path);
9879   gtk_tree_path_free (cursor_path);
9880 }
9881
9882 static void
9883 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9884                                       gint         count)
9885 {
9886   GtkRBTree *cursor_tree = NULL;
9887   GtkRBNode *cursor_node = NULL;
9888   GtkTreePath *cursor_path = NULL;
9889   GtkTreeViewColumn *column;
9890   GtkTreeIter iter;
9891   GList *list;
9892   gboolean found_column = FALSE;
9893   gboolean rtl;
9894
9895   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9896
9897   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9898     return;
9899
9900   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9901     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9902   else
9903     return;
9904
9905   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9906   if (cursor_tree == NULL)
9907     return;
9908   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9909     {
9910       gtk_tree_path_free (cursor_path);
9911       return;
9912     }
9913   gtk_tree_path_free (cursor_path);
9914
9915   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9916   if (tree_view->priv->focus_column)
9917     {
9918       for (; list; list = (rtl ? list->prev : list->next))
9919         {
9920           if (list->data == tree_view->priv->focus_column)
9921             break;
9922         }
9923     }
9924
9925   while (list)
9926     {
9927       gboolean left, right;
9928
9929       column = list->data;
9930       if (column->visible == FALSE)
9931         goto loop_end;
9932
9933       gtk_tree_view_column_cell_set_cell_data (column,
9934                                                tree_view->priv->model,
9935                                                &iter,
9936                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9937                                                cursor_node->children?TRUE:FALSE);
9938
9939       if (rtl)
9940         {
9941           right = list->prev ? TRUE : FALSE;
9942           left = list->next ? TRUE : FALSE;
9943         }
9944       else
9945         {
9946           left = list->prev ? TRUE : FALSE;
9947           right = list->next ? TRUE : FALSE;
9948         }
9949
9950       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9951         {
9952           tree_view->priv->focus_column = column;
9953           found_column = TRUE;
9954           break;
9955         }
9956     loop_end:
9957       if (count == 1)
9958         list = rtl ? list->prev : list->next;
9959       else
9960         list = rtl ? list->next : list->prev;
9961     }
9962
9963   if (found_column)
9964     {
9965       if (!gtk_tree_view_has_special_cell (tree_view))
9966         _gtk_tree_view_queue_draw_node (tree_view,
9967                                         cursor_tree,
9968                                         cursor_node,
9969                                         NULL);
9970       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9971     }
9972   else
9973     {
9974       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9975     }
9976
9977   gtk_tree_view_clamp_column_visible (tree_view,
9978                                       tree_view->priv->focus_column, TRUE);
9979 }
9980
9981 static void
9982 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9983                                      gint         count)
9984 {
9985   GtkRBTree *cursor_tree;
9986   GtkRBNode *cursor_node;
9987   GtkTreePath *path;
9988   GtkTreePath *old_path;
9989
9990   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9991     return;
9992
9993   g_return_if_fail (tree_view->priv->tree != NULL);
9994
9995   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9996
9997   cursor_tree = tree_view->priv->tree;
9998   cursor_node = cursor_tree->root;
9999
10000   if (count == -1)
10001     {
10002       while (cursor_node && cursor_node->left != cursor_tree->nil)
10003         cursor_node = cursor_node->left;
10004
10005       /* Now go forward to find the first focusable row. */
10006       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10007       search_first_focusable_path (tree_view, &path,
10008                                    TRUE, &cursor_tree, &cursor_node);
10009     }
10010   else
10011     {
10012       do
10013         {
10014           while (cursor_node && cursor_node->right != cursor_tree->nil)
10015             cursor_node = cursor_node->right;
10016           if (cursor_node->children == NULL)
10017             break;
10018
10019           cursor_tree = cursor_node->children;
10020           cursor_node = cursor_tree->root;
10021         }
10022       while (1);
10023
10024       /* Now go backwards to find last focusable row. */
10025       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10026       search_first_focusable_path (tree_view, &path,
10027                                    FALSE, &cursor_tree, &cursor_node);
10028     }
10029
10030   if (!path)
10031     goto cleanup;
10032
10033   if (gtk_tree_path_compare (old_path, path))
10034     {
10035       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10036     }
10037   else
10038     {
10039       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10040     }
10041
10042 cleanup:
10043   gtk_tree_path_free (old_path);
10044   gtk_tree_path_free (path);
10045 }
10046
10047 static gboolean
10048 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10049 {
10050   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10051     return FALSE;
10052
10053   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10054     return FALSE;
10055
10056   gtk_tree_selection_select_all (tree_view->priv->selection);
10057
10058   return TRUE;
10059 }
10060
10061 static gboolean
10062 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10063 {
10064   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10065     return FALSE;
10066
10067   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10068     return FALSE;
10069
10070   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10071
10072   return TRUE;
10073 }
10074
10075 static gboolean
10076 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10077                                       gboolean     start_editing)
10078 {
10079   GtkRBTree *cursor_tree = NULL;
10080   GtkRBNode *cursor_node = NULL;
10081   GtkTreePath *cursor_path = NULL;
10082   GtkTreeSelectMode mode = 0;
10083
10084   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10085     return FALSE;
10086
10087   if (tree_view->priv->cursor)
10088     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10089
10090   if (cursor_path == NULL)
10091     return FALSE;
10092
10093   _gtk_tree_view_find_node (tree_view, cursor_path,
10094                             &cursor_tree, &cursor_node);
10095
10096   if (cursor_tree == NULL)
10097     {
10098       gtk_tree_path_free (cursor_path);
10099       return FALSE;
10100     }
10101
10102   if (!tree_view->priv->shift_pressed && start_editing &&
10103       tree_view->priv->focus_column)
10104     {
10105       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10106         {
10107           gtk_tree_path_free (cursor_path);
10108           return TRUE;
10109         }
10110     }
10111
10112   if (tree_view->priv->ctrl_pressed)
10113     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10114   if (tree_view->priv->shift_pressed)
10115     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10116
10117   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10118                                             cursor_node,
10119                                             cursor_tree,
10120                                             cursor_path,
10121                                             mode,
10122                                             FALSE);
10123
10124   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10125
10126   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10127   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10128
10129   if (!tree_view->priv->shift_pressed)
10130     gtk_tree_view_row_activated (tree_view, cursor_path,
10131                                  tree_view->priv->focus_column);
10132     
10133   gtk_tree_path_free (cursor_path);
10134
10135   return TRUE;
10136 }
10137
10138 static gboolean
10139 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10140 {
10141   GtkRBTree *cursor_tree = NULL;
10142   GtkRBNode *cursor_node = NULL;
10143   GtkTreePath *cursor_path = NULL;
10144
10145   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10146     return FALSE;
10147
10148   cursor_path = NULL;
10149   if (tree_view->priv->cursor)
10150     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10151
10152   if (cursor_path == NULL)
10153     return FALSE;
10154
10155   _gtk_tree_view_find_node (tree_view, cursor_path,
10156                             &cursor_tree, &cursor_node);
10157   if (cursor_tree == NULL)
10158     {
10159       gtk_tree_path_free (cursor_path);
10160       return FALSE;
10161     }
10162
10163   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10164                                             cursor_node,
10165                                             cursor_tree,
10166                                             cursor_path,
10167                                             GTK_TREE_SELECT_MODE_TOGGLE,
10168                                             FALSE);
10169
10170   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10171
10172   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10173   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10174   gtk_tree_path_free (cursor_path);
10175
10176   return TRUE;
10177 }
10178
10179 static gboolean
10180 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10181                                                gboolean     logical,
10182                                                gboolean     expand,
10183                                                gboolean     open_all)
10184 {
10185   GtkTreePath *cursor_path = NULL;
10186   GtkRBTree *tree;
10187   GtkRBNode *node;
10188
10189   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10190     return FALSE;
10191
10192   cursor_path = NULL;
10193   if (tree_view->priv->cursor)
10194     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10195
10196   if (cursor_path == NULL)
10197     return FALSE;
10198
10199   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10200     return FALSE;
10201
10202   /* Don't handle the event if we aren't an expander */
10203   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10204     return FALSE;
10205
10206   if (!logical
10207       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10208     expand = !expand;
10209
10210   if (expand)
10211     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10212   else
10213     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10214
10215   gtk_tree_path_free (cursor_path);
10216
10217   return TRUE;
10218 }
10219
10220 static gboolean
10221 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10222 {
10223   GtkRBTree *cursor_tree = NULL;
10224   GtkRBNode *cursor_node = NULL;
10225   GtkTreePath *cursor_path = NULL;
10226   GdkModifierType state;
10227
10228   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10229     return FALSE;
10230
10231   cursor_path = NULL;
10232   if (tree_view->priv->cursor)
10233     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10234
10235   if (cursor_path == NULL)
10236     return FALSE;
10237
10238   _gtk_tree_view_find_node (tree_view, cursor_path,
10239                             &cursor_tree, &cursor_node);
10240   if (cursor_tree == NULL)
10241     {
10242       gtk_tree_path_free (cursor_path);
10243       return FALSE;
10244     }
10245
10246   if (gtk_get_current_event_state (&state))
10247     {
10248       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10249         tree_view->priv->ctrl_pressed = TRUE;
10250     }
10251
10252   if (cursor_tree->parent_node)
10253     {
10254       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10255       cursor_node = cursor_tree->parent_node;
10256       cursor_tree = cursor_tree->parent_tree;
10257
10258       gtk_tree_path_up (cursor_path);
10259
10260       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10261     }
10262
10263   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10264
10265   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10266   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10267   gtk_tree_path_free (cursor_path);
10268
10269   tree_view->priv->ctrl_pressed = FALSE;
10270
10271   return TRUE;
10272 }
10273 static gboolean
10274 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10275 {
10276   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
10277   tree_view->priv->typeselect_flush_timeout = 0;
10278
10279   return FALSE;
10280 }
10281
10282 /* Cut and paste from gtkwindow.c */
10283 static void
10284 send_focus_change (GtkWidget *widget,
10285                    gboolean   in)
10286 {
10287   GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10288
10289   g_object_ref (widget);
10290    
10291  if (in)
10292     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
10293   else
10294     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
10295
10296   fevent->focus_change.type = GDK_FOCUS_CHANGE;
10297   fevent->focus_change.window = g_object_ref (widget->window);
10298   fevent->focus_change.in = in;
10299   
10300   gtk_widget_event (widget, fevent);
10301   
10302   g_object_notify (G_OBJECT (widget), "has-focus");
10303
10304   g_object_unref (widget);
10305   gdk_event_free (fevent);
10306 }
10307
10308 static void
10309 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10310 {
10311   GtkWidget *frame, *vbox, *toplevel;
10312
10313   if (tree_view->priv->search_custom_entry_set)
10314     return;
10315
10316   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10317
10318    if (tree_view->priv->search_window != NULL)
10319      {
10320        if (GTK_WINDOW (toplevel)->group)
10321          gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10322                                       GTK_WINDOW (tree_view->priv->search_window));
10323        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
10324          gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
10325                                          GTK_WINDOW (tree_view->priv->search_window));
10326        return;
10327      }
10328    
10329   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10330
10331   if (GTK_WINDOW (toplevel)->group)
10332     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10333                                  GTK_WINDOW (tree_view->priv->search_window));
10334
10335   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10336   g_signal_connect (tree_view->priv->search_window, "delete_event",
10337                     G_CALLBACK (gtk_tree_view_search_delete_event),
10338                     tree_view);
10339   g_signal_connect (tree_view->priv->search_window, "key_press_event",
10340                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10341                     tree_view);
10342   g_signal_connect (tree_view->priv->search_window, "button_press_event",
10343                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10344                     tree_view);
10345   g_signal_connect (tree_view->priv->search_window, "scroll_event",
10346                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10347                     tree_view);
10348
10349   frame = gtk_frame_new (NULL);
10350   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10351   gtk_widget_show (frame);
10352   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10353
10354   vbox = gtk_vbox_new (FALSE, 0);
10355   gtk_widget_show (vbox);
10356   gtk_container_add (GTK_CONTAINER (frame), vbox);
10357   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10358
10359   /* add entry */
10360   tree_view->priv->search_entry = gtk_entry_new ();
10361   gtk_widget_show (tree_view->priv->search_entry);
10362   g_signal_connect (tree_view->priv->search_entry, "populate_popup",
10363                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10364                     tree_view);
10365   g_signal_connect (tree_view->priv->search_entry,
10366                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10367                     tree_view);
10368   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10369                     "preedit_changed",
10370                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10371                     tree_view);
10372   gtk_container_add (GTK_CONTAINER (vbox),
10373                      tree_view->priv->search_entry);
10374
10375   gtk_widget_realize (tree_view->priv->search_entry);
10376 }
10377
10378 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10379  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10380  */
10381 static gboolean
10382 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10383                                              gboolean     keybinding)
10384 {
10385   /* We only start interactive search if we have focus or the columns
10386    * have focus.  If one of our children have focus, we don't want to
10387    * start the search.
10388    */
10389   GList *list;
10390   gboolean found_focus = FALSE;
10391   GtkWidgetClass *entry_parent_class;
10392   
10393   if (!tree_view->priv->enable_search && !keybinding)
10394     return FALSE;
10395
10396   if (tree_view->priv->search_custom_entry_set)
10397     return FALSE;
10398
10399   if (tree_view->priv->search_window != NULL &&
10400       GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
10401     return TRUE;
10402
10403   for (list = tree_view->priv->columns; list; list = list->next)
10404     {
10405       GtkTreeViewColumn *column;
10406
10407       column = list->data;
10408       if (! column->visible)
10409         continue;
10410
10411       if (GTK_WIDGET_HAS_FOCUS (column->button))
10412         {
10413           found_focus = TRUE;
10414           break;
10415         }
10416     }
10417   
10418   if (GTK_WIDGET_HAS_FOCUS (tree_view))
10419     found_focus = TRUE;
10420
10421   if (!found_focus)
10422     return FALSE;
10423
10424   if (tree_view->priv->search_column < 0)
10425     return FALSE;
10426
10427   gtk_tree_view_ensure_interactive_directory (tree_view);
10428
10429   if (keybinding)
10430     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10431
10432   /* done, show it */
10433   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10434   gtk_widget_show (tree_view->priv->search_window);
10435   if (tree_view->priv->search_entry_changed_id == 0)
10436     {
10437       tree_view->priv->search_entry_changed_id =
10438         g_signal_connect (tree_view->priv->search_entry, "changed",
10439                           G_CALLBACK (gtk_tree_view_search_init),
10440                           tree_view);
10441     }
10442
10443   tree_view->priv->typeselect_flush_timeout =
10444     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10445                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10446                    tree_view);
10447
10448   /* Grab focus will select all the text.  We don't want that to happen, so we
10449    * call the parent instance and bypass the selection change.  This is probably
10450    * really non-kosher. */
10451   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10452   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10453
10454   /* send focus-in event */
10455   send_focus_change (tree_view->priv->search_entry, TRUE);
10456
10457   /* search first matching iter */
10458   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10459
10460   return TRUE;
10461 }
10462
10463 static gboolean
10464 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10465 {
10466   return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
10467 }
10468
10469 /* this function returns the new width of the column being resized given
10470  * the column and x position of the cursor; the x cursor position is passed
10471  * in as a pointer and automagicly corrected if it's beyond min/max limits
10472  */
10473 static gint
10474 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10475                                 gint       i,
10476                                 gint      *x)
10477 {
10478   GtkTreeViewColumn *column;
10479   gint width;
10480   gboolean rtl;
10481
10482   /* first translate the x position from widget->window
10483    * to clist->clist_window
10484    */
10485   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10486   column = g_list_nth (tree_view->priv->columns, i)->data;
10487   width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
10488  
10489   /* Clamp down the value */
10490   if (column->min_width == -1)
10491     width = MAX (column->button->requisition.width,
10492                  width);
10493   else
10494     width = MAX (column->min_width,
10495                  width);
10496   if (column->max_width != -1)
10497     width = MIN (width, column->max_width);
10498
10499   *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
10500  
10501   return width;
10502 }
10503
10504
10505 /* FIXME this adjust_allocation is a big cut-and-paste from
10506  * GtkCList, needs to be some "official" way to do this
10507  * factored out.
10508  */
10509 typedef struct
10510 {
10511   GdkWindow *window;
10512   int dx;
10513   int dy;
10514 } ScrollData;
10515
10516 /* The window to which widget->window is relative */
10517 #define ALLOCATION_WINDOW(widget)               \
10518    (GTK_WIDGET_NO_WINDOW (widget) ?             \
10519     (widget)->window :                          \
10520      gdk_window_get_parent ((widget)->window))
10521
10522 static void
10523 adjust_allocation_recurse (GtkWidget *widget,
10524                            gpointer   data)
10525 {
10526   ScrollData *scroll_data = data;
10527
10528   /* Need to really size allocate instead of just poking
10529    * into widget->allocation if the widget is not realized.
10530    * FIXME someone figure out why this was.
10531    */
10532   if (!GTK_WIDGET_REALIZED (widget))
10533     {
10534       if (GTK_WIDGET_VISIBLE (widget))
10535         {
10536           GdkRectangle tmp_rectangle = widget->allocation;
10537           tmp_rectangle.x += scroll_data->dx;
10538           tmp_rectangle.y += scroll_data->dy;
10539           
10540           gtk_widget_size_allocate (widget, &tmp_rectangle);
10541         }
10542     }
10543   else
10544     {
10545       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10546         {
10547           widget->allocation.x += scroll_data->dx;
10548           widget->allocation.y += scroll_data->dy;
10549           
10550           if (GTK_IS_CONTAINER (widget))
10551             gtk_container_forall (GTK_CONTAINER (widget),
10552                                   adjust_allocation_recurse,
10553                                   data);
10554         }
10555     }
10556 }
10557
10558 static void
10559 adjust_allocation (GtkWidget *widget,
10560                    int        dx,
10561                    int        dy)
10562 {
10563   ScrollData scroll_data;
10564
10565   if (GTK_WIDGET_REALIZED (widget))
10566     scroll_data.window = ALLOCATION_WINDOW (widget);
10567   else
10568     scroll_data.window = NULL;
10569     
10570   scroll_data.dx = dx;
10571   scroll_data.dy = dy;
10572   
10573   adjust_allocation_recurse (widget, &scroll_data);
10574 }
10575
10576 /* Callbacks */
10577 static void
10578 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10579                                   GtkTreeView   *tree_view)
10580 {
10581   if (GTK_WIDGET_REALIZED (tree_view))
10582     {
10583       gint dy;
10584         
10585       gdk_window_move (tree_view->priv->bin_window,
10586                        - tree_view->priv->hadjustment->value,
10587                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10588       gdk_window_move (tree_view->priv->header_window,
10589                        - tree_view->priv->hadjustment->value,
10590                        0);
10591       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10592       if (dy && tree_view->priv->edited_column)
10593         {
10594           if (GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10595             {
10596               GList *list;
10597               GtkWidget *widget;
10598               GtkTreeViewChild *child = NULL;
10599
10600               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10601               adjust_allocation (widget, 0, dy); 
10602               
10603               for (list = tree_view->priv->children; list; list = list->next)
10604                 {
10605                   child = (GtkTreeViewChild *)list->data;
10606                   if (child->widget == widget)
10607                     {
10608                       child->y += dy;
10609                       break;
10610                     }
10611                 }
10612             }
10613         }
10614       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10615
10616       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10617         {
10618           /* update our dy and top_row */
10619           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10620
10621           if (!tree_view->priv->in_top_row_to_dy)
10622             gtk_tree_view_dy_to_top_row (tree_view);
10623         }
10624     }
10625 }
10626
10627 \f
10628
10629 /* Public methods
10630  */
10631
10632 /**
10633  * gtk_tree_view_new:
10634  *
10635  * Creates a new #GtkTreeView widget.
10636  *
10637  * Return value: A newly created #GtkTreeView widget.
10638  **/
10639 GtkWidget *
10640 gtk_tree_view_new (void)
10641 {
10642   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10643 }
10644
10645 /**
10646  * gtk_tree_view_new_with_model:
10647  * @model: the model.
10648  *
10649  * Creates a new #GtkTreeView widget with the model initialized to @model.
10650  *
10651  * Return value: A newly created #GtkTreeView widget.
10652  **/
10653 GtkWidget *
10654 gtk_tree_view_new_with_model (GtkTreeModel *model)
10655 {
10656   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10657 }
10658
10659 /* Public Accessors
10660  */
10661
10662 /**
10663  * gtk_tree_view_get_model:
10664  * @tree_view: a #GtkTreeView
10665  *
10666  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10667  * model is unset.
10668  *
10669  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
10670  **/
10671 GtkTreeModel *
10672 gtk_tree_view_get_model (GtkTreeView *tree_view)
10673 {
10674   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10675
10676   return tree_view->priv->model;
10677 }
10678
10679 /**
10680  * gtk_tree_view_set_model:
10681  * @tree_view: A #GtkTreeNode.
10682  * @model: The model.
10683  *
10684  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10685  * set, it will remove it before setting the new model.  If @model is %NULL, 
10686  * then it will unset the old model.
10687  **/
10688 void
10689 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10690                          GtkTreeModel *model)
10691 {
10692   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10693
10694   if (model != NULL)
10695     g_return_if_fail (GTK_IS_TREE_MODEL (model));
10696
10697   if (model == tree_view->priv->model)
10698     return;
10699
10700   if (tree_view->priv->scroll_to_path)
10701     {
10702       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10703       tree_view->priv->scroll_to_path = NULL;
10704     }
10705
10706   if (tree_view->priv->model)
10707     {
10708       GList *tmplist = tree_view->priv->columns;
10709
10710       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10711       gtk_tree_view_stop_editing (tree_view, TRUE);
10712
10713       if (tree_view->priv->expand_collapse_timeout)
10714         {
10715           g_source_remove (tree_view->priv->expand_collapse_timeout);
10716           tree_view->priv->expand_collapse_timeout = 0;
10717         }
10718
10719       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10720                                             gtk_tree_view_row_changed,
10721                                             tree_view);
10722       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10723                                             gtk_tree_view_row_inserted,
10724                                             tree_view);
10725       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10726                                             gtk_tree_view_row_has_child_toggled,
10727                                             tree_view);
10728       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10729                                             gtk_tree_view_row_deleted,
10730                                             tree_view);
10731       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10732                                             gtk_tree_view_rows_reordered,
10733                                             tree_view);
10734
10735       for (; tmplist; tmplist = tmplist->next)
10736         _gtk_tree_view_column_unset_model (tmplist->data,
10737                                            tree_view->priv->model);
10738
10739       if (tree_view->priv->tree)
10740         gtk_tree_view_free_rbtree (tree_view);
10741
10742       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10743       tree_view->priv->drag_dest_row = NULL;
10744       gtk_tree_row_reference_free (tree_view->priv->cursor);
10745       tree_view->priv->cursor = NULL;
10746       gtk_tree_row_reference_free (tree_view->priv->anchor);
10747       tree_view->priv->anchor = NULL;
10748       gtk_tree_row_reference_free (tree_view->priv->top_row);
10749       tree_view->priv->top_row = NULL;
10750       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
10751       tree_view->priv->last_button_press = NULL;
10752       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
10753       tree_view->priv->last_button_press_2 = NULL;
10754       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10755       tree_view->priv->scroll_to_path = NULL;
10756
10757       tree_view->priv->scroll_to_column = NULL;
10758
10759       g_object_unref (tree_view->priv->model);
10760
10761       tree_view->priv->search_column = -1;
10762       tree_view->priv->fixed_height_check = 0;
10763       tree_view->priv->fixed_height = -1;
10764       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10765     }
10766
10767   tree_view->priv->model = model;
10768
10769   if (tree_view->priv->model)
10770     {
10771       gint i;
10772       GtkTreePath *path;
10773       GtkTreeIter iter;
10774       GtkTreeModelFlags flags;
10775
10776       if (tree_view->priv->search_column == -1)
10777         {
10778           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10779             {
10780               GType type = gtk_tree_model_get_column_type (model, i);
10781
10782               if (g_value_type_transformable (type, G_TYPE_STRING))
10783                 {
10784                   tree_view->priv->search_column = i;
10785                   break;
10786                 }
10787             }
10788         }
10789
10790       g_object_ref (tree_view->priv->model);
10791       g_signal_connect (tree_view->priv->model,
10792                         "row_changed",
10793                         G_CALLBACK (gtk_tree_view_row_changed),
10794                         tree_view);
10795       g_signal_connect (tree_view->priv->model,
10796                         "row_inserted",
10797                         G_CALLBACK (gtk_tree_view_row_inserted),
10798                         tree_view);
10799       g_signal_connect (tree_view->priv->model,
10800                         "row_has_child_toggled",
10801                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10802                         tree_view);
10803       g_signal_connect (tree_view->priv->model,
10804                         "row_deleted",
10805                         G_CALLBACK (gtk_tree_view_row_deleted),
10806                         tree_view);
10807       g_signal_connect (tree_view->priv->model,
10808                         "rows_reordered",
10809                         G_CALLBACK (gtk_tree_view_rows_reordered),
10810                         tree_view);
10811
10812       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10813       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10814         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10815       else
10816         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10817
10818       path = gtk_tree_path_new_first ();
10819       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10820         {
10821           tree_view->priv->tree = _gtk_rbtree_new ();
10822           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10823         }
10824       gtk_tree_path_free (path);
10825
10826       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10827       install_presize_handler (tree_view);
10828     }
10829
10830   g_object_notify (G_OBJECT (tree_view), "model");
10831
10832   if (tree_view->priv->selection)
10833   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10834
10835   if (GTK_WIDGET_REALIZED (tree_view))
10836     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10837 }
10838
10839 /**
10840  * gtk_tree_view_get_selection:
10841  * @tree_view: A #GtkTreeView.
10842  *
10843  * Gets the #GtkTreeSelection associated with @tree_view.
10844  *
10845  * Return value: A #GtkTreeSelection object.
10846  **/
10847 GtkTreeSelection *
10848 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10849 {
10850   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10851
10852   return tree_view->priv->selection;
10853 }
10854
10855 /**
10856  * gtk_tree_view_get_hadjustment:
10857  * @tree_view: A #GtkTreeView
10858  *
10859  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10860  *
10861  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10862  * used.
10863  **/
10864 GtkAdjustment *
10865 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10866 {
10867   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10868
10869   if (tree_view->priv->hadjustment == NULL)
10870     gtk_tree_view_set_hadjustment (tree_view, NULL);
10871
10872   return tree_view->priv->hadjustment;
10873 }
10874
10875 /**
10876  * gtk_tree_view_set_hadjustment:
10877  * @tree_view: A #GtkTreeView
10878  * @adjustment: The #GtkAdjustment to set, or %NULL
10879  *
10880  * Sets the #GtkAdjustment for the current horizontal aspect.
10881  **/
10882 void
10883 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10884                                GtkAdjustment *adjustment)
10885 {
10886   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10887
10888   gtk_tree_view_set_adjustments (tree_view,
10889                                  adjustment,
10890                                  tree_view->priv->vadjustment);
10891
10892   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10893 }
10894
10895 /**
10896  * gtk_tree_view_get_vadjustment:
10897  * @tree_view: A #GtkTreeView
10898  *
10899  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10900  *
10901  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10902  * used.
10903  **/
10904 GtkAdjustment *
10905 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10906 {
10907   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10908
10909   if (tree_view->priv->vadjustment == NULL)
10910     gtk_tree_view_set_vadjustment (tree_view, NULL);
10911
10912   return tree_view->priv->vadjustment;
10913 }
10914
10915 /**
10916  * gtk_tree_view_set_vadjustment:
10917  * @tree_view: A #GtkTreeView
10918  * @adjustment: The #GtkAdjustment to set, or %NULL
10919  *
10920  * Sets the #GtkAdjustment for the current vertical aspect.
10921  **/
10922 void
10923 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10924                                GtkAdjustment *adjustment)
10925 {
10926   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10927
10928   gtk_tree_view_set_adjustments (tree_view,
10929                                  tree_view->priv->hadjustment,
10930                                  adjustment);
10931
10932   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10933 }
10934
10935 /* Column and header operations */
10936
10937 /**
10938  * gtk_tree_view_get_headers_visible:
10939  * @tree_view: A #GtkTreeView.
10940  *
10941  * Returns %TRUE if the headers on the @tree_view are visible.
10942  *
10943  * Return value: Whether the headers are visible or not.
10944  **/
10945 gboolean
10946 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10947 {
10948   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10949
10950   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10951 }
10952
10953 /**
10954  * gtk_tree_view_set_headers_visible:
10955  * @tree_view: A #GtkTreeView.
10956  * @headers_visible: %TRUE if the headers are visible
10957  *
10958  * Sets the visibility state of the headers.
10959  **/
10960 void
10961 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
10962                                    gboolean     headers_visible)
10963 {
10964   gint x, y;
10965   GList *list;
10966   GtkTreeViewColumn *column;
10967
10968   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10969
10970   headers_visible = !! headers_visible;
10971
10972   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
10973     return;
10974
10975   if (headers_visible)
10976     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10977   else
10978     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10979
10980   if (GTK_WIDGET_REALIZED (tree_view))
10981     {
10982       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
10983       if (headers_visible)
10984         {
10985           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));
10986
10987           if (GTK_WIDGET_MAPPED (tree_view))
10988             gtk_tree_view_map_buttons (tree_view);
10989         }
10990       else
10991         {
10992           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
10993
10994           for (list = tree_view->priv->columns; list; list = list->next)
10995             {
10996               column = list->data;
10997               gtk_widget_unmap (column->button);
10998             }
10999           gdk_window_hide (tree_view->priv->header_window);
11000         }
11001     }
11002
11003   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11004   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11005   tree_view->priv->vadjustment->lower = 0;
11006   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11007   gtk_adjustment_changed (tree_view->priv->vadjustment);
11008
11009   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11010
11011   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11012 }
11013
11014 /**
11015  * gtk_tree_view_columns_autosize:
11016  * @tree_view: A #GtkTreeView.
11017  *
11018  * Resizes all columns to their optimal width. Only works after the
11019  * treeview has been realized.
11020  **/
11021 void
11022 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11023 {
11024   gboolean dirty = FALSE;
11025   GList *list;
11026   GtkTreeViewColumn *column;
11027
11028   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11029
11030   for (list = tree_view->priv->columns; list; list = list->next)
11031     {
11032       column = list->data;
11033       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11034         continue;
11035       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11036       dirty = TRUE;
11037     }
11038
11039   if (dirty)
11040     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11041 }
11042
11043 /**
11044  * gtk_tree_view_set_headers_clickable:
11045  * @tree_view: A #GtkTreeView.
11046  * @setting: %TRUE if the columns are clickable.
11047  *
11048  * Allow the column title buttons to be clicked.
11049  **/
11050 void
11051 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11052                                      gboolean   setting)
11053 {
11054   GList *list;
11055
11056   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11057
11058   for (list = tree_view->priv->columns; list; list = list->next)
11059     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11060
11061   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11062 }
11063
11064
11065 /**
11066  * gtk_tree_view_get_headers_clickable:
11067  * @tree_view: A #GtkTreeView.
11068  *
11069  * Returns whether all header columns are clickable.
11070  *
11071  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11072  *
11073  * Since: 2.10
11074  **/
11075 gboolean 
11076 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11077 {
11078   GList *list;
11079   
11080   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11081
11082   for (list = tree_view->priv->columns; list; list = list->next)
11083     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11084       return FALSE;
11085
11086   return TRUE;
11087 }
11088
11089 /**
11090  * gtk_tree_view_set_rules_hint
11091  * @tree_view: a #GtkTreeView
11092  * @setting: %TRUE if the tree requires reading across rows
11093  *
11094  * This function tells GTK+ that the user interface for your
11095  * application requires users to read across tree rows and associate
11096  * cells with one another. By default, GTK+ will then render the tree
11097  * with alternating row colors. Do <emphasis>not</emphasis> use it
11098  * just because you prefer the appearance of the ruled tree; that's a
11099  * question for the theme. Some themes will draw tree rows in
11100  * alternating colors even when rules are turned off, and users who
11101  * prefer that appearance all the time can choose those themes. You
11102  * should call this function only as a <emphasis>semantic</emphasis>
11103  * hint to the theme engine that your tree makes alternating colors
11104  * useful from a functional standpoint (since it has lots of columns,
11105  * generally).
11106  *
11107  **/
11108 void
11109 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11110                               gboolean      setting)
11111 {
11112   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11113
11114   setting = setting != FALSE;
11115
11116   if (tree_view->priv->has_rules != setting)
11117     {
11118       tree_view->priv->has_rules = setting;
11119       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11120     }
11121
11122   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11123 }
11124
11125 /**
11126  * gtk_tree_view_get_rules_hint
11127  * @tree_view: a #GtkTreeView
11128  *
11129  * Gets the setting set by gtk_tree_view_set_rules_hint().
11130  *
11131  * Return value: %TRUE if rules are useful for the user of this tree
11132  **/
11133 gboolean
11134 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11135 {
11136   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11137
11138   return tree_view->priv->has_rules;
11139 }
11140
11141 /* Public Column functions
11142  */
11143
11144 /**
11145  * gtk_tree_view_append_column:
11146  * @tree_view: A #GtkTreeView.
11147  * @column: The #GtkTreeViewColumn to add.
11148  *
11149  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11150  * mode enabled, then @column must have its "sizing" property set to be
11151  * GTK_TREE_VIEW_COLUMN_FIXED.
11152  *
11153  * Return value: The number of columns in @tree_view after appending.
11154  **/
11155 gint
11156 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11157                              GtkTreeViewColumn *column)
11158 {
11159   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11160   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11161   g_return_val_if_fail (column->tree_view == NULL, -1);
11162
11163   return gtk_tree_view_insert_column (tree_view, column, -1);
11164 }
11165
11166
11167 /**
11168  * gtk_tree_view_remove_column:
11169  * @tree_view: A #GtkTreeView.
11170  * @column: The #GtkTreeViewColumn to remove.
11171  *
11172  * Removes @column from @tree_view.
11173  *
11174  * Return value: The number of columns in @tree_view after removing.
11175  **/
11176 gint
11177 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11178                              GtkTreeViewColumn *column)
11179 {
11180   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11181   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11182   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11183
11184   if (tree_view->priv->focus_column == column)
11185     tree_view->priv->focus_column = NULL;
11186
11187   if (tree_view->priv->edited_column == column)
11188     {
11189       gtk_tree_view_stop_editing (tree_view, TRUE);
11190
11191       /* no need to, but just to be sure ... */
11192       tree_view->priv->edited_column = NULL;
11193     }
11194
11195   g_signal_handlers_disconnect_by_func (column,
11196                                         G_CALLBACK (column_sizing_notify),
11197                                         tree_view);
11198
11199   _gtk_tree_view_column_unset_tree_view (column);
11200
11201   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11202   tree_view->priv->n_columns--;
11203
11204   if (GTK_WIDGET_REALIZED (tree_view))
11205     {
11206       GList *list;
11207
11208       _gtk_tree_view_column_unrealize_button (column);
11209       for (list = tree_view->priv->columns; list; list = list->next)
11210         {
11211           GtkTreeViewColumn *tmp_column;
11212
11213           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11214           if (tmp_column->visible)
11215             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11216         }
11217
11218       if (tree_view->priv->n_columns == 0 &&
11219           gtk_tree_view_get_headers_visible (tree_view))
11220         gdk_window_hide (tree_view->priv->header_window);
11221
11222       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11223     }
11224
11225   g_object_unref (column);
11226   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11227
11228   return tree_view->priv->n_columns;
11229 }
11230
11231 /**
11232  * gtk_tree_view_insert_column:
11233  * @tree_view: A #GtkTreeView.
11234  * @column: The #GtkTreeViewColumn to be inserted.
11235  * @position: The position to insert @column in.
11236  *
11237  * This inserts the @column into the @tree_view at @position.  If @position is
11238  * -1, then the column is inserted at the end. If @tree_view has
11239  * "fixed_height" mode enabled, then @column must have its "sizing" property
11240  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11241  *
11242  * Return value: The number of columns in @tree_view after insertion.
11243  **/
11244 gint
11245 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11246                              GtkTreeViewColumn *column,
11247                              gint               position)
11248 {
11249   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11250   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11251   g_return_val_if_fail (column->tree_view == NULL, -1);
11252
11253   if (tree_view->priv->fixed_height_mode)
11254     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11255                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11256
11257   g_object_ref_sink (column);
11258
11259   if (tree_view->priv->n_columns == 0 &&
11260       GTK_WIDGET_REALIZED (tree_view) &&
11261       gtk_tree_view_get_headers_visible (tree_view))
11262     {
11263       gdk_window_show (tree_view->priv->header_window);
11264     }
11265
11266   g_signal_connect (column, "notify::sizing",
11267                     G_CALLBACK (column_sizing_notify), tree_view);
11268
11269   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11270                                             column, position);
11271   tree_view->priv->n_columns++;
11272
11273   _gtk_tree_view_column_set_tree_view (column, tree_view);
11274
11275   if (GTK_WIDGET_REALIZED (tree_view))
11276     {
11277       GList *list;
11278
11279       _gtk_tree_view_column_realize_button (column);
11280
11281       for (list = tree_view->priv->columns; list; list = list->next)
11282         {
11283           column = GTK_TREE_VIEW_COLUMN (list->data);
11284           if (column->visible)
11285             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11286         }
11287       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11288     }
11289
11290   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11291
11292   return tree_view->priv->n_columns;
11293 }
11294
11295 /**
11296  * gtk_tree_view_insert_column_with_attributes:
11297  * @tree_view: A #GtkTreeView
11298  * @position: The position to insert the new column in.
11299  * @title: The title to set the header to.
11300  * @cell: The #GtkCellRenderer.
11301  * @Varargs: A %NULL-terminated list of attributes.
11302  *
11303  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11304  * @position.  If @position is -1, then the newly created column is inserted at
11305  * the end.  The column is initialized with the attributes given. If @tree_view
11306  * has "fixed_height" mode enabled, then the new column will have its sizing
11307  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11308  *
11309  * Return value: The number of columns in @tree_view after insertion.
11310  **/
11311 gint
11312 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11313                                              gint             position,
11314                                              const gchar     *title,
11315                                              GtkCellRenderer *cell,
11316                                              ...)
11317 {
11318   GtkTreeViewColumn *column;
11319   gchar *attribute;
11320   va_list args;
11321   gint column_id;
11322
11323   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11324
11325   column = gtk_tree_view_column_new ();
11326   if (tree_view->priv->fixed_height_mode)
11327     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11328
11329   gtk_tree_view_column_set_title (column, title);
11330   gtk_tree_view_column_pack_start (column, cell, TRUE);
11331
11332   va_start (args, cell);
11333
11334   attribute = va_arg (args, gchar *);
11335
11336   while (attribute != NULL)
11337     {
11338       column_id = va_arg (args, gint);
11339       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11340       attribute = va_arg (args, gchar *);
11341     }
11342
11343   va_end (args);
11344
11345   gtk_tree_view_insert_column (tree_view, column, position);
11346
11347   return tree_view->priv->n_columns;
11348 }
11349
11350 /**
11351  * gtk_tree_view_insert_column_with_data_func:
11352  * @tree_view: a #GtkTreeView
11353  * @position: Position to insert, -1 for append
11354  * @title: column title
11355  * @cell: cell renderer for column
11356  * @func: function to set attributes of cell renderer
11357  * @data: data for @func
11358  * @dnotify: destroy notifier for @data
11359  *
11360  * Convenience function that inserts a new column into the #GtkTreeView
11361  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11362  * attributes (normally using data from the model). See also
11363  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11364  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11365  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11366  *
11367  * Return value: number of columns in the tree view post-insert
11368  **/
11369 gint
11370 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11371                                              gint                       position,
11372                                              const gchar               *title,
11373                                              GtkCellRenderer           *cell,
11374                                              GtkTreeCellDataFunc        func,
11375                                              gpointer                   data,
11376                                              GDestroyNotify             dnotify)
11377 {
11378   GtkTreeViewColumn *column;
11379
11380   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11381
11382   column = gtk_tree_view_column_new ();
11383   if (tree_view->priv->fixed_height_mode)
11384     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11385
11386   gtk_tree_view_column_set_title (column, title);
11387   gtk_tree_view_column_pack_start (column, cell, TRUE);
11388   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11389
11390   gtk_tree_view_insert_column (tree_view, column, position);
11391
11392   return tree_view->priv->n_columns;
11393 }
11394
11395 /**
11396  * gtk_tree_view_get_column:
11397  * @tree_view: A #GtkTreeView.
11398  * @n: The position of the column, counting from 0.
11399  *
11400  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11401  *
11402  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11403  * range of columns.
11404  **/
11405 GtkTreeViewColumn *
11406 gtk_tree_view_get_column (GtkTreeView *tree_view,
11407                           gint         n)
11408 {
11409   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11410
11411   if (n < 0 || n >= tree_view->priv->n_columns)
11412     return NULL;
11413
11414   if (tree_view->priv->columns == NULL)
11415     return NULL;
11416
11417   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11418 }
11419
11420 /**
11421  * gtk_tree_view_get_columns:
11422  * @tree_view: A #GtkTreeView
11423  *
11424  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11425  * The returned list must be freed with g_list_free ().
11426  *
11427  * Return value: A list of #GtkTreeViewColumn s
11428  **/
11429 GList *
11430 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11431 {
11432   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11433
11434   return g_list_copy (tree_view->priv->columns);
11435 }
11436
11437 /**
11438  * gtk_tree_view_move_column_after:
11439  * @tree_view: A #GtkTreeView
11440  * @column: The #GtkTreeViewColumn to be moved.
11441  * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
11442  *
11443  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11444  * @column is placed in the first position.
11445  **/
11446 void
11447 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11448                                  GtkTreeViewColumn *column,
11449                                  GtkTreeViewColumn *base_column)
11450 {
11451   GList *column_list_el, *base_el = NULL;
11452
11453   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11454
11455   column_list_el = g_list_find (tree_view->priv->columns, column);
11456   g_return_if_fail (column_list_el != NULL);
11457
11458   if (base_column)
11459     {
11460       base_el = g_list_find (tree_view->priv->columns, base_column);
11461       g_return_if_fail (base_el != NULL);
11462     }
11463
11464   if (column_list_el->prev == base_el)
11465     return;
11466
11467   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11468   if (base_el == NULL)
11469     {
11470       column_list_el->prev = NULL;
11471       column_list_el->next = tree_view->priv->columns;
11472       if (column_list_el->next)
11473         column_list_el->next->prev = column_list_el;
11474       tree_view->priv->columns = column_list_el;
11475     }
11476   else
11477     {
11478       column_list_el->prev = base_el;
11479       column_list_el->next = base_el->next;
11480       if (column_list_el->next)
11481         column_list_el->next->prev = column_list_el;
11482       base_el->next = column_list_el;
11483     }
11484
11485   if (GTK_WIDGET_REALIZED (tree_view))
11486     {
11487       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11488       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view));
11489     }
11490
11491   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11492 }
11493
11494 /**
11495  * gtk_tree_view_set_expander_column:
11496  * @tree_view: A #GtkTreeView
11497  * @column: %NULL, or the column to draw the expander arrow at.
11498  *
11499  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11500  * If @column is %NULL, then the expander arrow is always at the first 
11501  * visible column.
11502  *
11503  * If you do not want expander arrow to appear in your tree, set the 
11504  * expander column to a hidden column.
11505  **/
11506 void
11507 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11508                                    GtkTreeViewColumn *column)
11509 {
11510   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11511   if (column != NULL)
11512     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
11513
11514   if (tree_view->priv->expander_column != column)
11515     {
11516       GList *list;
11517
11518       if (column)
11519         {
11520           /* Confirm that column is in tree_view */
11521           for (list = tree_view->priv->columns; list; list = list->next)
11522             if (list->data == column)
11523               break;
11524           g_return_if_fail (list != NULL);
11525         }
11526
11527       tree_view->priv->expander_column = column;
11528       g_object_notify (G_OBJECT (tree_view), "expander-column");
11529     }
11530 }
11531
11532 /**
11533  * gtk_tree_view_get_expander_column:
11534  * @tree_view: A #GtkTreeView
11535  *
11536  * Returns the column that is the current expander column.  This
11537  * column has the expander arrow drawn next to it.
11538  *
11539  * Return value: The expander column.
11540  **/
11541 GtkTreeViewColumn *
11542 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11543 {
11544   GList *list;
11545
11546   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11547
11548   for (list = tree_view->priv->columns; list; list = list->next)
11549     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11550       return (GtkTreeViewColumn *) list->data;
11551   return NULL;
11552 }
11553
11554
11555 /**
11556  * gtk_tree_view_set_column_drag_function:
11557  * @tree_view: A #GtkTreeView.
11558  * @func: A function to determine which columns are reorderable, or %NULL.
11559  * @user_data: User data to be passed to @func, or %NULL
11560  * @destroy: Destroy notifier for @user_data, or %NULL
11561  *
11562  * Sets a user function for determining where a column may be dropped when
11563  * dragged.  This function is called on every column pair in turn at the
11564  * beginning of a column drag to determine where a drop can take place.  The
11565  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11566  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11567  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11568  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11569  * @tree_view reverts to the default behavior of allowing all columns to be
11570  * dropped everywhere.
11571  **/
11572 void
11573 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11574                                         GtkTreeViewColumnDropFunc  func,
11575                                         gpointer                   user_data,
11576                                         GtkDestroyNotify           destroy)
11577 {
11578   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11579
11580   if (tree_view->priv->column_drop_func_data_destroy)
11581     (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
11582
11583   tree_view->priv->column_drop_func = func;
11584   tree_view->priv->column_drop_func_data = user_data;
11585   tree_view->priv->column_drop_func_data_destroy = destroy;
11586 }
11587
11588 /**
11589  * gtk_tree_view_scroll_to_point:
11590  * @tree_view: a #GtkTreeView
11591  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11592  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11593  *
11594  * Scrolls the tree view such that the top-left corner of the visible
11595  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11596  * in tree coordinates.  The @tree_view must be realized before
11597  * this function is called.  If it isn't, you probably want to be
11598  * using gtk_tree_view_scroll_to_cell().
11599  *
11600  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11601  **/
11602 void
11603 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11604                                gint         tree_x,
11605                                gint         tree_y)
11606 {
11607   GtkAdjustment *hadj;
11608   GtkAdjustment *vadj;
11609
11610   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11611   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
11612
11613   hadj = tree_view->priv->hadjustment;
11614   vadj = tree_view->priv->vadjustment;
11615
11616   if (tree_x != -1)
11617     gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
11618   if (tree_y != -1)
11619     gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
11620 }
11621
11622 /**
11623  * gtk_tree_view_scroll_to_cell:
11624  * @tree_view: A #GtkTreeView.
11625  * @path: The path of the row to move to, or %NULL.
11626  * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
11627  * @use_align: whether to use alignment arguments, or %FALSE.
11628  * @row_align: The vertical alignment of the row specified by @path.
11629  * @col_align: The horizontal alignment of the column specified by @column.
11630  *
11631  * Moves the alignments of @tree_view to the position specified by @column and
11632  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11633  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11634  * or @path need to be non-%NULL.  @row_align determines where the row is
11635  * placed, and @col_align determines where @column is placed.  Both are expected
11636  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11637  * right/bottom alignment, 0.5 means center.
11638  *
11639  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11640  * tree does the minimum amount of work to scroll the cell onto the screen.
11641  * This means that the cell will be scrolled to the edge closest to its current
11642  * position.  If the cell is currently visible on the screen, nothing is done.
11643  *
11644  * This function only works if the model is set, and @path is a valid row on the
11645  * model.  If the model changes before the @tree_view is realized, the centered
11646  * path will be modified to reflect this change.
11647  **/
11648 void
11649 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11650                               GtkTreePath       *path,
11651                               GtkTreeViewColumn *column,
11652                               gboolean           use_align,
11653                               gfloat             row_align,
11654                               gfloat             col_align)
11655 {
11656   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11657   g_return_if_fail (tree_view->priv->model != NULL);
11658   g_return_if_fail (tree_view->priv->tree != NULL);
11659   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11660   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11661   g_return_if_fail (path != NULL || column != NULL);
11662
11663 #if 0
11664   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11665            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11666 #endif
11667   row_align = CLAMP (row_align, 0.0, 1.0);
11668   col_align = CLAMP (col_align, 0.0, 1.0);
11669
11670
11671   /* Note: Despite the benefits that come from having one code path for the
11672    * scrolling code, we short-circuit validate_visible_area's immplementation as
11673    * it is much slower than just going to the point.
11674    */
11675   if (! GTK_WIDGET_VISIBLE (tree_view) ||
11676       ! GTK_WIDGET_REALIZED (tree_view) ||
11677       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11678       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11679     {
11680       if (tree_view->priv->scroll_to_path)
11681         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11682
11683       tree_view->priv->scroll_to_path = NULL;
11684       tree_view->priv->scroll_to_column = NULL;
11685
11686       if (path)
11687         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11688       if (column)
11689         tree_view->priv->scroll_to_column = column;
11690       tree_view->priv->scroll_to_use_align = use_align;
11691       tree_view->priv->scroll_to_row_align = row_align;
11692       tree_view->priv->scroll_to_col_align = col_align;
11693
11694       install_presize_handler (tree_view);
11695     }
11696   else
11697     {
11698       GdkRectangle cell_rect;
11699       GdkRectangle vis_rect;
11700       gint dest_x, dest_y;
11701
11702       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11703       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11704
11705       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11706
11707       dest_x = vis_rect.x;
11708       dest_y = vis_rect.y;
11709
11710       if (column)
11711         {
11712           if (use_align)
11713             {
11714               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11715             }
11716           else
11717             {
11718               if (cell_rect.x < vis_rect.x)
11719                 dest_x = cell_rect.x;
11720               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11721                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11722             }
11723         }
11724
11725       if (path)
11726         {
11727           if (use_align)
11728             {
11729               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11730               dest_y = MAX (dest_y, 0);
11731             }
11732           else
11733             {
11734               if (cell_rect.y < vis_rect.y)
11735                 dest_y = cell_rect.y;
11736               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11737                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11738             }
11739         }
11740
11741       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11742     }
11743 }
11744
11745 /**
11746  * gtk_tree_view_row_activated:
11747  * @tree_view: A #GtkTreeView
11748  * @path: The #GtkTreePath to be activated.
11749  * @column: The #GtkTreeViewColumn to be activated.
11750  *
11751  * Activates the cell determined by @path and @column.
11752  **/
11753 void
11754 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11755                              GtkTreePath       *path,
11756                              GtkTreeViewColumn *column)
11757 {
11758   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11759
11760   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11761 }
11762
11763
11764 static void
11765 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11766                                           GtkRBNode *node,
11767                                           gpointer   data)
11768 {
11769   GtkTreeView *tree_view = data;
11770
11771   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11772       node->children)
11773     {
11774       GtkTreePath *path;
11775       GtkTreeIter iter;
11776
11777       path = _gtk_tree_view_find_path (tree_view, tree, node);
11778       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11779
11780       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11781
11782       gtk_tree_path_free (path);
11783     }
11784
11785   if (node->children)
11786     _gtk_rbtree_traverse (node->children,
11787                           node->children->root,
11788                           G_PRE_ORDER,
11789                           gtk_tree_view_expand_all_emission_helper,
11790                           tree_view);
11791 }
11792 /**
11793  * gtk_tree_view_expand_all:
11794  * @tree_view: A #GtkTreeView.
11795  *
11796  * Recursively expands all nodes in the @tree_view.
11797  **/
11798 void
11799 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11800 {
11801   GtkTreePath *path;
11802   GtkRBTree *tree;
11803   GtkRBNode *node;
11804
11805   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11806
11807   if (tree_view->priv->tree == NULL)
11808     return;
11809
11810   path = gtk_tree_path_new_first ();
11811   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11812
11813   while (node)
11814     {
11815       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11816       node = _gtk_rbtree_next (tree, node);
11817       gtk_tree_path_next (path);
11818   }
11819
11820   gtk_tree_path_free (path);
11821 }
11822
11823 /* Timeout to animate the expander during expands and collapses */
11824 static gboolean
11825 expand_collapse_timeout (gpointer data)
11826 {
11827   return do_expand_collapse (data);
11828 }
11829
11830 static gboolean
11831 do_expand_collapse (GtkTreeView *tree_view)
11832 {
11833   GtkRBNode *node;
11834   GtkRBTree *tree;
11835   gboolean expanding;
11836   gboolean redraw;
11837
11838   redraw = FALSE;
11839   expanding = TRUE;
11840
11841   node = tree_view->priv->expanded_collapsed_node;
11842   tree = tree_view->priv->expanded_collapsed_tree;
11843
11844   if (node->children == NULL)
11845     expanding = FALSE;
11846
11847   if (expanding)
11848     {
11849       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11850         {
11851           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11852           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11853
11854           redraw = TRUE;
11855
11856         }
11857       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11858         {
11859           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11860
11861           redraw = TRUE;
11862         }
11863     }
11864   else
11865     {
11866       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11867         {
11868           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11869           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11870
11871           redraw = TRUE;
11872         }
11873       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11874         {
11875           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11876
11877           redraw = TRUE;
11878
11879         }
11880     }
11881
11882   if (redraw)
11883     {
11884       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
11885
11886       return TRUE;
11887     }
11888
11889   return FALSE;
11890 }
11891
11892 /**
11893  * gtk_tree_view_collapse_all:
11894  * @tree_view: A #GtkTreeView.
11895  *
11896  * Recursively collapses all visible, expanded nodes in @tree_view.
11897  **/
11898 void
11899 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11900 {
11901   GtkRBTree *tree;
11902   GtkRBNode *node;
11903   GtkTreePath *path;
11904   gint *indices;
11905
11906   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11907
11908   if (tree_view->priv->tree == NULL)
11909     return;
11910
11911   path = gtk_tree_path_new ();
11912   gtk_tree_path_down (path);
11913   indices = gtk_tree_path_get_indices (path);
11914
11915   tree = tree_view->priv->tree;
11916   node = tree->root;
11917   while (node && node->left != tree->nil)
11918     node = node->left;
11919
11920   while (node)
11921     {
11922       if (node->children)
11923         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
11924       indices[0]++;
11925       node = _gtk_rbtree_next (tree, node);
11926     }
11927
11928   gtk_tree_path_free (path);
11929 }
11930
11931 /**
11932  * gtk_tree_view_expand_to_path:
11933  * @tree_view: A #GtkTreeView.
11934  * @path: path to a row.
11935  *
11936  * Expands the row at @path. This will also expand all parent rows of
11937  * @path as necessary.
11938  *
11939  * Since: 2.2
11940  **/
11941 void
11942 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
11943                               GtkTreePath *path)
11944 {
11945   gint i, depth;
11946   gint *indices;
11947   GtkTreePath *tmp;
11948
11949   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11950   g_return_if_fail (path != NULL);
11951
11952   depth = gtk_tree_path_get_depth (path);
11953   indices = gtk_tree_path_get_indices (path);
11954
11955   tmp = gtk_tree_path_new ();
11956   g_return_if_fail (tmp != NULL);
11957
11958   for (i = 0; i < depth; i++)
11959     {
11960       gtk_tree_path_append_index (tmp, indices[i]);
11961       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
11962     }
11963
11964   gtk_tree_path_free (tmp);
11965 }
11966
11967 /* FIXME the bool return values for expand_row and collapse_row are
11968  * not analagous; they should be TRUE if the row had children and
11969  * was not already in the requested state.
11970  */
11971
11972
11973 static gboolean
11974 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
11975                                GtkTreePath *path,
11976                                GtkRBTree   *tree,
11977                                GtkRBNode   *node,
11978                                gboolean     open_all,
11979                                gboolean     animate)
11980 {
11981   GtkTreeIter iter;
11982   GtkTreeIter temp;
11983   gboolean expand;
11984
11985   if (animate)
11986     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
11987                   "gtk-enable-animations", &animate,
11988                   NULL);
11989
11990   remove_auto_expand_timeout (tree_view);
11991
11992   if (node->children && !open_all)
11993     return FALSE;
11994
11995   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
11996     return FALSE;
11997
11998   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11999   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12000     return FALSE;
12001
12002
12003    if (node->children && open_all)
12004     {
12005       gboolean retval = FALSE;
12006       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12007
12008       gtk_tree_path_append_index (tmp_path, 0);
12009       tree = node->children;
12010       node = tree->root;
12011       while (node->left != tree->nil)
12012         node = node->left;
12013       /* try to expand the children */
12014       do
12015         {
12016          gboolean t;
12017          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12018                                             TRUE, animate);
12019          if (t)
12020            retval = TRUE;
12021
12022          gtk_tree_path_next (tmp_path);
12023          node = _gtk_rbtree_next (tree, node);
12024        }
12025       while (node != NULL);
12026
12027       gtk_tree_path_free (tmp_path);
12028
12029       return retval;
12030     }
12031
12032   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12033
12034   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12035     return FALSE;
12036
12037   if (expand)
12038     return FALSE;
12039
12040   node->children = _gtk_rbtree_new ();
12041   node->children->parent_tree = tree;
12042   node->children->parent_node = node;
12043
12044   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12045
12046   gtk_tree_view_build_tree (tree_view,
12047                             node->children,
12048                             &temp,
12049                             gtk_tree_path_get_depth (path) + 1,
12050                             open_all);
12051
12052   if (tree_view->priv->expand_collapse_timeout)
12053     {
12054       g_source_remove (tree_view->priv->expand_collapse_timeout);
12055       tree_view->priv->expand_collapse_timeout = 0;
12056     }
12057
12058   if (tree_view->priv->expanded_collapsed_node != NULL)
12059     {
12060       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
12061       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12062
12063       tree_view->priv->expanded_collapsed_node = NULL;
12064     }
12065
12066   if (animate)
12067     {
12068       tree_view->priv->expand_collapse_timeout = gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
12069       tree_view->priv->expanded_collapsed_node = node;
12070       tree_view->priv->expanded_collapsed_tree = tree;
12071
12072       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12073     }
12074
12075   install_presize_handler (tree_view);
12076
12077   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12078   if (open_all && node->children)
12079     {
12080       _gtk_rbtree_traverse (node->children,
12081                             node->children->root,
12082                             G_PRE_ORDER,
12083                             gtk_tree_view_expand_all_emission_helper,
12084                             tree_view);
12085     }
12086   return TRUE;
12087 }
12088
12089
12090 /**
12091  * gtk_tree_view_expand_row:
12092  * @tree_view: a #GtkTreeView
12093  * @path: path to a row
12094  * @open_all: whether to recursively expand, or just expand immediate children
12095  *
12096  * Opens the row so its children are visible.
12097  *
12098  * Return value: %TRUE if the row existed and had children
12099  **/
12100 gboolean
12101 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12102                           GtkTreePath *path,
12103                           gboolean     open_all)
12104 {
12105   GtkRBTree *tree;
12106   GtkRBNode *node;
12107
12108   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12109   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12110   g_return_val_if_fail (path != NULL, FALSE);
12111
12112   if (_gtk_tree_view_find_node (tree_view,
12113                                 path,
12114                                 &tree,
12115                                 &node))
12116     return FALSE;
12117
12118   if (tree != NULL)
12119     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12120   else
12121     return FALSE;
12122 }
12123
12124 static gboolean
12125 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12126                                  GtkTreePath *path,
12127                                  GtkRBTree   *tree,
12128                                  GtkRBNode   *node,
12129                                  gboolean     animate)
12130 {
12131   GtkTreeIter iter;
12132   GtkTreeIter children;
12133   gboolean collapse;
12134   gint x, y;
12135   GList *list;
12136   GdkWindow *child, *parent;
12137
12138   if (animate)
12139     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12140                   "gtk-enable-animations", &animate,
12141                   NULL);
12142
12143   remove_auto_expand_timeout (tree_view);
12144
12145   if (node->children == NULL)
12146     return FALSE;
12147
12148   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12149
12150   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12151
12152   if (collapse)
12153     return FALSE;
12154
12155   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12156    * a chance to prelight the correct node below */
12157
12158   if (tree_view->priv->prelight_tree)
12159     {
12160       GtkRBTree *parent_tree;
12161       GtkRBNode *parent_node;
12162
12163       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12164       parent_node = tree_view->priv->prelight_tree->parent_node;
12165       while (parent_tree)
12166         {
12167           if (parent_tree == tree && parent_node == node)
12168             {
12169               ensure_unprelighted (tree_view);
12170               break;
12171             }
12172           parent_node = parent_tree->parent_node;
12173           parent_tree = parent_tree->parent_tree;
12174         }
12175     }
12176
12177   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12178
12179   for (list = tree_view->priv->columns; list; list = list->next)
12180     {
12181       GtkTreeViewColumn *column = list->data;
12182
12183       if (column->visible == FALSE)
12184         continue;
12185       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12186         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12187     }
12188
12189   if (tree_view->priv->destroy_count_func)
12190     {
12191       GtkTreePath *child_path;
12192       gint child_count = 0;
12193       child_path = gtk_tree_path_copy (path);
12194       gtk_tree_path_down (child_path);
12195       if (node->children)
12196         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12197       (* tree_view->priv->destroy_count_func) (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12198       gtk_tree_path_free (child_path);
12199     }
12200
12201   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12202     {
12203       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12204
12205       if (gtk_tree_path_is_ancestor (path, cursor_path))
12206         {
12207           gtk_tree_row_reference_free (tree_view->priv->cursor);
12208           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12209                                                                       tree_view->priv->model,
12210                                                                       path);
12211         }
12212       gtk_tree_path_free (cursor_path);
12213     }
12214
12215   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12216     {
12217       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12218       if (gtk_tree_path_is_ancestor (path, anchor_path))
12219         {
12220           gtk_tree_row_reference_free (tree_view->priv->anchor);
12221           tree_view->priv->anchor = NULL;
12222         }
12223       gtk_tree_path_free (anchor_path);
12224     }
12225
12226   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press))
12227     {
12228       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
12229       if (gtk_tree_path_is_ancestor (path, lsc))
12230         {
12231           gtk_tree_row_reference_free (tree_view->priv->last_button_press);
12232           tree_view->priv->last_button_press = NULL;
12233         }
12234       gtk_tree_path_free (lsc);
12235     }
12236
12237   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press_2))
12238     {
12239       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press_2);
12240       if (gtk_tree_path_is_ancestor (path, lsc))
12241         {
12242           gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
12243           tree_view->priv->last_button_press_2 = NULL;
12244         }
12245       gtk_tree_path_free (lsc);
12246     }
12247
12248   if (tree_view->priv->expanded_collapsed_node != NULL)
12249     {
12250       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
12251       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
12252       
12253       tree_view->priv->expanded_collapsed_node = NULL;
12254     }
12255
12256   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12257     {
12258       _gtk_rbtree_remove (node->children);
12259       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12260     }
12261   else
12262     _gtk_rbtree_remove (node->children);
12263
12264   if (tree_view->priv->expand_collapse_timeout)
12265     {
12266       g_source_remove (tree_view->priv->expand_collapse_timeout);
12267       tree_view->priv->expand_collapse_timeout = 0;
12268     }
12269   
12270   if (animate)
12271     {
12272       tree_view->priv->expand_collapse_timeout = gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
12273       tree_view->priv->expanded_collapsed_node = node;
12274       tree_view->priv->expanded_collapsed_tree = tree;
12275
12276       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
12277     }
12278   
12279   if (GTK_WIDGET_MAPPED (tree_view))
12280     {
12281       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12282     }
12283
12284   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12285
12286   if (GTK_WIDGET_MAPPED (tree_view))
12287     {
12288       /* now that we've collapsed all rows, we want to try to set the prelight
12289        * again. To do this, we fake a motion event and send it to ourselves. */
12290
12291       child = tree_view->priv->bin_window;
12292       parent = gdk_window_get_parent (child);
12293
12294       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12295         {
12296           GdkEventMotion event;
12297           gint child_x, child_y;
12298
12299           gdk_window_get_position (child, &child_x, &child_y);
12300
12301           event.window = tree_view->priv->bin_window;
12302           event.x = x - child_x;
12303           event.y = y - child_y;
12304
12305           /* despite the fact this isn't a real event, I'm almost positive it will
12306            * never trigger a drag event.  maybe_drag is the only function that uses
12307            * more than just event.x and event.y. */
12308           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12309         }
12310     }
12311
12312   return TRUE;
12313 }
12314
12315 /**
12316  * gtk_tree_view_collapse_row:
12317  * @tree_view: a #GtkTreeView
12318  * @path: path to a row in the @tree_view
12319  *
12320  * Collapses a row (hides its child rows, if they exist).
12321  *
12322  * Return value: %TRUE if the row was collapsed.
12323  **/
12324 gboolean
12325 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12326                             GtkTreePath *path)
12327 {
12328   GtkRBTree *tree;
12329   GtkRBNode *node;
12330
12331   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12332   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12333   g_return_val_if_fail (path != NULL, FALSE);
12334
12335   if (_gtk_tree_view_find_node (tree_view,
12336                                 path,
12337                                 &tree,
12338                                 &node))
12339     return FALSE;
12340
12341   if (tree == NULL || node->children == NULL)
12342     return FALSE;
12343
12344   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12345 }
12346
12347 static void
12348 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12349                                         GtkRBTree              *tree,
12350                                         GtkTreePath            *path,
12351                                         GtkTreeViewMappingFunc  func,
12352                                         gpointer                user_data)
12353 {
12354   GtkRBNode *node;
12355
12356   if (tree == NULL || tree->root == NULL)
12357     return;
12358
12359   node = tree->root;
12360
12361   while (node && node->left != tree->nil)
12362     node = node->left;
12363
12364   while (node)
12365     {
12366       if (node->children)
12367         {
12368           (* func) (tree_view, path, user_data);
12369           gtk_tree_path_down (path);
12370           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12371           gtk_tree_path_up (path);
12372         }
12373       gtk_tree_path_next (path);
12374       node = _gtk_rbtree_next (tree, node);
12375     }
12376 }
12377
12378 /**
12379  * gtk_tree_view_map_expanded_rows:
12380  * @tree_view: A #GtkTreeView
12381  * @func: A function to be called
12382  * @data: User data to be passed to the function.
12383  *
12384  * Calls @func on all expanded rows.
12385  **/
12386 void
12387 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12388                                  GtkTreeViewMappingFunc  func,
12389                                  gpointer                user_data)
12390 {
12391   GtkTreePath *path;
12392
12393   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12394   g_return_if_fail (func != NULL);
12395
12396   path = gtk_tree_path_new_first ();
12397
12398   gtk_tree_view_map_expanded_rows_helper (tree_view,
12399                                           tree_view->priv->tree,
12400                                           path, func, user_data);
12401
12402   gtk_tree_path_free (path);
12403 }
12404
12405 /**
12406  * gtk_tree_view_row_expanded:
12407  * @tree_view: A #GtkTreeView.
12408  * @path: A #GtkTreePath to test expansion state.
12409  *
12410  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12411  *
12412  * Return value: %TRUE if #path is expanded.
12413  **/
12414 gboolean
12415 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12416                             GtkTreePath *path)
12417 {
12418   GtkRBTree *tree;
12419   GtkRBNode *node;
12420
12421   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12422   g_return_val_if_fail (path != NULL, FALSE);
12423
12424   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12425
12426   if (node == NULL)
12427     return FALSE;
12428
12429   return (node->children != NULL);
12430 }
12431
12432 static const GtkTargetEntry row_targets[] = {
12433   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12434 };
12435
12436
12437 /**
12438  * gtk_tree_view_get_reorderable:
12439  * @tree_view: a #GtkTreeView
12440  *
12441  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12442  * gtk_tree_view_set_reorderable().
12443  *
12444  * Return value: %TRUE if the tree can be reordered.
12445  **/
12446 gboolean
12447 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12448 {
12449   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12450
12451   return tree_view->priv->reorderable;
12452 }
12453
12454 /**
12455  * gtk_tree_view_set_reorderable:
12456  * @tree_view: A #GtkTreeView.
12457  * @reorderable: %TRUE, if the tree can be reordered.
12458  *
12459  * This function is a convenience function to allow you to reorder models that
12460  * support the #GtkDragSourceIface and the #GtkDragDestIface.  Both
12461  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
12462  * the user can reorder the model by dragging and dropping rows.  The
12463  * developer can listen to these changes by connecting to the model's
12464  * row_inserted and row_deleted signals.
12465  *
12466  * This function does not give you any degree of control over the order -- any
12467  * reordering is allowed.  If more control is needed, you should probably
12468  * handle drag and drop manually.
12469  **/
12470 void
12471 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12472                                gboolean     reorderable)
12473 {
12474   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12475
12476   reorderable = reorderable != FALSE;
12477
12478   if (tree_view->priv->reorderable == reorderable)
12479     return;
12480
12481   if (reorderable)
12482     {
12483       gtk_tree_view_enable_model_drag_source (tree_view,
12484                                               GDK_BUTTON1_MASK,
12485                                               row_targets,
12486                                               G_N_ELEMENTS (row_targets),
12487                                               GDK_ACTION_MOVE);
12488       gtk_tree_view_enable_model_drag_dest (tree_view,
12489                                             row_targets,
12490                                             G_N_ELEMENTS (row_targets),
12491                                             GDK_ACTION_MOVE);
12492     }
12493   else
12494     {
12495       gtk_tree_view_unset_rows_drag_source (tree_view);
12496       gtk_tree_view_unset_rows_drag_dest (tree_view);
12497     }
12498
12499   tree_view->priv->reorderable = reorderable;
12500
12501   g_object_notify (G_OBJECT (tree_view), "reorderable");
12502 }
12503
12504 static void
12505 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12506                                GtkTreePath     *path,
12507                                gboolean         clear_and_select,
12508                                gboolean         clamp_node)
12509 {
12510   GtkRBTree *tree = NULL;
12511   GtkRBNode *node = NULL;
12512
12513   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12514     {
12515       GtkTreePath *cursor_path;
12516       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12517       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12518       gtk_tree_path_free (cursor_path);
12519     }
12520
12521   gtk_tree_row_reference_free (tree_view->priv->cursor);
12522   tree_view->priv->cursor = NULL;
12523
12524   /* One cannot set the cursor on a separator. */
12525   if (!row_is_separator (tree_view, NULL, path))
12526     {
12527       tree_view->priv->cursor =
12528         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12529                                           tree_view->priv->model,
12530                                           path);
12531       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12532     }
12533
12534   if (tree != NULL)
12535     {
12536       GtkRBTree *new_tree = NULL;
12537       GtkRBNode *new_node = NULL;
12538
12539       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12540         {
12541           GtkTreeSelectMode mode = 0;
12542
12543           if (tree_view->priv->ctrl_pressed)
12544             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12545           if (tree_view->priv->shift_pressed)
12546             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12547
12548           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12549                                                     node, tree, path, mode,
12550                                                     FALSE);
12551         }
12552
12553       /* We have to re-find tree and node here again, somebody might have
12554        * cleared the node or the whole tree in the GtkTreeSelection::changed
12555        * callback. If the nodes differ we bail out here.
12556        */
12557       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12558
12559       if (tree != new_tree || node != new_node)
12560         return;
12561
12562       if (clamp_node)
12563         {
12564           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12565           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12566         }
12567     }
12568
12569   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12570 }
12571
12572 /**
12573  * gtk_tree_view_get_cursor:
12574  * @tree_view: A #GtkTreeView
12575  * @path: A pointer to be filled with the current cursor path, or %NULL
12576  * @focus_column: A pointer to be filled with the current focus column, or %NULL
12577  *
12578  * Fills in @path and @focus_column with the current path and focus column.  If
12579  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12580  * currently has focus, then *@focus_column will be %NULL.
12581  *
12582  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12583  * you are done with it.
12584  **/
12585 void
12586 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12587                           GtkTreePath       **path,
12588                           GtkTreeViewColumn **focus_column)
12589 {
12590   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12591
12592   if (path)
12593     {
12594       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12595         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12596       else
12597         *path = NULL;
12598     }
12599
12600   if (focus_column)
12601     {
12602       *focus_column = tree_view->priv->focus_column;
12603     }
12604 }
12605
12606 /**
12607  * gtk_tree_view_set_cursor:
12608  * @tree_view: A #GtkTreeView
12609  * @path: A #GtkTreePath
12610  * @focus_column: A #GtkTreeViewColumn, or %NULL
12611  * @start_editing: %TRUE if the specified cell should start being edited.
12612  *
12613  * Sets the current keyboard focus to be at @path, and selects it.  This is
12614  * useful when you want to focus the user's attention on a particular row.  If
12615  * @focus_column is not %NULL, then focus is given to the column specified by 
12616  * it. Additionally, if @focus_column is specified, and @start_editing is 
12617  * %TRUE, then editing should be started in the specified cell.  
12618  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12619  * in order to give keyboard focus to the widget.  Please note that editing 
12620  * can only happen when the widget is realized.
12621  **/
12622 void
12623 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12624                           GtkTreePath       *path,
12625                           GtkTreeViewColumn *focus_column,
12626                           gboolean           start_editing)
12627 {
12628   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12629                                     NULL, start_editing);
12630 }
12631
12632 /**
12633  * gtk_tree_view_set_cursor_on_cell:
12634  * @tree_view: A #GtkTreeView
12635  * @path: A #GtkTreePath
12636  * @focus_column: A #GtkTreeViewColumn, or %NULL
12637  * @focus_cell: A #GtkCellRenderer, or %NULL
12638  * @start_editing: %TRUE if the specified cell should start being edited.
12639  *
12640  * Sets the current keyboard focus to be at @path, and selects it.  This is
12641  * useful when you want to focus the user's attention on a particular row.  If
12642  * @focus_column is not %NULL, then focus is given to the column specified by
12643  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12644  * contains 2 or more editable or activatable cells, then focus is given to
12645  * the cell specified by @focus_cell. Additionally, if @focus_column is
12646  * specified, and @start_editing is %TRUE, then editing should be started in
12647  * the specified cell.  This function is often followed by
12648  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12649  * widget.  Please note that editing can only happen when the widget is
12650  * realized.
12651  *
12652  * Since: 2.2
12653  **/
12654 void
12655 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12656                                   GtkTreePath       *path,
12657                                   GtkTreeViewColumn *focus_column,
12658                                   GtkCellRenderer   *focus_cell,
12659                                   gboolean           start_editing)
12660 {
12661   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12662   g_return_if_fail (path != NULL);
12663   if (focus_column)
12664     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (focus_column));
12665   if (focus_cell)
12666     {
12667       g_return_if_fail (focus_column);
12668       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12669     }
12670
12671   /* cancel the current editing, if it exists */
12672   if (tree_view->priv->edited_column &&
12673       tree_view->priv->edited_column->editable_widget)
12674     gtk_tree_view_stop_editing (tree_view, TRUE);
12675
12676   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12677
12678   if (focus_column && focus_column->visible)
12679     {
12680       GList *list;
12681       gboolean column_in_tree = FALSE;
12682
12683       for (list = tree_view->priv->columns; list; list = list->next)
12684         if (list->data == focus_column)
12685           {
12686             column_in_tree = TRUE;
12687             break;
12688           }
12689       g_return_if_fail (column_in_tree);
12690       tree_view->priv->focus_column = focus_column;
12691       if (focus_cell)
12692         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12693       if (start_editing)
12694         gtk_tree_view_start_editing (tree_view, path);
12695     }
12696 }
12697
12698 /**
12699  * gtk_tree_view_get_bin_window:
12700  * @tree_view: A #GtkTreeView
12701  * 
12702  * Returns the window that @tree_view renders to.  This is used primarily to
12703  * compare to <literal>event->window</literal> to confirm that the event on
12704  * @tree_view is on the right window.
12705  * 
12706  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12707  **/
12708 GdkWindow *
12709 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12710 {
12711   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12712
12713   return tree_view->priv->bin_window;
12714 }
12715
12716 /**
12717  * gtk_tree_view_get_path_at_pos:
12718  * @tree_view: A #GtkTreeView.
12719  * @x: The x position to be identified (relative to bin_window).
12720  * @y: The y position to be identified (relative to bin_window).
12721  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12722  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12723  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
12724  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12725  *
12726  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12727  * (please see gtk_tree_view_get_bin_window()).
12728  * That is, @x and @y are relative to an events coordinates. @x and @y must
12729  * come from an event on the @tree_view only where <literal>event->window ==
12730  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12731  * things like popup menus. If @path is non-%NULL, then it will be filled
12732  * with the #GtkTreePath at that point.  This path should be freed with
12733  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12734  * with the column at that point.  @cell_x and @cell_y return the coordinates
12735  * relative to the cell background (i.e. the @background_area passed to
12736  * gtk_cell_renderer_render()).  This function is only meaningful if
12737  * @tree_view is realized.
12738  *
12739  * For converting widget coordinates (eg. the ones you get from
12740  * GtkWidget::query-tooltip), please see
12741  * gtk_tree_view_convert_widget_to_bin_window_coords().
12742  *
12743  * Return value: %TRUE if a row exists at that coordinate.
12744  **/
12745 gboolean
12746 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12747                                gint                x,
12748                                gint                y,
12749                                GtkTreePath       **path,
12750                                GtkTreeViewColumn **column,
12751                                gint               *cell_x,
12752                                gint               *cell_y)
12753 {
12754   GtkRBTree *tree;
12755   GtkRBNode *node;
12756   gint y_offset;
12757
12758   g_return_val_if_fail (tree_view != NULL, FALSE);
12759   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
12760
12761   if (path)
12762     *path = NULL;
12763   if (column)
12764     *column = NULL;
12765
12766   if (tree_view->priv->tree == NULL)
12767     return FALSE;
12768
12769   if (x > tree_view->priv->hadjustment->upper)
12770     return FALSE;
12771
12772   if (x < 0 || y < 0)
12773     return FALSE;
12774
12775   if (column || cell_x)
12776     {
12777       GtkTreeViewColumn *tmp_column;
12778       GtkTreeViewColumn *last_column = NULL;
12779       GList *list;
12780       gint remaining_x = x;
12781       gboolean found = FALSE;
12782       gboolean rtl;
12783
12784       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12785       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12786            list;
12787            list = (rtl ? list->prev : list->next))
12788         {
12789           tmp_column = list->data;
12790
12791           if (tmp_column->visible == FALSE)
12792             continue;
12793
12794           last_column = tmp_column;
12795           if (remaining_x <= tmp_column->width)
12796             {
12797               found = TRUE;
12798
12799               if (column)
12800                 *column = tmp_column;
12801
12802               if (cell_x)
12803                 *cell_x = remaining_x;
12804
12805               break;
12806             }
12807           remaining_x -= tmp_column->width;
12808         }
12809
12810       /* If found is FALSE and there is a last_column, then it the remainder
12811        * space is in that area
12812        */
12813       if (!found)
12814         {
12815           if (last_column)
12816             {
12817               if (column)
12818                 *column = last_column;
12819               
12820               if (cell_x)
12821                 *cell_x = last_column->width + remaining_x;
12822             }
12823           else
12824             {
12825               return FALSE;
12826             }
12827         }
12828     }
12829
12830   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12831                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12832                                       &tree, &node);
12833
12834   if (tree == NULL)
12835     return FALSE;
12836
12837   if (cell_y)
12838     *cell_y = y_offset;
12839
12840   if (path)
12841     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12842
12843   return TRUE;
12844 }
12845
12846
12847 /**
12848  * gtk_tree_view_get_cell_area:
12849  * @tree_view: a #GtkTreeView
12850  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12851  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12852  * @rect: rectangle to fill with cell rect
12853  *
12854  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12855  * row specified by @path and the column specified by @column.  If @path is
12856  * %NULL, or points to a path not currently displayed, the @y and @height fields
12857  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12858  * fields will be filled with 0.  The sum of all cell rects does not cover the
12859  * entire tree; there are extra pixels in between rows, for example. The
12860  * returned rectangle is equivalent to the @cell_area passed to
12861  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12862  * realized.
12863  **/
12864 void
12865 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12866                              GtkTreePath        *path,
12867                              GtkTreeViewColumn  *column,
12868                              GdkRectangle       *rect)
12869 {
12870   GtkRBTree *tree = NULL;
12871   GtkRBNode *node = NULL;
12872   gint vertical_separator;
12873   gint horizontal_separator;
12874
12875   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12876   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12877   g_return_if_fail (rect != NULL);
12878   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12879   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
12880
12881   gtk_widget_style_get (GTK_WIDGET (tree_view),
12882                         "vertical-separator", &vertical_separator,
12883                         "horizontal-separator", &horizontal_separator,
12884                         NULL);
12885
12886   rect->x = 0;
12887   rect->y = 0;
12888   rect->width = 0;
12889   rect->height = 0;
12890
12891   if (column)
12892     {
12893       rect->x = column->button->allocation.x + horizontal_separator/2;
12894       rect->width = column->button->allocation.width - horizontal_separator;
12895     }
12896
12897   if (path)
12898     {
12899       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12900
12901       /* Get vertical coords */
12902       if ((!ret && tree == NULL) || ret)
12903         return;
12904
12905       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12906       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12907
12908       if (column &&
12909           gtk_tree_view_is_expander_column (tree_view, column))
12910         {
12911           gint depth = gtk_tree_path_get_depth (path);
12912           gboolean rtl;
12913
12914           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12915
12916           if (!rtl)
12917             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12918           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12919
12920           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12921             {
12922               if (!rtl)
12923                 rect->x += depth * tree_view->priv->expander_size;
12924               rect->width -= depth * tree_view->priv->expander_size;
12925             }
12926
12927           rect->width = MAX (rect->width, 0);
12928         }
12929     }
12930 }
12931
12932 /**
12933  * gtk_tree_view_get_background_area:
12934  * @tree_view: a #GtkTreeView
12935  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12936  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
12937  * @rect: rectangle to fill with cell background rect
12938  *
12939  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12940  * row specified by @path and the column specified by @column.  If @path is
12941  * %NULL, or points to a node not found in the tree, the @y and @height fields of
12942  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12943  * fields will be filled with 0.  The returned rectangle is equivalent to the
12944  * @background_area passed to gtk_cell_renderer_render().  These background
12945  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
12946  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
12947  * itself, excluding surrounding borders and the tree expander area.
12948  *
12949  **/
12950 void
12951 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
12952                                    GtkTreePath        *path,
12953                                    GtkTreeViewColumn  *column,
12954                                    GdkRectangle       *rect)
12955 {
12956   GtkRBTree *tree = NULL;
12957   GtkRBNode *node = NULL;
12958
12959   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12960   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12961   g_return_if_fail (rect != NULL);
12962
12963   rect->x = 0;
12964   rect->y = 0;
12965   rect->width = 0;
12966   rect->height = 0;
12967
12968   if (path)
12969     {
12970       /* Get vertical coords */
12971
12972       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
12973           tree == NULL)
12974         return;
12975
12976       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
12977
12978       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
12979     }
12980
12981   if (column)
12982     {
12983       gint x2 = 0;
12984
12985       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
12986       rect->width = x2 - rect->x;
12987     }
12988 }
12989
12990 /**
12991  * gtk_tree_view_get_visible_rect:
12992  * @tree_view: a #GtkTreeView
12993  * @visible_rect: rectangle to fill
12994  *
12995  * Fills @visible_rect with the currently-visible region of the
12996  * buffer, in tree coordinates. Convert to bin_window coordinates with
12997  * gtk_tree_view_convert_tree_to_bin_window_coords().
12998  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
12999  * scrollable area of the tree.
13000  **/
13001 void
13002 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13003                                 GdkRectangle *visible_rect)
13004 {
13005   GtkWidget *widget;
13006
13007   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13008
13009   widget = GTK_WIDGET (tree_view);
13010
13011   if (visible_rect)
13012     {
13013       visible_rect->x = tree_view->priv->hadjustment->value;
13014       visible_rect->y = tree_view->priv->vadjustment->value;
13015       visible_rect->width = widget->allocation.width;
13016       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13017     }
13018 }
13019
13020 /**
13021  * gtk_tree_view_widget_to_tree_coords:
13022  * @tree_view: a #GtkTreeView
13023  * @wx: X coordinate relative to bin_window
13024  * @wy: Y coordinate relative to bin_window
13025  * @tx: return location for tree X coordinate
13026  * @ty: return location for tree Y coordinate
13027  *
13028  * Converts bin_window coordinates to coordinates for the
13029  * tree (the full scrollable area of the tree).
13030  *
13031  * Deprecated: 2.12: Due to historial reasons the name of this function is
13032  * incorrect.  For converting coordinates relative to the widget to
13033  * bin_window coordinates, please see
13034  * gtk_tree_view_convert_widget_to_bin_window_coords().
13035  *
13036  **/
13037 void
13038 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
13039                                       gint         wx,
13040                                       gint         wy,
13041                                       gint        *tx,
13042                                       gint        *ty)
13043 {
13044   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13045
13046   if (tx)
13047     *tx = wx + tree_view->priv->hadjustment->value;
13048   if (ty)
13049     *ty = wy + tree_view->priv->dy;
13050 }
13051
13052 /**
13053  * gtk_tree_view_tree_to_widget_coords:
13054  * @tree_view: a #GtkTreeView
13055  * @tx: tree X coordinate
13056  * @ty: tree Y coordinate
13057  * @wx: return location for X coordinate relative to bin_window
13058  * @wy: return location for Y coordinate relative to bin_window
13059  *
13060  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13061  * to bin_window coordinates.
13062  *
13063  * Deprecated: 2.12: Due to historial reasons the name of this function is
13064  * incorrect.  For converting bin_window coordinates to coordinates relative
13065  * to bin_window, please see
13066  * gtk_tree_view_convert_bin_window_to_widget_coords().
13067  *
13068  **/
13069 void
13070 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
13071                                      gint         tx,
13072                                      gint         ty,
13073                                      gint        *wx,
13074                                      gint        *wy)
13075 {
13076   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13077
13078   if (wx)
13079     *wx = tx - tree_view->priv->hadjustment->value;
13080   if (wy)
13081     *wy = ty - tree_view->priv->dy;
13082 }
13083
13084
13085 /**
13086  * gtk_tree_view_convert_widget_to_tree_coords:
13087  * @tree_view: a #GtkTreeView
13088  * @wx: X coordinate relative to the widget
13089  * @wy: Y coordinate relative to the widget
13090  * @tx: return location for tree X coordinate
13091  * @ty: return location for tree Y coordinate
13092  *
13093  * Converts widget coordinates to coordinates for the
13094  * tree (the full scrollable area of the tree).
13095  *
13096  * Since: 2.12
13097  **/
13098 void
13099 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13100                                              gint         wx,
13101                                              gint         wy,
13102                                              gint        *tx,
13103                                              gint        *ty)
13104 {
13105   gint x, y;
13106
13107   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13108
13109   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13110                                                      wx, wy,
13111                                                      &x, &y);
13112   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13113                                                    x, y,
13114                                                    tx, ty);
13115 }
13116
13117 /**
13118  * gtk_tree_view_convert_tree_to_widget_coords:
13119  * @tree_view: a #GtkTreeView
13120  * @tx: X coordinate relative to the tree
13121  * @ty: Y coordinate relative to the tree
13122  * @wx: return location for widget X coordinate
13123  * @wy: return location for widget Y coordinate
13124  *
13125  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13126  * to widget coordinates.
13127  *
13128  * Since: 2.12
13129  **/
13130 void
13131 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13132                                              gint         tx,
13133                                              gint         ty,
13134                                              gint        *wx,
13135                                              gint        *wy)
13136 {
13137   gint x, y;
13138
13139   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13140
13141   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13142                                                    tx, ty,
13143                                                    &x, &y);
13144   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13145                                                      x, y,
13146                                                      wx, wy);
13147 }
13148
13149 /**
13150  * gtk_tree_view_convert_widget_to_bin_window_coords:
13151  * @tree_view: a #GtkTreeView
13152  * @wx: X coordinate relative to the widget
13153  * @wy: Y coordinate relative to the widget
13154  * @bx: return location for bin_window X coordinate
13155  * @by: return location for bin_window Y coordinate
13156  *
13157  * Converts widget coordinates to coordinates for the bin_window
13158  * (see gtk_tree_view_get_bin_window()).
13159  *
13160  * Since: 2.12
13161  **/
13162 void
13163 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13164                                                    gint         wx,
13165                                                    gint         wy,
13166                                                    gint        *bx,
13167                                                    gint        *by)
13168 {
13169   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13170
13171   if (bx)
13172     *bx = wx + tree_view->priv->hadjustment->value;
13173   if (by)
13174     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13175 }
13176
13177 /**
13178  * gtk_tree_view_convert_bin_window_to_widget_coords:
13179  * @tree_view: a #GtkTreeView
13180  * @bx: bin_window X coordinate
13181  * @by: bin_window Y coordinate
13182  * @wx: return location for widget X coordinate
13183  * @wy: return location for widget Y coordinate
13184  *
13185  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13186  * to widget relative coordinates.
13187  *
13188  * Since: 2.12
13189  **/
13190 void
13191 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13192                                                    gint         bx,
13193                                                    gint         by,
13194                                                    gint        *wx,
13195                                                    gint        *wy)
13196 {
13197   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13198
13199   if (wx)
13200     *wx = bx - tree_view->priv->hadjustment->value;
13201   if (wy)
13202     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13203 }
13204
13205 /**
13206  * gtk_tree_view_convert_tree_to_bin_window_coords:
13207  * @tree_view: a #GtkTreeView
13208  * @tx: tree X coordinate
13209  * @ty: tree Y coordinate
13210  * @bx: return location for X coordinate relative to bin_window
13211  * @by: return location for Y coordinate relative to bin_window
13212  *
13213  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13214  * to bin_window coordinates.
13215  *
13216  * Since: 2.12
13217  **/
13218 void
13219 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13220                                                  gint         tx,
13221                                                  gint         ty,
13222                                                  gint        *bx,
13223                                                  gint        *by)
13224 {
13225   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13226
13227   if (bx)
13228     *bx = tx;
13229   if (by)
13230     *by = ty - tree_view->priv->dy;
13231 }
13232
13233 /**
13234  * gtk_tree_view_convert_bin_window_to_tree_coords:
13235  * @tree_view: a #GtkTreeView
13236  * @bx: X coordinate relative to bin_window
13237  * @by: Y coordinate relative to bin_window
13238  * @tx: return location for tree X coordinate
13239  * @ty: return location for tree Y coordinate
13240  *
13241  * Converts bin_window coordinates to coordinates for the
13242  * tree (the full scrollable area of the tree).
13243  *
13244  * Since: 2.12
13245  **/
13246 void
13247 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13248                                                  gint         bx,
13249                                                  gint         by,
13250                                                  gint        *tx,
13251                                                  gint        *ty)
13252 {
13253   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13254
13255   if (tx)
13256     *tx = bx;
13257   if (ty)
13258     *ty = by + tree_view->priv->dy;
13259 }
13260
13261
13262
13263 /**
13264  * gtk_tree_view_get_visible_range:
13265  * @tree_view: A #GtkTreeView
13266  * @start_path: Return location for start of region, or %NULL.
13267  * @end_path: Return location for end of region, or %NULL.
13268  *
13269  * Sets @start_path and @end_path to be the first and last visible path.
13270  * Note that there may be invisible paths in between.
13271  *
13272  * The paths should be freed with gtk_tree_path_free() after use.
13273  *
13274  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13275  *
13276  * Since: 2.8
13277  **/
13278 gboolean
13279 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13280                                  GtkTreePath **start_path,
13281                                  GtkTreePath **end_path)
13282 {
13283   GtkRBTree *tree;
13284   GtkRBNode *node;
13285
13286   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13287
13288   if (!tree_view->priv->tree)
13289     return FALSE;
13290
13291   if (start_path)
13292     {
13293       _gtk_rbtree_find_offset (tree_view->priv->tree,
13294                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13295                                &tree, &node);
13296       *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13297     }
13298
13299   if (end_path)
13300     {
13301       gint y;
13302
13303       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13304         y = tree_view->priv->height - 1;
13305       else
13306         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13307
13308       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13309       *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13310     }
13311
13312   return TRUE;
13313 }
13314
13315 static void
13316 unset_reorderable (GtkTreeView *tree_view)
13317 {
13318   if (tree_view->priv->reorderable)
13319     {
13320       tree_view->priv->reorderable = FALSE;
13321       g_object_notify (G_OBJECT (tree_view), "reorderable");
13322     }
13323 }
13324
13325 /**
13326  * gtk_tree_view_enable_model_drag_source:
13327  * @tree_view: a #GtkTreeView
13328  * @start_button_mask: Mask of allowed buttons to start drag
13329  * @targets: the table of targets that the drag will support
13330  * @n_targets: the number of items in @targets
13331  * @actions: the bitmask of possible actions for a drag from this
13332  *    widget
13333  * 
13334  * Turns @tree_view into a drag source for automatic DND.
13335  **/
13336 void
13337 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13338                                         GdkModifierType           start_button_mask,
13339                                         const GtkTargetEntry     *targets,
13340                                         gint                      n_targets,
13341                                         GdkDragAction             actions)
13342 {
13343   TreeViewDragInfo *di;
13344
13345   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13346
13347   gtk_drag_source_set (GTK_WIDGET (tree_view),
13348                        0,
13349                        targets,
13350                        n_targets,
13351                        actions);
13352
13353   di = ensure_info (tree_view);
13354   clear_source_info (di);
13355
13356   di->start_button_mask = start_button_mask;
13357   di->source_target_list = gtk_target_list_new (targets, n_targets);
13358   di->source_actions = actions;
13359
13360   di->source_set = TRUE;
13361
13362   unset_reorderable (tree_view);
13363 }
13364
13365 /**
13366  * gtk_tree_view_enable_model_drag_dest:
13367  * @tree_view: a #GtkTreeView
13368  * @targets: the table of targets that the drag will support
13369  * @n_targets: the number of items in @targets
13370  * @actions: the bitmask of possible actions for a drag from this
13371  *    widget
13372  * 
13373  * Turns @tree_view into a drop destination for automatic DND.
13374  **/
13375 void
13376 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13377                                       const GtkTargetEntry     *targets,
13378                                       gint                      n_targets,
13379                                       GdkDragAction             actions)
13380 {
13381   TreeViewDragInfo *di;
13382
13383   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13384
13385   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13386                      0,
13387                      targets,
13388                      n_targets,
13389                      actions);
13390
13391   di = ensure_info (tree_view);
13392   clear_dest_info (di);
13393
13394   if (targets)
13395     di->dest_target_list = gtk_target_list_new (targets, n_targets);
13396
13397   di->dest_set = TRUE;
13398
13399   unset_reorderable (tree_view);
13400 }
13401
13402 /**
13403  * gtk_tree_view_unset_rows_drag_source:
13404  * @tree_view: a #GtkTreeView
13405  * 
13406  * Undoes the effect of gtk_tree_view_enable_model_drag_source().
13407  **/
13408 void
13409 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13410 {
13411   TreeViewDragInfo *di;
13412
13413   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13414
13415   di = get_info (tree_view);
13416
13417   if (di)
13418     {
13419       if (di->source_set)
13420         {
13421           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13422           clear_source_info (di);
13423           di->source_set = FALSE;
13424         }
13425
13426       if (!di->dest_set && !di->source_set)
13427         remove_info (tree_view);
13428     }
13429   
13430   unset_reorderable (tree_view);
13431 }
13432
13433 /**
13434  * gtk_tree_view_unset_rows_drag_dest:
13435  * @tree_view: a #GtkTreeView
13436  * 
13437  * Undoes the effect of gtk_tree_view_enable_model_drag_dest().
13438  **/
13439 void
13440 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13441 {
13442   TreeViewDragInfo *di;
13443
13444   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13445
13446   di = get_info (tree_view);
13447
13448   if (di)
13449     {
13450       if (di->dest_set)
13451         {
13452           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13453           clear_dest_info (di);
13454           di->dest_set = FALSE;
13455         }
13456
13457       if (!di->dest_set && !di->source_set)
13458         remove_info (tree_view);
13459     }
13460
13461   unset_reorderable (tree_view);
13462 }
13463
13464 /**
13465  * gtk_tree_view_set_drag_dest_row:
13466  * @tree_view: a #GtkTreeView
13467  * @path: The path of the row to highlight, or %NULL.
13468  * @pos: Specifies whether to drop before, after or into the row
13469  * 
13470  * Sets the row that is highlighted for feedback.
13471  **/
13472 void
13473 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13474                                  GtkTreePath            *path,
13475                                  GtkTreeViewDropPosition pos)
13476 {
13477   GtkTreePath *current_dest;
13478
13479   /* Note; this function is exported to allow a custom DND
13480    * implementation, so it can't touch TreeViewDragInfo
13481    */
13482
13483   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13484
13485   current_dest = NULL;
13486
13487   if (tree_view->priv->drag_dest_row)
13488     {
13489       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13490       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13491     }
13492
13493   /* special case a drop on an empty model */
13494   tree_view->priv->empty_view_drop = 0;
13495
13496   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13497       && gtk_tree_path_get_depth (path) == 1
13498       && gtk_tree_path_get_indices (path)[0] == 0)
13499     {
13500       gint n_children;
13501
13502       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13503                                                    NULL);
13504
13505       if (!n_children)
13506         tree_view->priv->empty_view_drop = 1;
13507     }
13508
13509   tree_view->priv->drag_dest_pos = pos;
13510
13511   if (path)
13512     {
13513       tree_view->priv->drag_dest_row =
13514         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13515       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13516     }
13517   else
13518     tree_view->priv->drag_dest_row = NULL;
13519
13520   if (current_dest)
13521     {
13522       GtkRBTree *tree, *new_tree;
13523       GtkRBNode *node, *new_node;
13524
13525       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13526       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13527
13528       if (tree && node)
13529         {
13530           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13531           if (new_tree && new_node)
13532             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13533
13534           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13535           if (new_tree && new_node)
13536             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13537         }
13538       gtk_tree_path_free (current_dest);
13539     }
13540 }
13541
13542 /**
13543  * gtk_tree_view_get_drag_dest_row:
13544  * @tree_view: a #GtkTreeView
13545  * @path: Return location for the path of the highlighted row, or %NULL.
13546  * @pos: Return location for the drop position, or %NULL
13547  * 
13548  * Gets information about the row that is highlighted for feedback.
13549  **/
13550 void
13551 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13552                                  GtkTreePath             **path,
13553                                  GtkTreeViewDropPosition  *pos)
13554 {
13555   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13556
13557   if (path)
13558     {
13559       if (tree_view->priv->drag_dest_row)
13560         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13561       else
13562         {
13563           if (tree_view->priv->empty_view_drop)
13564             *path = gtk_tree_path_new_from_indices (0, -1);
13565           else
13566             *path = NULL;
13567         }
13568     }
13569
13570   if (pos)
13571     *pos = tree_view->priv->drag_dest_pos;
13572 }
13573
13574 /**
13575  * gtk_tree_view_get_dest_row_at_pos:
13576  * @tree_view: a #GtkTreeView
13577  * @drag_x: the position to determine the destination row for
13578  * @drag_y: the position to determine the destination row for
13579  * @path: Return location for the path of the highlighted row, or %NULL.
13580  * @pos: Return location for the drop position, or %NULL
13581  * 
13582  * Determines the destination row for a given position.  @drag_x and
13583  * @drag_y are expected to be in widget coordinates.
13584  * 
13585  * Return value: whether there is a row at the given position.
13586  **/
13587 gboolean
13588 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13589                                    gint                     drag_x,
13590                                    gint                     drag_y,
13591                                    GtkTreePath            **path,
13592                                    GtkTreeViewDropPosition *pos)
13593 {
13594   gint cell_y;
13595   gint bin_x, bin_y;
13596   gdouble offset_into_row;
13597   gdouble third;
13598   GdkRectangle cell;
13599   GtkTreeViewColumn *column = NULL;
13600   GtkTreePath *tmp_path = NULL;
13601
13602   /* Note; this function is exported to allow a custom DND
13603    * implementation, so it can't touch TreeViewDragInfo
13604    */
13605
13606   g_return_val_if_fail (tree_view != NULL, FALSE);
13607   g_return_val_if_fail (drag_x >= 0, FALSE);
13608   g_return_val_if_fail (drag_y >= 0, FALSE);
13609   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
13610
13611
13612   if (path)
13613     *path = NULL;
13614
13615   if (tree_view->priv->tree == NULL)
13616     return FALSE;
13617
13618   /* If in the top third of a row, we drop before that row; if
13619    * in the bottom third, drop after that row; if in the middle,
13620    * and the row has children, drop into the row.
13621    */
13622   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13623                                                      &bin_x, &bin_y);
13624
13625   if (!gtk_tree_view_get_path_at_pos (tree_view,
13626                                       bin_x,
13627                                       bin_y,
13628                                       &tmp_path,
13629                                       &column,
13630                                       NULL,
13631                                       &cell_y))
13632     return FALSE;
13633
13634   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13635                                      &cell);
13636
13637   offset_into_row = cell_y;
13638
13639   if (path)
13640     *path = tmp_path;
13641   else
13642     gtk_tree_path_free (tmp_path);
13643
13644   tmp_path = NULL;
13645
13646   third = cell.height / 3.0;
13647
13648   if (pos)
13649     {
13650       if (offset_into_row < third)
13651         {
13652           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13653         }
13654       else if (offset_into_row < (cell.height / 2.0))
13655         {
13656           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13657         }
13658       else if (offset_into_row < third * 2.0)
13659         {
13660           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13661         }
13662       else
13663         {
13664           *pos = GTK_TREE_VIEW_DROP_AFTER;
13665         }
13666     }
13667
13668   return TRUE;
13669 }
13670
13671
13672
13673 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13674 /**
13675  * gtk_tree_view_create_row_drag_icon:
13676  * @tree_view: a #GtkTreeView
13677  * @path: a #GtkTreePath in @tree_view
13678  *
13679  * Creates a #GdkPixmap representation of the row at @path.  
13680  * This image is used for a drag icon.
13681  *
13682  * Return value: a newly-allocated pixmap of the drag icon.
13683  **/
13684 GdkPixmap *
13685 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13686                                     GtkTreePath  *path)
13687 {
13688   GtkTreeIter   iter;
13689   GtkRBTree    *tree;
13690   GtkRBNode    *node;
13691   gint cell_offset;
13692   GList *list;
13693   GdkRectangle background_area;
13694   GdkRectangle expose_area;
13695   GtkWidget *widget;
13696   gint depth;
13697   /* start drawing inside the black outline */
13698   gint x = 1, y = 1;
13699   GdkDrawable *drawable;
13700   gint bin_window_width;
13701   gboolean is_separator = FALSE;
13702   gboolean rtl;
13703
13704   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13705   g_return_val_if_fail (path != NULL, NULL);
13706
13707   widget = GTK_WIDGET (tree_view);
13708
13709   if (!GTK_WIDGET_REALIZED (tree_view))
13710     return NULL;
13711
13712   depth = gtk_tree_path_get_depth (path);
13713
13714   _gtk_tree_view_find_node (tree_view,
13715                             path,
13716                             &tree,
13717                             &node);
13718
13719   if (tree == NULL)
13720     return NULL;
13721
13722   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13723                                 &iter,
13724                                 path))
13725     return NULL;
13726   
13727   is_separator = row_is_separator (tree_view, &iter, NULL);
13728
13729   cell_offset = x;
13730
13731   background_area.y = y;
13732   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13733
13734   gdk_drawable_get_size (tree_view->priv->bin_window,
13735                          &bin_window_width, NULL);
13736
13737   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13738                              bin_window_width + 2,
13739                              background_area.height + 2,
13740                              -1);
13741
13742   expose_area.x = 0;
13743   expose_area.y = 0;
13744   expose_area.width = bin_window_width + 2;
13745   expose_area.height = background_area.height + 2;
13746
13747   gdk_draw_rectangle (drawable,
13748                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
13749                       TRUE,
13750                       0, 0,
13751                       bin_window_width + 2,
13752                       background_area.height + 2);
13753
13754   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13755
13756   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13757       list;
13758       list = (rtl ? list->prev : list->next))
13759     {
13760       GtkTreeViewColumn *column = list->data;
13761       GdkRectangle cell_area;
13762       gint vertical_separator;
13763
13764       if (!column->visible)
13765         continue;
13766
13767       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13768                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13769                                                node->children?TRUE:FALSE);
13770
13771       background_area.x = cell_offset;
13772       background_area.width = column->width;
13773
13774       gtk_widget_style_get (widget,
13775                             "vertical-separator", &vertical_separator,
13776                             NULL);
13777
13778       cell_area = background_area;
13779
13780       cell_area.y += vertical_separator / 2;
13781       cell_area.height -= vertical_separator;
13782
13783       if (gtk_tree_view_is_expander_column (tree_view, column))
13784         {
13785           if (!rtl)
13786             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13787           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13788
13789           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13790             {
13791               if (!rtl)
13792                 cell_area.x += depth * tree_view->priv->expander_size;
13793               cell_area.width -= depth * tree_view->priv->expander_size;
13794             }
13795         }
13796
13797       if (gtk_tree_view_column_cell_is_visible (column))
13798         {
13799           if (is_separator)
13800             gtk_paint_hline (widget->style,
13801                              drawable,
13802                              GTK_STATE_NORMAL,
13803                              &cell_area,
13804                              widget,
13805                              NULL,
13806                              cell_area.x,
13807                              cell_area.x + cell_area.width,
13808                              cell_area.y + cell_area.height / 2);
13809           else
13810             _gtk_tree_view_column_cell_render (column,
13811                                                drawable,
13812                                                &background_area,
13813                                                &cell_area,
13814                                                &expose_area,
13815                                                0);
13816         }
13817       cell_offset += column->width;
13818     }
13819
13820   gdk_draw_rectangle (drawable,
13821                       widget->style->black_gc,
13822                       FALSE,
13823                       0, 0,
13824                       bin_window_width + 1,
13825                       background_area.height + 1);
13826
13827   return drawable;
13828 }
13829
13830
13831 /**
13832  * gtk_tree_view_set_destroy_count_func:
13833  * @tree_view: A #GtkTreeView
13834  * @func: Function to be called when a view row is destroyed, or %NULL
13835  * @data: User data to be passed to @func, or %NULL
13836  * @destroy: Destroy notifier for @data, or %NULL
13837  *
13838  * This function should almost never be used.  It is meant for private use by
13839  * ATK for determining the number of visible children that are removed when the
13840  * user collapses a row, or a row is deleted.
13841  **/
13842 void
13843 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13844                                       GtkTreeDestroyCountFunc  func,
13845                                       gpointer                 data,
13846                                       GtkDestroyNotify         destroy)
13847 {
13848   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13849
13850   if (tree_view->priv->destroy_count_destroy)
13851     (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
13852
13853   tree_view->priv->destroy_count_func = func;
13854   tree_view->priv->destroy_count_data = data;
13855   tree_view->priv->destroy_count_destroy = destroy;
13856 }
13857
13858
13859 /*
13860  * Interactive search
13861  */
13862
13863 /**
13864  * gtk_tree_view_set_enable_search:
13865  * @tree_view: A #GtkTreeView
13866  * @enable_search: %TRUE, if the user can search interactively
13867  *
13868  * If @enable_search is set, then the user can type in text to search through
13869  * the tree interactively (this is sometimes called "typeahead find").
13870  * 
13871  * Note that even if this is %FALSE, the user can still initiate a search 
13872  * using the "start-interactive-search" key binding.
13873  */
13874 void
13875 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13876                                  gboolean     enable_search)
13877 {
13878   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13879
13880   enable_search = !!enable_search;
13881   
13882   if (tree_view->priv->enable_search != enable_search)
13883     {
13884        tree_view->priv->enable_search = enable_search;
13885        g_object_notify (G_OBJECT (tree_view), "enable-search");
13886     }
13887 }
13888
13889 /**
13890  * gtk_tree_view_get_enable_search:
13891  * @tree_view: A #GtkTreeView
13892  *
13893  * Returns whether or not the tree allows to start interactive searching 
13894  * by typing in text.
13895  *
13896  * Return value: whether or not to let the user search interactively
13897  */
13898 gboolean
13899 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13900 {
13901   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13902
13903   return tree_view->priv->enable_search;
13904 }
13905
13906
13907 /**
13908  * gtk_tree_view_get_search_column:
13909  * @tree_view: A #GtkTreeView
13910  *
13911  * Gets the column searched on by the interactive search code.
13912  *
13913  * Return value: the column the interactive search code searches in.
13914  */
13915 gint
13916 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13917 {
13918   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13919
13920   return (tree_view->priv->search_column);
13921 }
13922
13923 /**
13924  * gtk_tree_view_set_search_column:
13925  * @tree_view: A #GtkTreeView
13926  * @column: the column of the model to search in, or -1 to disable searching
13927  *
13928  * Sets @column as the column where the interactive search code should
13929  * search in. 
13930  * 
13931  * If the sort column is set, users can use the "start-interactive-search"
13932  * key binding to bring up search popup. The enable-search property controls
13933  * whether simply typing text will also start an interactive search.
13934  *
13935  * Note that @column refers to a column of the model. 
13936  */
13937 void
13938 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13939                                  gint         column)
13940 {
13941   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13942   g_return_if_fail (column >= -1);
13943
13944   if (tree_view->priv->search_column == column)
13945     return;
13946
13947   tree_view->priv->search_column = column;
13948   g_object_notify (G_OBJECT (tree_view), "search-column");
13949 }
13950
13951 /**
13952  * gtk_tree_view_get_search_equal_func:
13953  * @tree_view: A #GtkTreeView
13954  *
13955  * Returns the compare function currently in use.
13956  *
13957  * Return value: the currently used compare function for the search code.
13958  */
13959
13960 GtkTreeViewSearchEqualFunc
13961 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
13962 {
13963   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13964
13965   return tree_view->priv->search_equal_func;
13966 }
13967
13968 /**
13969  * gtk_tree_view_set_search_equal_func:
13970  * @tree_view: A #GtkTreeView
13971  * @search_equal_func: the compare function to use during the search
13972  * @search_user_data: user data to pass to @search_equal_func, or %NULL
13973  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
13974  *
13975  * Sets the compare function for the interactive search capabilities; note
13976  * that somewhat like strcmp() returning 0 for equality
13977  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
13978  **/
13979 void
13980 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
13981                                      GtkTreeViewSearchEqualFunc  search_equal_func,
13982                                      gpointer                    search_user_data,
13983                                      GtkDestroyNotify            search_destroy)
13984 {
13985   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13986   g_return_if_fail (search_equal_func != NULL);
13987
13988   if (tree_view->priv->search_destroy)
13989     (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
13990
13991   tree_view->priv->search_equal_func = search_equal_func;
13992   tree_view->priv->search_user_data = search_user_data;
13993   tree_view->priv->search_destroy = search_destroy;
13994   if (tree_view->priv->search_equal_func == NULL)
13995     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
13996 }
13997
13998 /**
13999  * gtk_tree_view_get_search_entry:
14000  * @tree_view: A #GtkTreeView
14001  *
14002  * Returns the GtkEntry which is currently in use as interactive search
14003  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14004  * will be returned.
14005  *
14006  * Return value: the entry currently in use as search entry.
14007  *
14008  * Since: 2.10
14009  */
14010 GtkEntry *
14011 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14012 {
14013   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14014
14015   if (tree_view->priv->search_custom_entry_set)
14016     return GTK_ENTRY (tree_view->priv->search_entry);
14017
14018   return NULL;
14019 }
14020
14021 /**
14022  * gtk_tree_view_set_search_entry:
14023  * @tree_view: A #GtkTreeView
14024  * @entry: the entry the interactive search code of @tree_view should use or %NULL
14025  *
14026  * Sets the entry which the interactive search code will use for this
14027  * @tree_view.  This is useful when you want to provide a search entry
14028  * in our interface at all time at a fixed position.  Passing %NULL for
14029  * @entry will make the interactive search code use the built-in popup
14030  * entry again.
14031  *
14032  * Since: 2.10
14033  */
14034 void
14035 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14036                                 GtkEntry    *entry)
14037 {
14038   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14039   if (entry != NULL)
14040     g_return_if_fail (GTK_IS_ENTRY (entry));
14041
14042   if (tree_view->priv->search_custom_entry_set)
14043     {
14044       if (tree_view->priv->search_entry_changed_id)
14045         {
14046           g_signal_handler_disconnect (tree_view->priv->search_entry,
14047                                        tree_view->priv->search_entry_changed_id);
14048           tree_view->priv->search_entry_changed_id = 0;
14049         }
14050       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14051                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14052                                             tree_view);
14053
14054       g_object_unref (tree_view->priv->search_entry);
14055     }
14056   else if (tree_view->priv->search_window)
14057     {
14058       gtk_widget_destroy (tree_view->priv->search_window);
14059
14060       tree_view->priv->search_window = NULL;
14061     }
14062
14063   if (entry)
14064     {
14065       tree_view->priv->search_entry = g_object_ref (entry);
14066       tree_view->priv->search_custom_entry_set = TRUE;
14067
14068       if (tree_view->priv->search_entry_changed_id == 0)
14069         {
14070           tree_view->priv->search_entry_changed_id =
14071             g_signal_connect (tree_view->priv->search_entry, "changed",
14072                               G_CALLBACK (gtk_tree_view_search_init),
14073                               tree_view);
14074         }
14075       
14076         g_signal_connect (tree_view->priv->search_entry, "key_press_event",
14077                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14078                           tree_view);
14079
14080         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14081     }
14082   else
14083     {
14084       tree_view->priv->search_entry = NULL;
14085       tree_view->priv->search_custom_entry_set = FALSE;
14086     }
14087 }
14088
14089 /**
14090  * gtk_tree_view_set_search_position_func:
14091  * @tree_view: A #GtkTreeView
14092  * @func: the function to use to position the search dialog, or %NULL
14093  *    to use the default search position function
14094  * @data: user data to pass to @func, or %NULL
14095  * @destroy: Destroy notifier for @data, or %NULL
14096  *
14097  * Sets the function to use when positioning the seach dialog.
14098  *
14099  * Since: 2.10
14100  **/
14101 void
14102 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14103                                         GtkTreeViewSearchPositionFunc  func,
14104                                         gpointer                       user_data,
14105                                         GDestroyNotify                 destroy)
14106 {
14107   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14108
14109   if (tree_view->priv->search_position_destroy)
14110     (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
14111
14112   tree_view->priv->search_position_func = func;
14113   tree_view->priv->search_position_user_data = user_data;
14114   tree_view->priv->search_position_destroy = destroy;
14115   if (tree_view->priv->search_position_func == NULL)
14116     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14117 }
14118
14119 /**
14120  * gtk_tree_view_get_search_position_func:
14121  * @tree_view: A #GtkTreeView
14122  *
14123  * Returns the positioning function currently in use.
14124  *
14125  * Return value: the currently used function for positioning the search dialog.
14126  *
14127  * Since: 2.10
14128  */
14129 GtkTreeViewSearchPositionFunc
14130 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14131 {
14132   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14133
14134   return tree_view->priv->search_position_func;
14135 }
14136
14137
14138 static void
14139 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14140                                   GtkTreeView *tree_view)
14141 {
14142   if (tree_view->priv->disable_popdown)
14143     return;
14144
14145   if (tree_view->priv->search_entry_changed_id)
14146     {
14147       g_signal_handler_disconnect (tree_view->priv->search_entry,
14148                                    tree_view->priv->search_entry_changed_id);
14149       tree_view->priv->search_entry_changed_id = 0;
14150     }
14151   if (tree_view->priv->typeselect_flush_timeout)
14152     {
14153       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14154       tree_view->priv->typeselect_flush_timeout = 0;
14155     }
14156         
14157   if (GTK_WIDGET_VISIBLE (search_dialog))
14158     {
14159       /* send focus-in event */
14160       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
14161       gtk_widget_hide (search_dialog);
14162       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14163       send_focus_change (GTK_WIDGET (tree_view), TRUE);
14164     }
14165 }
14166
14167 static void
14168 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14169                                     GtkWidget   *search_dialog,
14170                                     gpointer     user_data)
14171 {
14172   gint x, y;
14173   gint tree_x, tree_y;
14174   gint tree_width, tree_height;
14175   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
14176   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14177   GtkRequisition requisition;
14178   gint monitor_num;
14179   GdkRectangle monitor;
14180
14181   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14182   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14183
14184   gtk_widget_realize (search_dialog);
14185
14186   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14187   gdk_drawable_get_size (tree_window,
14188                          &tree_width,
14189                          &tree_height);
14190   gtk_widget_size_request (search_dialog, &requisition);
14191
14192   if (tree_x + tree_width > gdk_screen_get_width (screen))
14193     x = gdk_screen_get_width (screen) - requisition.width;
14194   else if (tree_x + tree_width - requisition.width < 0)
14195     x = 0;
14196   else
14197     x = tree_x + tree_width - requisition.width;
14198
14199   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14200     y = gdk_screen_get_height (screen) - requisition.height;
14201   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14202     y = 0;
14203   else
14204     y = tree_y + tree_height;
14205
14206   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14207 }
14208
14209 static void
14210 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14211                                       GtkMenu  *menu,
14212                                       gpointer  data)
14213 {
14214   GtkTreeView *tree_view = (GtkTreeView *)data;
14215
14216   tree_view->priv->disable_popdown = 1;
14217   g_signal_connect (menu, "hide",
14218                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14219 }
14220
14221 /* Because we're visible but offscreen, we just set a flag in the preedit
14222  * callback.
14223  */
14224 static void
14225 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14226                                       GtkTreeView  *tree_view)
14227 {
14228   tree_view->priv->imcontext_changed = 1;
14229   if (tree_view->priv->typeselect_flush_timeout)
14230     {
14231       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14232       tree_view->priv->typeselect_flush_timeout =
14233         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14234                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14235                        tree_view);
14236     }
14237
14238 }
14239
14240 static void
14241 gtk_tree_view_search_activate (GtkEntry    *entry,
14242                                GtkTreeView *tree_view)
14243 {
14244   GtkTreePath *path;
14245   GtkRBNode *node;
14246   GtkRBTree *tree;
14247
14248   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14249                                     tree_view);
14250
14251   /* If we have a row selected and it's the cursor row, we activate
14252    * the row XXX */
14253   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14254     {
14255       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14256       
14257       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14258       
14259       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14260         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14261       
14262       gtk_tree_path_free (path);
14263     }
14264 }
14265
14266 static gboolean
14267 gtk_tree_view_real_search_enable_popdown (gpointer data)
14268 {
14269   GtkTreeView *tree_view = (GtkTreeView *)data;
14270
14271   tree_view->priv->disable_popdown = 0;
14272
14273   return FALSE;
14274 }
14275
14276 static void
14277 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14278                                      gpointer   data)
14279 {
14280   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14281 }
14282
14283 static gboolean
14284 gtk_tree_view_search_delete_event (GtkWidget *widget,
14285                                    GdkEventAny *event,
14286                                    GtkTreeView *tree_view)
14287 {
14288   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14289
14290   gtk_tree_view_search_dialog_hide (widget, tree_view);
14291
14292   return TRUE;
14293 }
14294
14295 static gboolean
14296 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14297                                          GdkEventButton *event,
14298                                          GtkTreeView *tree_view)
14299 {
14300   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14301
14302   gtk_tree_view_search_dialog_hide (widget, tree_view);
14303
14304   if (event->window == tree_view->priv->bin_window)
14305     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14306
14307   return TRUE;
14308 }
14309
14310 static gboolean
14311 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14312                                    GdkEventScroll *event,
14313                                    GtkTreeView *tree_view)
14314 {
14315   gboolean retval = FALSE;
14316
14317   if (event->direction == GDK_SCROLL_UP)
14318     {
14319       gtk_tree_view_search_move (widget, tree_view, TRUE);
14320       retval = TRUE;
14321     }
14322   else if (event->direction == GDK_SCROLL_DOWN)
14323     {
14324       gtk_tree_view_search_move (widget, tree_view, FALSE);
14325       retval = TRUE;
14326     }
14327
14328   /* renew the flush timeout */
14329   if (retval && tree_view->priv->typeselect_flush_timeout
14330       && !tree_view->priv->search_custom_entry_set)
14331     {
14332       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14333       tree_view->priv->typeselect_flush_timeout =
14334         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14335                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14336                        tree_view);
14337     }
14338
14339   return retval;
14340 }
14341
14342 static gboolean
14343 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14344                                       GdkEventKey *event,
14345                                       GtkTreeView *tree_view)
14346 {
14347   gboolean retval = FALSE;
14348
14349   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14350   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14351
14352   /* close window and cancel the search */
14353   if (!tree_view->priv->search_custom_entry_set
14354       && (event->keyval == GDK_Escape ||
14355           event->keyval == GDK_Tab ||
14356             event->keyval == GDK_KP_Tab ||
14357             event->keyval == GDK_ISO_Left_Tab))
14358     {
14359       gtk_tree_view_search_dialog_hide (widget, tree_view);
14360       return TRUE;
14361     }
14362
14363   /* select previous matching iter */
14364   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
14365     {
14366       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14367         gtk_widget_error_bell (widget);
14368
14369       retval = TRUE;
14370     }
14371
14372   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
14373       && (event->keyval == GDK_g || event->keyval == GDK_G))
14374     {
14375       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14376         gtk_widget_error_bell (widget);
14377
14378       retval = TRUE;
14379     }
14380
14381   /* select next matching iter */
14382   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
14383     {
14384       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14385         gtk_widget_error_bell (widget);
14386
14387       retval = TRUE;
14388     }
14389
14390   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
14391       && (event->keyval == GDK_g || event->keyval == GDK_G))
14392     {
14393       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14394         gtk_widget_error_bell (widget);
14395
14396       retval = TRUE;
14397     }
14398
14399   /* renew the flush timeout */
14400   if (retval && tree_view->priv->typeselect_flush_timeout
14401       && !tree_view->priv->search_custom_entry_set)
14402     {
14403       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14404       tree_view->priv->typeselect_flush_timeout =
14405         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14406                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14407                        tree_view);
14408     }
14409
14410   return retval;
14411 }
14412
14413 /*  this function returns FALSE if there is a search string but
14414  *  nothing was found, and TRUE otherwise.
14415  */
14416 static gboolean
14417 gtk_tree_view_search_move (GtkWidget   *window,
14418                            GtkTreeView *tree_view,
14419                            gboolean     up)
14420 {
14421   gboolean ret;
14422   gint len;
14423   gint count = 0;
14424   const gchar *text;
14425   GtkTreeIter iter;
14426   GtkTreeModel *model;
14427   GtkTreeSelection *selection;
14428
14429   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14430
14431   g_return_val_if_fail (text != NULL, FALSE);
14432
14433   len = strlen (text);
14434
14435   if (up && tree_view->priv->selected_iter == 1)
14436     return strlen (text) < 1;
14437
14438   len = strlen (text);
14439
14440   if (len < 1)
14441     return TRUE;
14442
14443   model = gtk_tree_view_get_model (tree_view);
14444   selection = gtk_tree_view_get_selection (tree_view);
14445
14446   /* search */
14447   gtk_tree_selection_unselect_all (selection);
14448   if (!gtk_tree_model_get_iter_first (model, &iter))
14449     return TRUE;
14450
14451   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14452                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14453
14454   if (ret)
14455     {
14456       /* found */
14457       tree_view->priv->selected_iter += up?(-1):(1);
14458       return TRUE;
14459     }
14460   else
14461     {
14462       /* return to old iter */
14463       count = 0;
14464       gtk_tree_model_get_iter_first (model, &iter);
14465       gtk_tree_view_search_iter (model, selection,
14466                                  &iter, text,
14467                                  &count, tree_view->priv->selected_iter);
14468       return FALSE;
14469     }
14470 }
14471
14472 static gboolean
14473 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14474                                  gint          column,
14475                                  const gchar  *key,
14476                                  GtkTreeIter  *iter,
14477                                  gpointer      search_data)
14478 {
14479   gboolean retval = TRUE;
14480   const gchar *str;
14481   gchar *normalized_string;
14482   gchar *normalized_key;
14483   gchar *case_normalized_string = NULL;
14484   gchar *case_normalized_key = NULL;
14485   GValue value = {0,};
14486   GValue transformed = {0,};
14487
14488   gtk_tree_model_get_value (model, iter, column, &value);
14489
14490   g_value_init (&transformed, G_TYPE_STRING);
14491
14492   if (!g_value_transform (&value, &transformed))
14493     {
14494       g_value_unset (&value);
14495       return TRUE;
14496     }
14497
14498   g_value_unset (&value);
14499
14500   str = g_value_get_string (&transformed);
14501   if (!str)
14502     {
14503       g_value_unset (&transformed);
14504       return TRUE;
14505     }
14506
14507   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14508   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14509
14510   if (normalized_string && normalized_key)
14511     {
14512       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14513       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14514
14515       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14516         retval = FALSE;
14517     }
14518
14519   g_value_unset (&transformed);
14520   g_free (normalized_key);
14521   g_free (normalized_string);
14522   g_free (case_normalized_key);
14523   g_free (case_normalized_string);
14524
14525   return retval;
14526 }
14527
14528 static gboolean
14529 gtk_tree_view_search_iter (GtkTreeModel     *model,
14530                            GtkTreeSelection *selection,
14531                            GtkTreeIter      *iter,
14532                            const gchar      *text,
14533                            gint             *count,
14534                            gint              n)
14535 {
14536   GtkRBTree *tree = NULL;
14537   GtkRBNode *node = NULL;
14538   GtkTreePath *path;
14539
14540   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14541
14542   path = gtk_tree_model_get_path (model, iter);
14543   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14544
14545   do
14546     {
14547       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14548         {
14549           (*count)++;
14550           if (*count == n)
14551             {
14552               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14553                                             TRUE, 0.5, 0.0);
14554               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14555               gtk_tree_selection_select_iter (selection, iter);
14556
14557               if (path)
14558                 gtk_tree_path_free (path);
14559
14560               return TRUE;
14561             }
14562         }
14563
14564       if (node->children)
14565         {
14566           gboolean has_child;
14567           GtkTreeIter tmp;
14568
14569           tree = node->children;
14570           node = tree->root;
14571
14572           while (node->left != tree->nil)
14573             node = node->left;
14574
14575           tmp = *iter;
14576           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14577           gtk_tree_path_down (path);
14578
14579           /* sanity check */
14580           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14581         }
14582       else
14583         {
14584           gboolean done = FALSE;
14585
14586           do
14587             {
14588               node = _gtk_rbtree_next (tree, node);
14589
14590               if (node)
14591                 {
14592                   gboolean has_next;
14593
14594                   has_next = gtk_tree_model_iter_next (model, iter);
14595
14596                   done = TRUE;
14597                   gtk_tree_path_next (path);
14598
14599                   /* sanity check */
14600                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14601                 }
14602               else
14603                 {
14604                   gboolean has_parent;
14605                   GtkTreeIter tmp_iter = *iter;
14606
14607                   node = tree->parent_node;
14608                   tree = tree->parent_tree;
14609
14610                   if (!tree)
14611                     {
14612                       if (path)
14613                         gtk_tree_path_free (path);
14614
14615                       /* we've run out of tree, done with this func */
14616                       return FALSE;
14617                     }
14618
14619                   has_parent = gtk_tree_model_iter_parent (model,
14620                                                            iter,
14621                                                            &tmp_iter);
14622                   gtk_tree_path_up (path);
14623
14624                   /* sanity check */
14625                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14626                 }
14627             }
14628           while (!done);
14629         }
14630     }
14631   while (1);
14632
14633   return FALSE;
14634 }
14635
14636 static void
14637 gtk_tree_view_search_init (GtkWidget   *entry,
14638                            GtkTreeView *tree_view)
14639 {
14640   gint ret;
14641   gint len;
14642   gint count = 0;
14643   const gchar *text;
14644   GtkTreeIter iter;
14645   GtkTreeModel *model;
14646   GtkTreeSelection *selection;
14647
14648   g_return_if_fail (GTK_IS_ENTRY (entry));
14649   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14650
14651   text = gtk_entry_get_text (GTK_ENTRY (entry));
14652   len = strlen (text);
14653   model = gtk_tree_view_get_model (tree_view);
14654   selection = gtk_tree_view_get_selection (tree_view);
14655
14656   /* search */
14657   gtk_tree_selection_unselect_all (selection);
14658   if (tree_view->priv->typeselect_flush_timeout
14659       && !tree_view->priv->search_custom_entry_set)
14660     {
14661       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14662       tree_view->priv->typeselect_flush_timeout =
14663         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14664                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14665                        tree_view);
14666     }
14667
14668   if (len < 1)
14669     return;
14670
14671   if (!gtk_tree_model_get_iter_first (model, &iter))
14672     return;
14673
14674   ret = gtk_tree_view_search_iter (model, selection,
14675                                    &iter, text,
14676                                    &count, 1);
14677
14678   if (ret)
14679     tree_view->priv->selected_iter = 1;
14680 }
14681
14682 static void
14683 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14684                              GtkTreeView     *tree_view)
14685 {
14686   if (tree_view->priv->edited_column == NULL)
14687     return;
14688
14689   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14690   tree_view->priv->edited_column = NULL;
14691
14692   if (GTK_WIDGET_HAS_FOCUS (cell_editable))
14693     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14694
14695   g_signal_handlers_disconnect_by_func (cell_editable,
14696                                         gtk_tree_view_remove_widget,
14697                                         tree_view);
14698
14699   gtk_container_remove (GTK_CONTAINER (tree_view),
14700                         GTK_WIDGET (cell_editable));  
14701
14702   /* FIXME should only redraw a single node */
14703   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14704 }
14705
14706 static gboolean
14707 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14708                              GtkTreePath *cursor_path)
14709 {
14710   GtkTreeIter iter;
14711   GdkRectangle background_area;
14712   GdkRectangle cell_area;
14713   GtkCellEditable *editable_widget = NULL;
14714   gchar *path_string;
14715   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14716   gint retval = FALSE;
14717   GtkRBTree *cursor_tree;
14718   GtkRBNode *cursor_node;
14719
14720   g_assert (tree_view->priv->focus_column);
14721
14722   if (! GTK_WIDGET_REALIZED (tree_view))
14723     return FALSE;
14724
14725   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14726       cursor_node == NULL)
14727     return FALSE;
14728
14729   path_string = gtk_tree_path_to_string (cursor_path);
14730   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14731
14732   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14733
14734   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14735                                            tree_view->priv->model,
14736                                            &iter,
14737                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14738                                            cursor_node->children?TRUE:FALSE);
14739   gtk_tree_view_get_background_area (tree_view,
14740                                      cursor_path,
14741                                      tree_view->priv->focus_column,
14742                                      &background_area);
14743   gtk_tree_view_get_cell_area (tree_view,
14744                                cursor_path,
14745                                tree_view->priv->focus_column,
14746                                &cell_area);
14747
14748   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14749                                         &editable_widget,
14750                                         NULL,
14751                                         path_string,
14752                                         &background_area,
14753                                         &cell_area,
14754                                         flags))
14755     {
14756       retval = TRUE;
14757       if (editable_widget != NULL)
14758         {
14759           gint left, right;
14760           GdkRectangle area;
14761           GtkCellRenderer *cell;
14762
14763           area = cell_area;
14764           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14765
14766           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14767
14768           area.x += left;
14769           area.width -= right + left;
14770
14771           gtk_tree_view_real_start_editing (tree_view,
14772                                             tree_view->priv->focus_column,
14773                                             cursor_path,
14774                                             editable_widget,
14775                                             &area,
14776                                             NULL,
14777                                             flags);
14778         }
14779
14780     }
14781   g_free (path_string);
14782   return retval;
14783 }
14784
14785 static void
14786 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14787                                   GtkTreeViewColumn *column,
14788                                   GtkTreePath       *path,
14789                                   GtkCellEditable   *cell_editable,
14790                                   GdkRectangle      *cell_area,
14791                                   GdkEvent          *event,
14792                                   guint              flags)
14793 {
14794   gint pre_val = tree_view->priv->vadjustment->value;
14795   GtkRequisition requisition;
14796
14797   tree_view->priv->edited_column = column;
14798   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14799
14800   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14801   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14802
14803   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
14804
14805   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14806
14807   if (requisition.height < cell_area->height)
14808     {
14809       gint diff = cell_area->height - requisition.height;
14810       gtk_tree_view_put (tree_view,
14811                          GTK_WIDGET (cell_editable),
14812                          cell_area->x, cell_area->y + diff/2,
14813                          cell_area->width, requisition.height);
14814     }
14815   else
14816     {
14817       gtk_tree_view_put (tree_view,
14818                          GTK_WIDGET (cell_editable),
14819                          cell_area->x, cell_area->y,
14820                          cell_area->width, cell_area->height);
14821     }
14822
14823   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14824                                    (GdkEvent *)event);
14825
14826   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14827   g_signal_connect (cell_editable, "remove_widget",
14828                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14829 }
14830
14831 static void
14832 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14833                             gboolean     cancel_editing)
14834 {
14835   GtkTreeViewColumn *column;
14836   GtkCellRenderer *cell;
14837
14838   if (tree_view->priv->edited_column == NULL)
14839     return;
14840
14841   /*
14842    * This is very evil. We need to do this, because
14843    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14844    * later on. If gtk_tree_view_row_changed notices
14845    * tree_view->priv->edited_column != NULL, it'll call
14846    * gtk_tree_view_stop_editing again. Bad things will happen then.
14847    *
14848    * Please read that again if you intend to modify anything here.
14849    */
14850
14851   column = tree_view->priv->edited_column;
14852   tree_view->priv->edited_column = NULL;
14853
14854   cell = _gtk_tree_view_column_get_edited_cell (column);
14855   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14856
14857   if (!cancel_editing)
14858     gtk_cell_editable_editing_done (column->editable_widget);
14859
14860   tree_view->priv->edited_column = column;
14861
14862   gtk_cell_editable_remove_widget (column->editable_widget);
14863 }
14864
14865
14866 /**
14867  * gtk_tree_view_set_hover_selection:
14868  * @tree_view: a #GtkTreeView
14869  * @hover: %TRUE to enable hover selection mode
14870  *
14871  * Enables of disables the hover selection mode of @tree_view.
14872  * Hover selection makes the selected row follow the pointer.
14873  * Currently, this works only for the selection modes 
14874  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14875  * 
14876  * Since: 2.6
14877  **/
14878 void     
14879 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14880                                    gboolean     hover)
14881 {
14882   hover = hover != FALSE;
14883
14884   if (hover != tree_view->priv->hover_selection)
14885     {
14886       tree_view->priv->hover_selection = hover;
14887
14888       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14889     }
14890 }
14891
14892 /**
14893  * gtk_tree_view_get_hover_selection:
14894  * @tree_view: a #GtkTreeView
14895  * 
14896  * Returns whether hover selection mode is turned on for @tree_view.
14897  * 
14898  * Return value: %TRUE if @tree_view is in hover selection mode
14899  *
14900  * Since: 2.6 
14901  **/
14902 gboolean 
14903 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14904 {
14905   return tree_view->priv->hover_selection;
14906 }
14907
14908 /**
14909  * gtk_tree_view_set_hover_expand:
14910  * @tree_view: a #GtkTreeView
14911  * @expand: %TRUE to enable hover selection mode
14912  *
14913  * Enables of disables the hover expansion mode of @tree_view.
14914  * Hover expansion makes rows expand or collaps if the pointer 
14915  * moves over them.
14916  * 
14917  * Since: 2.6
14918  **/
14919 void     
14920 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14921                                 gboolean     expand)
14922 {
14923   expand = expand != FALSE;
14924
14925   if (expand != tree_view->priv->hover_expand)
14926     {
14927       tree_view->priv->hover_expand = expand;
14928
14929       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14930     }
14931 }
14932
14933 /**
14934  * gtk_tree_view_get_hover_expand:
14935  * @tree_view: a #GtkTreeView
14936  * 
14937  * Returns whether hover expansion mode is turned on for @tree_view.
14938  * 
14939  * Return value: %TRUE if @tree_view is in hover expansion mode
14940  *
14941  * Since: 2.6 
14942  **/
14943 gboolean 
14944 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14945 {
14946   return tree_view->priv->hover_expand;
14947 }
14948
14949 /**
14950  * gtk_tree_view_set_rubber_banding:
14951  * @tree_view: a #GtkTreeView
14952  * @enable: %TRUE to enable rubber banding
14953  *
14954  * Enables or disables rubber banding in @tree_view.  If the selection mode
14955  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14956  * multiple rows by dragging the mouse.
14957  * 
14958  * Since: 2.10
14959  **/
14960 void
14961 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
14962                                   gboolean     enable)
14963 {
14964   enable = enable != FALSE;
14965
14966   if (enable != tree_view->priv->rubber_banding_enable)
14967     {
14968       tree_view->priv->rubber_banding_enable = enable;
14969
14970       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
14971     }
14972 }
14973
14974 /**
14975  * gtk_tree_view_get_rubber_banding:
14976  * @tree_view: a #GtkTreeView
14977  * 
14978  * Returns whether rubber banding is turned on for @tree_view.  If the
14979  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
14980  * user to select multiple rows by dragging the mouse.
14981  * 
14982  * Return value: %TRUE if rubber banding in @tree_view is enabled.
14983  *
14984  * Since: 2.10
14985  **/
14986 gboolean
14987 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
14988 {
14989   return tree_view->priv->rubber_banding_enable;
14990 }
14991
14992 /**
14993  * gtk_tree_view_is_rubber_banding_active:
14994  * @tree_view: a #GtkTreeView
14995  * 
14996  * Returns whether a rubber banding operation is currently being done
14997  * in @tree_view.
14998  *
14999  * Return value: %TRUE if a rubber banding operation is currently being
15000  * done in @tree_view.
15001  *
15002  * Since: 2.12
15003  **/
15004 gboolean
15005 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15006 {
15007   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15008
15009   if (tree_view->priv->rubber_banding_enable
15010       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15011     return TRUE;
15012
15013   return FALSE;
15014 }
15015
15016 /**
15017  * gtk_tree_view_get_row_separator_func:
15018  * @tree_view: a #GtkTreeView
15019  * 
15020  * Returns the current row separator function.
15021  * 
15022  * Return value: the current row separator function.
15023  *
15024  * Since: 2.6
15025  **/
15026 GtkTreeViewRowSeparatorFunc 
15027 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15028 {
15029   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15030
15031   return tree_view->priv->row_separator_func;
15032 }
15033
15034 /**
15035  * gtk_tree_view_set_row_separator_func:
15036  * @tree_view: a #GtkTreeView
15037  * @func: a #GtkTreeViewRowSeparatorFunc
15038  * @data: user data to pass to @func, or %NULL
15039  * @destroy: destroy notifier for @data, or %NULL
15040  * 
15041  * Sets the row separator function, which is used to determine
15042  * whether a row should be drawn as a separator. If the row separator
15043  * function is %NULL, no separators are drawn. This is the default value.
15044  *
15045  * Since: 2.6
15046  **/
15047 void
15048 gtk_tree_view_set_row_separator_func (GtkTreeView                *tree_view,
15049                                       GtkTreeViewRowSeparatorFunc func,
15050                                       gpointer                    data,
15051                                       GtkDestroyNotify            destroy)
15052 {
15053   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15054
15055   if (tree_view->priv->row_separator_destroy)
15056     (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data);
15057
15058   tree_view->priv->row_separator_func = func;
15059   tree_view->priv->row_separator_data = data;
15060   tree_view->priv->row_separator_destroy = destroy;
15061 }
15062
15063   
15064 static void
15065 gtk_tree_view_grab_notify (GtkWidget *widget,
15066                            gboolean   was_grabbed)
15067 {
15068   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15069
15070   tree_view->priv->in_grab = !was_grabbed;
15071
15072   if (!was_grabbed)
15073     {
15074       tree_view->priv->pressed_button = -1;
15075
15076       if (tree_view->priv->rubber_band_status)
15077         gtk_tree_view_stop_rubber_band (tree_view);
15078     }
15079 }
15080
15081 static void
15082 gtk_tree_view_state_changed (GtkWidget      *widget,
15083                              GtkStateType    previous_state)
15084 {
15085   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15086
15087   if (GTK_WIDGET_REALIZED (widget))
15088     {
15089       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
15090       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
15091     }
15092
15093   gtk_widget_queue_draw (widget);
15094 }
15095
15096 /**
15097  * gtk_tree_view_get_grid_lines:
15098  * @tree_view: a #GtkTreeView
15099  *
15100  * Returns which grid lines are enabled in @tree_view.
15101  *
15102  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15103  * are enabled.
15104  *
15105  * Since: 2.10
15106  */
15107 GtkTreeViewGridLines
15108 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15109 {
15110   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15111
15112   return tree_view->priv->grid_lines;
15113 }
15114
15115 /**
15116  * gtk_tree_view_set_grid_lines:
15117  * @tree_view: a #GtkTreeView
15118  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15119  * enable.
15120  *
15121  * Sets which grid lines to draw in @tree_view.
15122  *
15123  * Since: 2.10
15124  */
15125 void
15126 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15127                               GtkTreeViewGridLines   grid_lines)
15128 {
15129   GtkTreeViewPrivate *priv;
15130   GtkWidget *widget;
15131   GtkTreeViewGridLines old_grid_lines;
15132
15133   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15134
15135   priv = tree_view->priv;
15136   widget = GTK_WIDGET (tree_view);
15137
15138   old_grid_lines = priv->grid_lines;
15139   priv->grid_lines = grid_lines;
15140   
15141   if (GTK_WIDGET_REALIZED (widget))
15142     {
15143       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15144           priv->grid_line_gc)
15145         {
15146           g_object_unref (priv->grid_line_gc);
15147           priv->grid_line_gc = NULL;
15148         }
15149       
15150       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15151           !priv->grid_line_gc)
15152         {
15153           gint line_width;
15154           guint8 *dash_list;
15155
15156           gtk_widget_style_get (widget,
15157                                 "grid-line-width", &line_width,
15158                                 "grid-line-pattern", (gchar *)&dash_list,
15159                                 NULL);
15160       
15161           priv->grid_line_gc = gdk_gc_new (widget->window);
15162           gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
15163           
15164           gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
15165                                       GDK_LINE_ON_OFF_DASH,
15166                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15167           gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
15168
15169           g_free (dash_list);
15170         }      
15171     }
15172
15173   if (old_grid_lines != grid_lines)
15174     {
15175       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15176       
15177       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15178     }
15179 }
15180
15181 /**
15182  * gtk_tree_view_get_enable_tree_lines:
15183  * @tree_view: a #GtkTreeView.
15184  *
15185  * Returns whether or not tree lines are drawn in @tree_view.
15186  *
15187  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15188  * otherwise.
15189  *
15190  * Since: 2.10
15191  */
15192 gboolean
15193 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15194 {
15195   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15196
15197   return tree_view->priv->tree_lines_enabled;
15198 }
15199
15200 /**
15201  * gtk_tree_view_set_enable_tree_lines:
15202  * @tree_view: a #GtkTreeView
15203  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15204  *
15205  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15206  * This does not have any visible effects for lists.
15207  *
15208  * Since: 2.10
15209  */
15210 void
15211 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15212                                      gboolean     enabled)
15213 {
15214   GtkTreeViewPrivate *priv;
15215   GtkWidget *widget;
15216   gboolean was_enabled;
15217
15218   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15219
15220   enabled = enabled != FALSE;
15221
15222   priv = tree_view->priv;
15223   widget = GTK_WIDGET (tree_view);
15224
15225   was_enabled = priv->tree_lines_enabled;
15226
15227   priv->tree_lines_enabled = enabled;
15228
15229   if (GTK_WIDGET_REALIZED (widget))
15230     {
15231       if (!enabled && priv->tree_line_gc)
15232         {
15233           g_object_unref (priv->tree_line_gc);
15234           priv->tree_line_gc = NULL;
15235         }
15236       
15237       if (enabled && !priv->tree_line_gc)
15238         {
15239           gint line_width;
15240           guint8 *dash_list;
15241           gtk_widget_style_get (widget,
15242                                 "tree-line-width", &line_width,
15243                                 "tree-line-pattern", (gchar *)&dash_list,
15244                                 NULL);
15245           
15246           priv->tree_line_gc = gdk_gc_new (widget->window);
15247           gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc);
15248           
15249           gdk_gc_set_line_attributes (priv->tree_line_gc, line_width,
15250                                       GDK_LINE_ON_OFF_DASH,
15251                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15252           gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2);
15253
15254           g_free (dash_list);
15255         }
15256     }
15257
15258   if (was_enabled != enabled)
15259     {
15260       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15261
15262       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15263     }
15264 }
15265
15266
15267 /**
15268  * gtk_tree_view_set_show_expanders:
15269  * @tree_view: a #GtkTreeView
15270  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15271  *
15272  * Sets whether to draw and enable expanders and indent child rows in
15273  * @tree_view.  When disabled there will be no expanders visible in trees
15274  * and there will be no way to expand and collapse rows by default.  Also
15275  * note that hiding the expanders will disable the default indentation.  You
15276  * can set a custom indentation in this case using
15277  * gtk_tree_view_set_level_indentation().
15278  * This does not have any visible effects for lists.
15279  *
15280  * Since: 2.12
15281  */
15282 void
15283 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15284                                   gboolean     enabled)
15285 {
15286   gboolean was_enabled;
15287
15288   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15289
15290   enabled = enabled != FALSE;
15291   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15292
15293   if (enabled)
15294     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15295   else
15296     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15297
15298   if (enabled != was_enabled)
15299     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15300 }
15301
15302 /**
15303  * gtk_tree_view_get_show_expanders:
15304  * @tree_view: a #GtkTreeView.
15305  *
15306  * Returns whether or not expanders are drawn in @tree_view.
15307  *
15308  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15309  * otherwise.
15310  *
15311  * Since: 2.12
15312  */
15313 gboolean
15314 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15315 {
15316   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15317
15318   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15319 }
15320
15321 /**
15322  * gtk_tree_view_set_level_indentation:
15323  * @tree_view: a #GtkTreeView
15324  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15325  *
15326  * Sets the amount of extra indentation for child levels to use in @tree_view
15327  * in addition to the default indentation.  The value should be specified in
15328  * pixels, a value of 0 disables this feature and in this case only the default
15329  * indentation will be used.
15330  * This does not have any visible effects for lists.
15331  *
15332  * Since: 2.12
15333  */
15334 void
15335 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15336                                      gint         indentation)
15337 {
15338   tree_view->priv->level_indentation = indentation;
15339
15340   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15341 }
15342
15343 /**
15344  * gtk_tree_view_get_level_indentation:
15345  * @tree_view: a #GtkTreeView.
15346  *
15347  * Returns the amount, in pixels, of extra indentation for child levels
15348  * in @tree_view.
15349  *
15350  * Return value: the amount of extra indentation for child levels in
15351  * @tree_view.  A return value of 0 means that this feature is disabled.
15352  *
15353  * Since: 2.12
15354  */
15355 gint
15356 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15357 {
15358   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15359
15360   return tree_view->priv->level_indentation;
15361 }
15362
15363 /**
15364  * gtk_tree_view_set_tooltip_row:
15365  * @tree_view: a #GtkTreeView
15366  * @tooltip: a #GtkTooltip
15367  * @path: a #GtkTreePath
15368  *
15369  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15370  * See also gtk_tooltip_set_tip_area().
15371  *
15372  * Since: 2.12
15373  */
15374 void
15375 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15376                                GtkTooltip  *tooltip,
15377                                GtkTreePath *path)
15378 {
15379   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15380   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15381
15382   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15383 }
15384
15385 /**
15386  * gtk_tree_view_set_tooltip_cell:
15387  * @tree_view: a #GtkTreeView
15388  * @tooltip: a #GtkTooltip
15389  * @path: a #GtkTreePath or %NULL
15390  * @column: a #GtkTreeViewColumn or %NULL
15391  * @cell: a #GtkCellRenderer or %NULL
15392  *
15393  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15394  * in common.  For example if @path is %NULL and @column is set, the tip
15395  * area will be set to the full area covered by @column.  See also
15396  * gtk_tooltip_set_tip_area().
15397  *
15398  * Note that if @path is not specified and @cell is set and part of a column
15399  * containing the expander, the tooltip might not show and hide at the correct
15400  * position.  In such cases @path must be set to the current node under the
15401  * mouse cursor for this function to operate correctly.
15402  *
15403  * Since: 2.12
15404  */
15405 void
15406 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15407                                 GtkTooltip        *tooltip,
15408                                 GtkTreePath       *path,
15409                                 GtkTreeViewColumn *column,
15410                                 GtkCellRenderer   *cell)
15411 {
15412   GdkRectangle rect;
15413
15414   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15415   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15416
15417   if (column)
15418     g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
15419
15420   if (cell)
15421     g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
15422
15423   /* Determine x values. */
15424   if (column && cell)
15425     {
15426       GdkRectangle tmp;
15427       gint start, width;
15428
15429       /* We always pass in path here, whether it is NULL or not.
15430        * For cells in expander columns path must be specified so that
15431        * we can correctly account for the indentation.  This also means
15432        * that the tooltip is constrained vertically by the "Determine y
15433        * values" code below; this is not a real problem since cells actually
15434        * don't stretch vertically in constrast to columns.
15435        */
15436       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15437       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15438
15439       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15440                                                          tmp.x + start, 0,
15441                                                          &rect.x, NULL);
15442       rect.width = width;
15443     }
15444   else if (column)
15445     {
15446       GdkRectangle tmp;
15447
15448       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15449       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15450                                                          tmp.x, 0,
15451                                                          &rect.x, NULL);
15452       rect.width = tmp.width;
15453     }
15454   else
15455     {
15456       rect.x = 0;
15457       rect.width = GTK_WIDGET (tree_view)->allocation.width;
15458     }
15459
15460   /* Determine y values. */
15461   if (path)
15462     {
15463       GdkRectangle tmp;
15464
15465       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15466       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15467                                                          0, tmp.y,
15468                                                          NULL, &rect.y);
15469       rect.height = tmp.height;
15470     }
15471   else
15472     {
15473       rect.y = 0;
15474       rect.height = tree_view->priv->vadjustment->page_size;
15475     }
15476
15477   gtk_tooltip_set_tip_area (tooltip, &rect);
15478 }
15479
15480 /**
15481  * gtk_tree_view_get_tooltip_context:
15482  * @tree_view: a #GtkTreeView
15483  * @x: the x coordinate (relative to widget coordinates)
15484  * @y: the y coordinate (relative to widget coordinates)
15485  * @keyboard_tip: whether this is a keyboard tooltip or not
15486  * @model: a pointer to receive a #GtkTreeModel or %NULL
15487  * @path: a pointer to receive a #GtkTreePath or %NULL
15488  * @iter: a pointer to receive a #GtkTreeIter or %NULL
15489  *
15490  * This function is supposed to be used in a #GtkWidget::query-tooltip
15491  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15492  * which are received in the signal handler, should be passed to this
15493  * function without modification.
15494  *
15495  * The return value indicates whether there is a tree view row at the given
15496  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15497  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15498  * @model, @path and @iter which have been provided will be set to point to
15499  * that row and the corresponding model.  @x and @y will always be converted
15500  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15501  *
15502  * Return value: whether or not the given tooltip context points to a row.
15503  *
15504  * Since: 2.12
15505  */
15506 gboolean
15507 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15508                                    gint          *x,
15509                                    gint          *y,
15510                                    gboolean       keyboard_tip,
15511                                    GtkTreeModel **model,
15512                                    GtkTreePath  **path,
15513                                    GtkTreeIter   *iter)
15514 {
15515   GtkTreePath *tmppath = NULL;
15516
15517   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15518   g_return_val_if_fail (x != NULL, FALSE);
15519   g_return_val_if_fail (y != NULL, FALSE);
15520
15521   if (keyboard_tip)
15522     {
15523       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15524
15525       if (!tmppath)
15526         return FALSE;
15527     }
15528   else
15529     {
15530       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15531                                                          x, y);
15532
15533       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15534                                           &tmppath, NULL, NULL, NULL))
15535         return FALSE;
15536     }
15537
15538   if (model)
15539     *model = gtk_tree_view_get_model (tree_view);
15540
15541   if (iter)
15542     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15543                              iter, tmppath);
15544
15545   if (path)
15546     *path = tmppath;
15547   else
15548     gtk_tree_path_free (tmppath);
15549
15550   return TRUE;
15551 }
15552
15553 static gboolean
15554 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15555                                     gint        x,
15556                                     gint        y,
15557                                     gboolean    keyboard_tip,
15558                                     GtkTooltip *tooltip,
15559                                     gpointer    data)
15560 {
15561   gchar *str;
15562   GtkTreeIter iter;
15563   GtkTreePath *path;
15564   GtkTreeModel *model;
15565   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15566
15567   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15568                                           &x, &y,
15569                                           keyboard_tip,
15570                                           &model, &path, &iter))
15571     return FALSE;
15572
15573   gtk_tree_model_get (model, &iter, tree_view->priv->tooltip_column, &str, -1);
15574
15575   if (!str)
15576     {
15577       gtk_tree_path_free (path);
15578       return FALSE;
15579     }
15580
15581   gtk_tooltip_set_markup (tooltip, str);
15582   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15583
15584   gtk_tree_path_free (path);
15585   g_free (str);
15586
15587   return TRUE;
15588 }
15589
15590 /**
15591  * gtk_tree_view_set_tooltip_column:
15592  * @tree_view: a #GtkTreeView
15593  * @column: an integer, which is a valid column number for @tree_view's model
15594  *
15595  * If you only plan to have simple (text-only) tooltips on full rows, you
15596  * can use this function to have #GtkTreeView handle these automatically
15597  * for you. @column should be set to the column in @tree_view's model
15598  * containing the tooltip texts, or -1 to disable this feature.
15599  *
15600  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15601  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15602  *
15603  * Since: 2.12
15604  */
15605 void
15606 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15607                                   gint         column)
15608 {
15609   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15610
15611   if (column == tree_view->priv->tooltip_column)
15612     return;
15613
15614   if (column == -1)
15615     {
15616       g_signal_handlers_disconnect_by_func (tree_view,
15617                                             gtk_tree_view_set_tooltip_query_cb,
15618                                             NULL);
15619       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15620     }
15621   else
15622     {
15623       if (tree_view->priv->tooltip_column == -1)
15624         {
15625           g_signal_connect (tree_view, "query-tooltip",
15626                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15627           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15628         }
15629     }
15630
15631   tree_view->priv->tooltip_column = column;
15632   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15633 }
15634
15635 /**
15636  * gtk_tree_view_get_tooltip_column:
15637  * @tree_view: a #GtkTreeView
15638  *
15639  * Returns the column of @tree_view's model which is being used for
15640  * displaying tooltips on @tree_view's rows.
15641  *
15642  * Return value: the index of the tooltip column that is currently being
15643  * used, or -1 if this is disabled.
15644  *
15645  * Since: 2.12
15646  */
15647 gint
15648 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15649 {
15650   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15651
15652   return tree_view->priv->tooltip_column;
15653 }
15654
15655 #define __GTK_TREE_VIEW_C__
15656 #include "gtkaliasdef.c"