]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Add GtkScrollable interface
[~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 <math.h>
23 #include <string.h>
24 #include <gdk/gdkkeysyms.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmain.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtkalignment.h"
36 #include "gtklabel.h"
37 #include "gtkhbox.h"
38 #include "gtkvbox.h"
39 #include "gtkarrow.h"
40 #include "gtkintl.h"
41 #include "gtkbindings.h"
42 #include "gtkcontainer.h"
43 #include "gtkentry.h"
44 #include "gtkframe.h"
45 #include "gtktreemodelsort.h"
46 #include "gtktooltip.h"
47 #include "gtkscrollable.h"
48 #include "gtkprivate.h"
49 #include "gtkwidgetprivate.h"
50
51 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
52 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
53 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
54 #define SCROLL_EDGE_SIZE 15
55 #define EXPANDER_EXTRA_PADDING 4
56 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
57 #define AUTO_EXPAND_TIMEOUT 500
58
59 /* The "background" areas of all rows/cells add up to cover the entire tree.
60  * The background includes all inter-row and inter-cell spacing.
61  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
62  * i.e. just the cells, no spacing.
63  */
64
65 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
66 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
67
68 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
69  * vice versa.
70  */
71 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
72 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
73
74 /* This is in bin_window coordinates */
75 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
76 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
77
78 #define ROW_HEIGHT(tree_view,height) \
79   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
80
81
82 typedef struct _GtkTreeViewChild GtkTreeViewChild;
83 struct _GtkTreeViewChild
84 {
85   GtkWidget *widget;
86   gint x;
87   gint y;
88   gint width;
89   gint height;
90 };
91
92
93 typedef struct _TreeViewDragInfo TreeViewDragInfo;
94 struct _TreeViewDragInfo
95 {
96   GdkModifierType start_button_mask;
97   GtkTargetList *_unused_source_target_list;
98   GdkDragAction source_actions;
99
100   GtkTargetList *_unused_dest_target_list;
101
102   guint source_set : 1;
103   guint dest_set : 1;
104 };
105
106
107 /* Signals */
108 enum
109 {
110   ROW_ACTIVATED,
111   TEST_EXPAND_ROW,
112   TEST_COLLAPSE_ROW,
113   ROW_EXPANDED,
114   ROW_COLLAPSED,
115   COLUMNS_CHANGED,
116   CURSOR_CHANGED,
117   MOVE_CURSOR,
118   SELECT_ALL,
119   UNSELECT_ALL,
120   SELECT_CURSOR_ROW,
121   TOGGLE_CURSOR_ROW,
122   EXPAND_COLLAPSE_CURSOR_ROW,
123   SELECT_CURSOR_PARENT,
124   START_INTERACTIVE_SEARCH,
125   LAST_SIGNAL
126 };
127
128 /* Properties */
129 enum {
130   PROP_0,
131   PROP_MODEL,
132   PROP_HADJUSTMENT,
133   PROP_VADJUSTMENT,
134   PROP_HEADERS_VISIBLE,
135   PROP_HEADERS_CLICKABLE,
136   PROP_EXPANDER_COLUMN,
137   PROP_REORDERABLE,
138   PROP_RULES_HINT,
139   PROP_ENABLE_SEARCH,
140   PROP_SEARCH_COLUMN,
141   PROP_FIXED_HEIGHT_MODE,
142   PROP_HOVER_SELECTION,
143   PROP_HOVER_EXPAND,
144   PROP_SHOW_EXPANDERS,
145   PROP_LEVEL_INDENTATION,
146   PROP_RUBBER_BANDING,
147   PROP_ENABLE_GRID_LINES,
148   PROP_ENABLE_TREE_LINES,
149   PROP_TOOLTIP_COLUMN,
150   PROP_MIN_DISPLAY_WIDTH,
151   PROP_MIN_DISPLAY_HEIGHT
152 };
153
154 /* object signals */
155 static void     gtk_tree_view_finalize             (GObject          *object);
156 static void     gtk_tree_view_set_property         (GObject         *object,
157                                                     guint            prop_id,
158                                                     const GValue    *value,
159                                                     GParamSpec      *pspec);
160 static void     gtk_tree_view_get_property         (GObject         *object,
161                                                     guint            prop_id,
162                                                     GValue          *value,
163                                                     GParamSpec      *pspec);
164
165 /* gtkwidget signals */
166 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
167 static void     gtk_tree_view_realize              (GtkWidget        *widget);
168 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
169 static void     gtk_tree_view_map                  (GtkWidget        *widget);
170 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
171                                                     GtkRequisition   *requisition);
172 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
173                                                     GtkAllocation    *allocation);
174 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
175                                                     cairo_t          *cr);
176 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
177                                                     GdkEventKey      *event);
178 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
179                                                     GdkEventKey      *event);
180 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
181                                                     GdkEventMotion   *event);
182 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
183                                                     GdkEventCrossing *event);
184 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
185                                                     GdkEventCrossing *event);
186 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
187                                                     GdkEventButton   *event);
188 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
189                                                     GdkEventButton   *event);
190 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
191                                                     GdkEventGrabBroken *event);
192 #if 0
193 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
194                                                     GdkEventConfigure *event);
195 #endif
196
197 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
198                                                     GtkWidget        *child);
199 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
200                                                     GdkEventFocus    *event);
201 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
202                                                     GtkDirectionType  direction);
203 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
204 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
205                                                     GtkStyle         *previous_style);
206 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
207                                                     gboolean          was_grabbed);
208 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
209                                                     GtkStateType      previous_state);
210
211 /* container signals */
212 static void     gtk_tree_view_remove               (GtkContainer     *container,
213                                                     GtkWidget        *widget);
214 static void     gtk_tree_view_forall               (GtkContainer     *container,
215                                                     gboolean          include_internals,
216                                                     GtkCallback       callback,
217                                                     gpointer          callback_data);
218
219 /* Source side drag signals */
220 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
221                                             GdkDragContext   *context);
222 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
223                                             GdkDragContext   *context);
224 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
225                                             GdkDragContext   *context,
226                                             GtkSelectionData *selection_data,
227                                             guint             info,
228                                             guint             time);
229 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
230                                             GdkDragContext   *context);
231
232 /* Target side drag signals */
233 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
234                                                   GdkDragContext   *context,
235                                                   guint             time);
236 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
237                                                   GdkDragContext   *context,
238                                                   gint              x,
239                                                   gint              y,
240                                                   guint             time);
241 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
242                                                   GdkDragContext   *context,
243                                                   gint              x,
244                                                   gint              y,
245                                                   guint             time);
246 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
247                                                   GdkDragContext   *context,
248                                                   gint              x,
249                                                   gint              y,
250                                                   GtkSelectionData *selection_data,
251                                                   guint             info,
252                                                   guint             time);
253
254 /* tree_model signals */
255 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
256                                                            GtkAdjustment   *adjustment);
257 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
258                                                            GtkAdjustment   *adjustment);
259 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
260                                                            GtkMovementStep  step,
261                                                            gint             count);
262 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
263 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
264 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
265                                                            gboolean         start_editing);
266 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
267 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
268                                                                gboolean         logical,
269                                                                gboolean         expand,
270                                                                gboolean         open_all);
271 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
272 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
273                                                            GtkTreePath     *path,
274                                                            GtkTreeIter     *iter,
275                                                            gpointer         data);
276 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
277                                                            GtkTreePath     *path,
278                                                            GtkTreeIter     *iter,
279                                                            gpointer         data);
280 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
281                                                            GtkTreePath     *path,
282                                                            GtkTreeIter     *iter,
283                                                            gpointer         data);
284 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
285                                                            GtkTreePath     *path,
286                                                            gpointer         data);
287 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
288                                                            GtkTreePath     *parent,
289                                                            GtkTreeIter     *iter,
290                                                            gint            *new_order,
291                                                            gpointer         data);
292
293 /* Incremental reflow */
294 static gboolean validate_row             (GtkTreeView *tree_view,
295                                           GtkRBTree   *tree,
296                                           GtkRBNode   *node,
297                                           GtkTreeIter *iter,
298                                           GtkTreePath *path);
299 static void     validate_visible_area    (GtkTreeView *tree_view);
300 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
301 static gboolean do_validate_rows         (GtkTreeView *tree_view,
302                                           gboolean     size_request);
303 static gboolean validate_rows            (GtkTreeView *tree_view);
304 static gboolean presize_handler_callback (gpointer     data);
305 static void     install_presize_handler  (GtkTreeView *tree_view);
306 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
307 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
308                                              GtkTreePath *path,
309                                              gint         offset);
310 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
311 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
312 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
313
314 /* Internal functions */
315 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
316                                                               GtkTreeViewColumn  *column);
317 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
318                                                               guint               keyval,
319                                                               guint               modmask,
320                                                               gboolean            add_shifted_binding,
321                                                               GtkMovementStep     step,
322                                                               gint                count);
323 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
324                                                               GtkRBTree          *tree);
325 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
326                                                               GtkTreePath        *path,
327                                                               const GdkRectangle *clip_rect);
328 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
329                                                               GtkRBTree          *tree,
330                                                               GtkRBNode          *node);
331 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
332                                                               cairo_t            *cr,
333                                                               GtkRBTree          *tree,
334                                                               GtkRBNode          *node,
335                                                               gint                x,
336                                                               gint                y);
337 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
338                                                               GtkRBTree          *tree,
339                                                               gint               *x1,
340                                                               gint               *x2);
341 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
342                                                               gint                i,
343                                                               gint               *x);
344 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
345                                                               GtkTreeView        *tree_view);
346 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
347                                                               GtkRBTree          *tree,
348                                                               GtkTreeIter        *iter,
349                                                               gint                depth,
350                                                               gboolean            recurse);
351 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
352                                                               GtkRBTree          *tree,
353                                                               GtkRBNode          *node);
354 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
355                                                               GtkTreeViewColumn  *column,
356                                                               gboolean            focus_to_cell);
357 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
358                                                               GdkEventMotion     *event);
359 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
360 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
361                                                               gint                count);
362 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
363                                                               gint                count);
364 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
365                                                               gint                count);
366 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
367                                                               gint                count);
368 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
369                                                               GtkTreePath        *path,
370                                                               GtkRBTree          *tree,
371                                                               GtkRBNode          *node,
372                                                               gboolean            animate);
373 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
374                                                               GtkTreePath        *path,
375                                                               GtkRBTree          *tree,
376                                                               GtkRBNode          *node,
377                                                               gboolean            open_all,
378                                                               gboolean            animate);
379 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
380                                                               GtkTreePath        *path,
381                                                               gboolean            clear_and_select,
382                                                               gboolean            clamp_node);
383 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
384 static void     column_sizing_notify                         (GObject            *object,
385                                                               GParamSpec         *pspec,
386                                                               gpointer            data);
387 static gboolean expand_collapse_timeout                      (gpointer            data);
388 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
389                                                               GtkRBTree          *tree,
390                                                               GtkRBNode          *node,
391                                                               gboolean            expand);
392 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
393 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
394 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
395 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
396 static void     update_prelight                              (GtkTreeView        *tree_view,
397                                                               int                 x,
398                                                               int                 y);
399
400 /* interactive search */
401 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
402 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
403                                                          GtkTreeView      *tree_view,
404                                                          GdkDevice        *device);
405 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
406                                                          GtkWidget        *search_dialog,
407                                                          gpointer          user_data);
408 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
409                                                          GtkMenu          *menu,
410                                                          gpointer          data);
411 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
412                                                          GtkTreeView      *tree_view);
413 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
414                                                          GtkTreeView      *tree_view);
415 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
416 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
417                                                          gpointer          data);
418 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
419                                                          GdkEventAny      *event,
420                                                          GtkTreeView      *tree_view);
421 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
422                                                          GdkEventButton   *event,
423                                                          GtkTreeView      *tree_view);
424 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
425                                                          GdkEventScroll   *event,
426                                                          GtkTreeView      *tree_view);
427 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
428                                                          GdkEventKey      *event,
429                                                          GtkTreeView      *tree_view);
430 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
431                                                          GtkTreeView      *tree_view,
432                                                          gboolean          up);
433 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
434                                                          gint              column,
435                                                          const gchar      *key,
436                                                          GtkTreeIter      *iter,
437                                                          gpointer          search_data);
438 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
439                                                          GtkTreeSelection *selection,
440                                                          GtkTreeIter      *iter,
441                                                          const gchar      *text,
442                                                          gint             *count,
443                                                          gint              n);
444 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
445                                                          GtkTreeView      *tree_view);
446 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
447                                                          GtkWidget        *child_widget,
448                                                          gint              x,
449                                                          gint              y,
450                                                          gint              width,
451                                                          gint              height);
452 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
453                                                          GtkTreePath      *cursor_path);
454 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
455                                               GtkTreeViewColumn *column,
456                                               GtkTreePath       *path,
457                                               GtkCellEditable   *cell_editable,
458                                               GdkRectangle      *cell_area,
459                                               GdkEvent          *event,
460                                               guint              flags);
461 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
462                                                          gboolean     cancel_editing);
463 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
464                                                              GdkDevice   *device,
465                                                              gboolean     keybinding);
466 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
467 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
468                                                          GtkTreeViewColumn *column,
469                                                          gint               drop_position);
470
471 /* GtkBuildable */
472 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
473                                                             GtkBuilder        *builder,
474                                                             GObject           *child,
475                                                             const gchar       *type);
476 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
477                                                             GtkBuilder        *builder,
478                                                             const gchar       *childname);
479 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
480
481
482 static gboolean scroll_row_timeout                   (gpointer     data);
483 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
484 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
485
486 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
487
488 \f
489
490 /* GType Methods
491  */
492
493 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
494                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
495                                                 gtk_tree_view_buildable_init)
496                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
497
498 static void
499 gtk_tree_view_class_init (GtkTreeViewClass *class)
500 {
501   GObjectClass *o_class;
502   GtkWidgetClass *widget_class;
503   GtkContainerClass *container_class;
504   GtkBindingSet *binding_set;
505
506   binding_set = gtk_binding_set_by_class (class);
507
508   o_class = (GObjectClass *) class;
509   widget_class = (GtkWidgetClass *) class;
510   container_class = (GtkContainerClass *) class;
511
512   /* GObject signals */
513   o_class->set_property = gtk_tree_view_set_property;
514   o_class->get_property = gtk_tree_view_get_property;
515   o_class->finalize = gtk_tree_view_finalize;
516
517   /* GtkWidget signals */
518   widget_class->destroy = gtk_tree_view_destroy;
519   widget_class->map = gtk_tree_view_map;
520   widget_class->realize = gtk_tree_view_realize;
521   widget_class->unrealize = gtk_tree_view_unrealize;
522   widget_class->size_request = gtk_tree_view_size_request;
523   widget_class->size_allocate = gtk_tree_view_size_allocate;
524   widget_class->button_press_event = gtk_tree_view_button_press;
525   widget_class->button_release_event = gtk_tree_view_button_release;
526   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
527   /*widget_class->configure_event = gtk_tree_view_configure;*/
528   widget_class->motion_notify_event = gtk_tree_view_motion;
529   widget_class->draw = gtk_tree_view_draw;
530   widget_class->key_press_event = gtk_tree_view_key_press;
531   widget_class->key_release_event = gtk_tree_view_key_release;
532   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
533   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
534   widget_class->focus_out_event = gtk_tree_view_focus_out;
535   widget_class->drag_begin = gtk_tree_view_drag_begin;
536   widget_class->drag_end = gtk_tree_view_drag_end;
537   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
538   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
539   widget_class->drag_leave = gtk_tree_view_drag_leave;
540   widget_class->drag_motion = gtk_tree_view_drag_motion;
541   widget_class->drag_drop = gtk_tree_view_drag_drop;
542   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
543   widget_class->focus = gtk_tree_view_focus;
544   widget_class->grab_focus = gtk_tree_view_grab_focus;
545   widget_class->style_set = gtk_tree_view_style_set;
546   widget_class->grab_notify = gtk_tree_view_grab_notify;
547   widget_class->state_changed = gtk_tree_view_state_changed;
548
549   /* GtkContainer signals */
550   container_class->remove = gtk_tree_view_remove;
551   container_class->forall = gtk_tree_view_forall;
552   container_class->set_focus_child = gtk_tree_view_set_focus_child;
553
554   class->move_cursor = gtk_tree_view_real_move_cursor;
555   class->select_all = gtk_tree_view_real_select_all;
556   class->unselect_all = gtk_tree_view_real_unselect_all;
557   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
558   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
559   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
560   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
561   class->start_interactive_search = gtk_tree_view_start_interactive_search;
562
563   /* Properties */
564
565   g_object_class_install_property (o_class,
566                                    PROP_MODEL,
567                                    g_param_spec_object ("model",
568                                                         P_("TreeView Model"),
569                                                         P_("The model for the tree view"),
570                                                         GTK_TYPE_TREE_MODEL,
571                                                         GTK_PARAM_READWRITE));
572
573   g_object_class_override_property (o_class, PROP_HADJUSTMENT, "hadjustment");
574   g_object_class_override_property (o_class, PROP_VADJUSTMENT, "vadjustment");
575   g_object_class_override_property (o_class, PROP_MIN_DISPLAY_WIDTH,  "min-display-width");
576   g_object_class_override_property (o_class, PROP_MIN_DISPLAY_HEIGHT, "min-display-height");
577
578   g_object_class_install_property (o_class,
579                                    PROP_HEADERS_VISIBLE,
580                                    g_param_spec_boolean ("headers-visible",
581                                                          P_("Headers Visible"),
582                                                          P_("Show the column header buttons"),
583                                                          TRUE,
584                                                          GTK_PARAM_READWRITE));
585
586   g_object_class_install_property (o_class,
587                                    PROP_HEADERS_CLICKABLE,
588                                    g_param_spec_boolean ("headers-clickable",
589                                                          P_("Headers Clickable"),
590                                                          P_("Column headers respond to click events"),
591                                                          TRUE,
592                                                          GTK_PARAM_READWRITE));
593
594   g_object_class_install_property (o_class,
595                                    PROP_EXPANDER_COLUMN,
596                                    g_param_spec_object ("expander-column",
597                                                         P_("Expander Column"),
598                                                         P_("Set the column for the expander column"),
599                                                         GTK_TYPE_TREE_VIEW_COLUMN,
600                                                         GTK_PARAM_READWRITE));
601
602   g_object_class_install_property (o_class,
603                                    PROP_REORDERABLE,
604                                    g_param_spec_boolean ("reorderable",
605                                                          P_("Reorderable"),
606                                                          P_("View is reorderable"),
607                                                          FALSE,
608                                                          GTK_PARAM_READWRITE));
609
610   g_object_class_install_property (o_class,
611                                    PROP_RULES_HINT,
612                                    g_param_spec_boolean ("rules-hint",
613                                                          P_("Rules Hint"),
614                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
615                                                          FALSE,
616                                                          GTK_PARAM_READWRITE));
617
618     g_object_class_install_property (o_class,
619                                      PROP_ENABLE_SEARCH,
620                                      g_param_spec_boolean ("enable-search",
621                                                            P_("Enable Search"),
622                                                            P_("View allows user to search through columns interactively"),
623                                                            TRUE,
624                                                            GTK_PARAM_READWRITE));
625
626     g_object_class_install_property (o_class,
627                                      PROP_SEARCH_COLUMN,
628                                      g_param_spec_int ("search-column",
629                                                        P_("Search Column"),
630                                                        P_("Model column to search through during interactive search"),
631                                                        -1,
632                                                        G_MAXINT,
633                                                        -1,
634                                                        GTK_PARAM_READWRITE));
635
636     /**
637      * GtkTreeView:fixed-height-mode:
638      *
639      * Setting the ::fixed-height-mode property to %TRUE speeds up 
640      * #GtkTreeView by assuming that all rows have the same height. 
641      * Only enable this option if all rows are the same height.  
642      * Please see gtk_tree_view_set_fixed_height_mode() for more 
643      * information on this option.
644      *
645      * Since: 2.4
646      **/
647     g_object_class_install_property (o_class,
648                                      PROP_FIXED_HEIGHT_MODE,
649                                      g_param_spec_boolean ("fixed-height-mode",
650                                                            P_("Fixed Height Mode"),
651                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
652                                                            FALSE,
653                                                            GTK_PARAM_READWRITE));
654     
655     /**
656      * GtkTreeView:hover-selection:
657      * 
658      * Enables or disables the hover selection mode of @tree_view.
659      * Hover selection makes the selected row follow the pointer.
660      * Currently, this works only for the selection modes 
661      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
662      *
663      * This mode is primarily intended for treeviews in popups, e.g.
664      * in #GtkComboBox or #GtkEntryCompletion.
665      *
666      * Since: 2.6
667      */
668     g_object_class_install_property (o_class,
669                                      PROP_HOVER_SELECTION,
670                                      g_param_spec_boolean ("hover-selection",
671                                                            P_("Hover Selection"),
672                                                            P_("Whether the selection should follow the pointer"),
673                                                            FALSE,
674                                                            GTK_PARAM_READWRITE));
675
676     /**
677      * GtkTreeView:hover-expand:
678      * 
679      * Enables or disables the hover expansion mode of @tree_view.
680      * Hover expansion makes rows expand or collapse if the pointer moves 
681      * over them.
682      *
683      * This mode is primarily intended for treeviews in popups, e.g.
684      * in #GtkComboBox or #GtkEntryCompletion.
685      *
686      * Since: 2.6
687      */
688     g_object_class_install_property (o_class,
689                                      PROP_HOVER_EXPAND,
690                                      g_param_spec_boolean ("hover-expand",
691                                                            P_("Hover Expand"),
692                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
693                                                            FALSE,
694                                                            GTK_PARAM_READWRITE));
695
696     /**
697      * GtkTreeView:show-expanders:
698      *
699      * %TRUE if the view has expanders.
700      *
701      * Since: 2.12
702      */
703     g_object_class_install_property (o_class,
704                                      PROP_SHOW_EXPANDERS,
705                                      g_param_spec_boolean ("show-expanders",
706                                                            P_("Show Expanders"),
707                                                            P_("View has expanders"),
708                                                            TRUE,
709                                                            GTK_PARAM_READWRITE));
710
711     /**
712      * GtkTreeView:level-indentation:
713      *
714      * Extra indentation for each level.
715      *
716      * Since: 2.12
717      */
718     g_object_class_install_property (o_class,
719                                      PROP_LEVEL_INDENTATION,
720                                      g_param_spec_int ("level-indentation",
721                                                        P_("Level Indentation"),
722                                                        P_("Extra indentation for each level"),
723                                                        0,
724                                                        G_MAXINT,
725                                                        0,
726                                                        GTK_PARAM_READWRITE));
727
728     g_object_class_install_property (o_class,
729                                      PROP_RUBBER_BANDING,
730                                      g_param_spec_boolean ("rubber-banding",
731                                                            P_("Rubber Banding"),
732                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
733                                                            FALSE,
734                                                            GTK_PARAM_READWRITE));
735
736     g_object_class_install_property (o_class,
737                                      PROP_ENABLE_GRID_LINES,
738                                      g_param_spec_enum ("enable-grid-lines",
739                                                         P_("Enable Grid Lines"),
740                                                         P_("Whether grid lines should be drawn in the tree view"),
741                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
742                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
743                                                         GTK_PARAM_READWRITE));
744
745     g_object_class_install_property (o_class,
746                                      PROP_ENABLE_TREE_LINES,
747                                      g_param_spec_boolean ("enable-tree-lines",
748                                                            P_("Enable Tree Lines"),
749                                                            P_("Whether tree lines should be drawn in the tree view"),
750                                                            FALSE,
751                                                            GTK_PARAM_READWRITE));
752
753     g_object_class_install_property (o_class,
754                                      PROP_TOOLTIP_COLUMN,
755                                      g_param_spec_int ("tooltip-column",
756                                                        P_("Tooltip Column"),
757                                                        P_("The column in the model containing the tooltip texts for the rows"),
758                                                        -1,
759                                                        G_MAXINT,
760                                                        -1,
761                                                        GTK_PARAM_READWRITE));
762
763   /* Style properties */
764 #define _TREE_VIEW_EXPANDER_SIZE 12
765 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
766 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
767
768   gtk_widget_class_install_style_property (widget_class,
769                                            g_param_spec_int ("expander-size",
770                                                              P_("Expander Size"),
771                                                              P_("Size of the expander arrow"),
772                                                              0,
773                                                              G_MAXINT,
774                                                              _TREE_VIEW_EXPANDER_SIZE,
775                                                              GTK_PARAM_READABLE));
776
777   gtk_widget_class_install_style_property (widget_class,
778                                            g_param_spec_int ("vertical-separator",
779                                                              P_("Vertical Separator Width"),
780                                                              P_("Vertical space between cells.  Must be an even number"),
781                                                              0,
782                                                              G_MAXINT,
783                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
784                                                              GTK_PARAM_READABLE));
785
786   gtk_widget_class_install_style_property (widget_class,
787                                            g_param_spec_int ("horizontal-separator",
788                                                              P_("Horizontal Separator Width"),
789                                                              P_("Horizontal space between cells.  Must be an even number"),
790                                                              0,
791                                                              G_MAXINT,
792                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
793                                                              GTK_PARAM_READABLE));
794
795   gtk_widget_class_install_style_property (widget_class,
796                                            g_param_spec_boolean ("allow-rules",
797                                                                  P_("Allow Rules"),
798                                                                  P_("Allow drawing of alternating color rows"),
799                                                                  TRUE,
800                                                                  GTK_PARAM_READABLE));
801
802   gtk_widget_class_install_style_property (widget_class,
803                                            g_param_spec_boolean ("indent-expanders",
804                                                                  P_("Indent Expanders"),
805                                                                  P_("Make the expanders indented"),
806                                                                  TRUE,
807                                                                  GTK_PARAM_READABLE));
808
809   gtk_widget_class_install_style_property (widget_class,
810                                            g_param_spec_boxed ("even-row-color",
811                                                                P_("Even Row Color"),
812                                                                P_("Color to use for even rows"),
813                                                                GDK_TYPE_COLOR,
814                                                                GTK_PARAM_READABLE));
815
816   gtk_widget_class_install_style_property (widget_class,
817                                            g_param_spec_boxed ("odd-row-color",
818                                                                P_("Odd Row Color"),
819                                                                P_("Color to use for odd rows"),
820                                                                GDK_TYPE_COLOR,
821                                                                GTK_PARAM_READABLE));
822
823   gtk_widget_class_install_style_property (widget_class,
824                                            g_param_spec_int ("grid-line-width",
825                                                              P_("Grid line width"),
826                                                              P_("Width, in pixels, of the tree view grid lines"),
827                                                              0, G_MAXINT, 1,
828                                                              GTK_PARAM_READABLE));
829
830   gtk_widget_class_install_style_property (widget_class,
831                                            g_param_spec_int ("tree-line-width",
832                                                              P_("Tree line width"),
833                                                              P_("Width, in pixels, of the tree view lines"),
834                                                              0, G_MAXINT, 1,
835                                                              GTK_PARAM_READABLE));
836
837   gtk_widget_class_install_style_property (widget_class,
838                                            g_param_spec_string ("grid-line-pattern",
839                                                                 P_("Grid line pattern"),
840                                                                 P_("Dash pattern used to draw the tree view grid lines"),
841                                                                 "\1\1",
842                                                                 GTK_PARAM_READABLE));
843
844   gtk_widget_class_install_style_property (widget_class,
845                                            g_param_spec_string ("tree-line-pattern",
846                                                                 P_("Tree line pattern"),
847                                                                 P_("Dash pattern used to draw the tree view lines"),
848                                                                 "\1\1",
849                                                                 GTK_PARAM_READABLE));
850
851   /* Signals */
852   /**
853    * GtkTreeView::row-activated:
854    * @tree_view: the object on which the signal is emitted
855    * @path: the #GtkTreePath for the activated row
856    * @column: the #GtkTreeViewColumn in which the activation occurred
857    *
858    * The "row-activated" signal is emitted when the method
859    * gtk_tree_view_row_activated() is called or the user double clicks 
860    * a treeview row. It is also emitted when a non-editable row is 
861    * selected and one of the keys: Space, Shift+Space, Return or 
862    * Enter is pressed.
863    * 
864    * For selection handling refer to the <link linkend="TreeWidget">tree 
865    * widget conceptual overview</link> as well as #GtkTreeSelection.
866    */
867   tree_view_signals[ROW_ACTIVATED] =
868     g_signal_new (I_("row-activated"),
869                   G_TYPE_FROM_CLASS (o_class),
870                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
871                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
872                   NULL, NULL,
873                   _gtk_marshal_VOID__BOXED_OBJECT,
874                   G_TYPE_NONE, 2,
875                   GTK_TYPE_TREE_PATH,
876                   GTK_TYPE_TREE_VIEW_COLUMN);
877
878   /**
879    * GtkTreeView::test-expand-row:
880    * @tree_view: the object on which the signal is emitted
881    * @iter: the tree iter of the row to expand
882    * @path: a tree path that points to the row 
883    * 
884    * The given row is about to be expanded (show its children nodes). Use this
885    * signal if you need to control the expandability of individual rows.
886    *
887    * Returns: %FALSE to allow expansion, %TRUE to reject
888    */
889   tree_view_signals[TEST_EXPAND_ROW] =
890     g_signal_new (I_("test-expand-row"),
891                   G_TYPE_FROM_CLASS (o_class),
892                   G_SIGNAL_RUN_LAST,
893                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
894                   _gtk_boolean_handled_accumulator, NULL,
895                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
896                   G_TYPE_BOOLEAN, 2,
897                   GTK_TYPE_TREE_ITER,
898                   GTK_TYPE_TREE_PATH);
899
900   /**
901    * GtkTreeView::test-collapse-row:
902    * @tree_view: the object on which the signal is emitted
903    * @iter: the tree iter of the row to collapse
904    * @path: a tree path that points to the row 
905    * 
906    * The given row is about to be collapsed (hide its children nodes). Use this
907    * signal if you need to control the collapsibility of individual rows.
908    *
909    * Returns: %FALSE to allow collapsing, %TRUE to reject
910    */
911   tree_view_signals[TEST_COLLAPSE_ROW] =
912     g_signal_new (I_("test-collapse-row"),
913                   G_TYPE_FROM_CLASS (o_class),
914                   G_SIGNAL_RUN_LAST,
915                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
916                   _gtk_boolean_handled_accumulator, NULL,
917                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
918                   G_TYPE_BOOLEAN, 2,
919                   GTK_TYPE_TREE_ITER,
920                   GTK_TYPE_TREE_PATH);
921
922   /**
923    * GtkTreeView::row-expanded:
924    * @tree_view: the object on which the signal is emitted
925    * @iter: the tree iter of the expanded row
926    * @path: a tree path that points to the row 
927    * 
928    * The given row has been expanded (child nodes are shown).
929    */
930   tree_view_signals[ROW_EXPANDED] =
931     g_signal_new (I_("row-expanded"),
932                   G_TYPE_FROM_CLASS (o_class),
933                   G_SIGNAL_RUN_LAST,
934                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
935                   NULL, NULL,
936                   _gtk_marshal_VOID__BOXED_BOXED,
937                   G_TYPE_NONE, 2,
938                   GTK_TYPE_TREE_ITER,
939                   GTK_TYPE_TREE_PATH);
940
941   /**
942    * GtkTreeView::row-collapsed:
943    * @tree_view: the object on which the signal is emitted
944    * @iter: the tree iter of the collapsed row
945    * @path: a tree path that points to the row 
946    * 
947    * The given row has been collapsed (child nodes are hidden).
948    */
949   tree_view_signals[ROW_COLLAPSED] =
950     g_signal_new (I_("row-collapsed"),
951                   G_TYPE_FROM_CLASS (o_class),
952                   G_SIGNAL_RUN_LAST,
953                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
954                   NULL, NULL,
955                   _gtk_marshal_VOID__BOXED_BOXED,
956                   G_TYPE_NONE, 2,
957                   GTK_TYPE_TREE_ITER,
958                   GTK_TYPE_TREE_PATH);
959
960   /**
961    * GtkTreeView::columns-changed:
962    * @tree_view: the object on which the signal is emitted 
963    * 
964    * The number of columns of the treeview has changed.
965    */
966   tree_view_signals[COLUMNS_CHANGED] =
967     g_signal_new (I_("columns-changed"),
968                   G_TYPE_FROM_CLASS (o_class),
969                   G_SIGNAL_RUN_LAST,
970                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
971                   NULL, NULL,
972                   _gtk_marshal_VOID__VOID,
973                   G_TYPE_NONE, 0);
974
975   /**
976    * GtkTreeView::cursor-changed:
977    * @tree_view: the object on which the signal is emitted
978    * 
979    * The position of the cursor (focused cell) has changed.
980    */
981   tree_view_signals[CURSOR_CHANGED] =
982     g_signal_new (I_("cursor-changed"),
983                   G_TYPE_FROM_CLASS (o_class),
984                   G_SIGNAL_RUN_LAST,
985                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
986                   NULL, NULL,
987                   _gtk_marshal_VOID__VOID,
988                   G_TYPE_NONE, 0);
989
990   tree_view_signals[MOVE_CURSOR] =
991     g_signal_new (I_("move-cursor"),
992                   G_TYPE_FROM_CLASS (o_class),
993                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
994                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
995                   NULL, NULL,
996                   _gtk_marshal_BOOLEAN__ENUM_INT,
997                   G_TYPE_BOOLEAN, 2,
998                   GTK_TYPE_MOVEMENT_STEP,
999                   G_TYPE_INT);
1000
1001   tree_view_signals[SELECT_ALL] =
1002     g_signal_new (I_("select-all"),
1003                   G_TYPE_FROM_CLASS (o_class),
1004                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1005                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1006                   NULL, NULL,
1007                   _gtk_marshal_BOOLEAN__VOID,
1008                   G_TYPE_BOOLEAN, 0);
1009
1010   tree_view_signals[UNSELECT_ALL] =
1011     g_signal_new (I_("unselect-all"),
1012                   G_TYPE_FROM_CLASS (o_class),
1013                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1014                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1015                   NULL, NULL,
1016                   _gtk_marshal_BOOLEAN__VOID,
1017                   G_TYPE_BOOLEAN, 0);
1018
1019   tree_view_signals[SELECT_CURSOR_ROW] =
1020     g_signal_new (I_("select-cursor-row"),
1021                   G_TYPE_FROM_CLASS (o_class),
1022                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1023                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1024                   NULL, NULL,
1025                   _gtk_marshal_BOOLEAN__BOOLEAN,
1026                   G_TYPE_BOOLEAN, 1,
1027                   G_TYPE_BOOLEAN);
1028
1029   tree_view_signals[TOGGLE_CURSOR_ROW] =
1030     g_signal_new (I_("toggle-cursor-row"),
1031                   G_TYPE_FROM_CLASS (o_class),
1032                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1033                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1034                   NULL, NULL,
1035                   _gtk_marshal_BOOLEAN__VOID,
1036                   G_TYPE_BOOLEAN, 0);
1037
1038   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1039     g_signal_new (I_("expand-collapse-cursor-row"),
1040                   G_TYPE_FROM_CLASS (o_class),
1041                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1042                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1043                   NULL, NULL,
1044                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1045                   G_TYPE_BOOLEAN, 3,
1046                   G_TYPE_BOOLEAN,
1047                   G_TYPE_BOOLEAN,
1048                   G_TYPE_BOOLEAN);
1049
1050   tree_view_signals[SELECT_CURSOR_PARENT] =
1051     g_signal_new (I_("select-cursor-parent"),
1052                   G_TYPE_FROM_CLASS (o_class),
1053                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1054                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1055                   NULL, NULL,
1056                   _gtk_marshal_BOOLEAN__VOID,
1057                   G_TYPE_BOOLEAN, 0);
1058
1059   tree_view_signals[START_INTERACTIVE_SEARCH] =
1060     g_signal_new (I_("start-interactive-search"),
1061                   G_TYPE_FROM_CLASS (o_class),
1062                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1063                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1064                   NULL, NULL,
1065                   _gtk_marshal_BOOLEAN__VOID,
1066                   G_TYPE_BOOLEAN, 0);
1067
1068   /* Key bindings */
1069   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1070                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1071   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1072                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1073
1074   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1075                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1076   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1077                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1078
1079   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1080                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1081
1082   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1083                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1084
1085   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1086                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1087   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1088                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1089
1090   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1091                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1092   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1093                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1094
1095   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1096                                   GTK_MOVEMENT_PAGES, -1);
1097   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1098                                   GTK_MOVEMENT_PAGES, -1);
1099
1100   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1101                                   GTK_MOVEMENT_PAGES, 1);
1102   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1103                                   GTK_MOVEMENT_PAGES, 1);
1104
1105
1106   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1107                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1108                                 G_TYPE_INT, 1);
1109
1110   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1111                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1112                                 G_TYPE_INT, -1);
1113
1114   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1115                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1116                                 G_TYPE_INT, 1);
1117
1118   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1119                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1120                                 G_TYPE_INT, -1);
1121
1122   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1123                                 "move-cursor", 2,
1124                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1125                                 G_TYPE_INT, 1);
1126
1127   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1128                                 "move-cursor", 2,
1129                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1130                                 G_TYPE_INT, -1);
1131
1132   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1133                                 "move-cursor", 2,
1134                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1135                                 G_TYPE_INT, 1);
1136
1137   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1138                                 "move-cursor", 2,
1139                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1140                                 G_TYPE_INT, -1);
1141
1142   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1143   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1144
1145   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1146   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1147
1148   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1149   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1150
1151   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1152                                 G_TYPE_BOOLEAN, TRUE);
1153   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1154                                 G_TYPE_BOOLEAN, TRUE);
1155
1156   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1157                                 G_TYPE_BOOLEAN, TRUE);
1158   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1159                                 G_TYPE_BOOLEAN, TRUE);
1160   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1161                                 G_TYPE_BOOLEAN, TRUE);
1162   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1163                                 G_TYPE_BOOLEAN, TRUE);
1164   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1165                                 G_TYPE_BOOLEAN, TRUE);
1166
1167   /* expand and collapse rows */
1168   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1169                                 G_TYPE_BOOLEAN, TRUE,
1170                                 G_TYPE_BOOLEAN, TRUE,
1171                                 G_TYPE_BOOLEAN, FALSE);
1172
1173   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1174                                 "expand-collapse-cursor-row", 3,
1175                                 G_TYPE_BOOLEAN, TRUE,
1176                                 G_TYPE_BOOLEAN, TRUE,
1177                                 G_TYPE_BOOLEAN, TRUE);
1178   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1179                                 "expand-collapse-cursor-row", 3,
1180                                 G_TYPE_BOOLEAN, TRUE,
1181                                 G_TYPE_BOOLEAN, TRUE,
1182                                 G_TYPE_BOOLEAN, TRUE);
1183
1184   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1185                                 "expand-collapse-cursor-row", 3,
1186                                 G_TYPE_BOOLEAN, TRUE,
1187                                 G_TYPE_BOOLEAN, FALSE,
1188                                 G_TYPE_BOOLEAN, FALSE);
1189   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1190                                 "expand-collapse-cursor-row", 3,
1191                                 G_TYPE_BOOLEAN, TRUE,
1192                                 G_TYPE_BOOLEAN, FALSE,
1193                                 G_TYPE_BOOLEAN, FALSE);
1194
1195   /* Not doable on US keyboards */
1196   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1197                                 G_TYPE_BOOLEAN, TRUE,
1198                                 G_TYPE_BOOLEAN, TRUE,
1199                                 G_TYPE_BOOLEAN, TRUE);
1200   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1201                                 G_TYPE_BOOLEAN, TRUE,
1202                                 G_TYPE_BOOLEAN, TRUE,
1203                                 G_TYPE_BOOLEAN, FALSE);
1204   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1205                                 G_TYPE_BOOLEAN, TRUE,
1206                                 G_TYPE_BOOLEAN, TRUE,
1207                                 G_TYPE_BOOLEAN, TRUE);
1208   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1209                                 G_TYPE_BOOLEAN, TRUE,
1210                                 G_TYPE_BOOLEAN, TRUE,
1211                                 G_TYPE_BOOLEAN, TRUE);
1212   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1213                                 "expand-collapse-cursor-row", 3,
1214                                 G_TYPE_BOOLEAN, FALSE,
1215                                 G_TYPE_BOOLEAN, TRUE,
1216                                 G_TYPE_BOOLEAN, TRUE);
1217   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1218                                 "expand-collapse-cursor-row", 3,
1219                                 G_TYPE_BOOLEAN, FALSE,
1220                                 G_TYPE_BOOLEAN, TRUE,
1221                                 G_TYPE_BOOLEAN, TRUE);
1222   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1223                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1224                                 "expand-collapse-cursor-row", 3,
1225                                 G_TYPE_BOOLEAN, FALSE,
1226                                 G_TYPE_BOOLEAN, TRUE,
1227                                 G_TYPE_BOOLEAN, TRUE);
1228   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1229                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1230                                 "expand-collapse-cursor-row", 3,
1231                                 G_TYPE_BOOLEAN, FALSE,
1232                                 G_TYPE_BOOLEAN, TRUE,
1233                                 G_TYPE_BOOLEAN, TRUE);
1234
1235   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1236                                 G_TYPE_BOOLEAN, TRUE,
1237                                 G_TYPE_BOOLEAN, FALSE,
1238                                 G_TYPE_BOOLEAN, FALSE);
1239   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1240                                 G_TYPE_BOOLEAN, TRUE,
1241                                 G_TYPE_BOOLEAN, FALSE,
1242                                 G_TYPE_BOOLEAN, TRUE);
1243   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1244                                 G_TYPE_BOOLEAN, TRUE,
1245                                 G_TYPE_BOOLEAN, FALSE,
1246                                 G_TYPE_BOOLEAN, FALSE);
1247   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1248                                 G_TYPE_BOOLEAN, TRUE,
1249                                 G_TYPE_BOOLEAN, FALSE,
1250                                 G_TYPE_BOOLEAN, TRUE);
1251   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1252                                 "expand-collapse-cursor-row", 3,
1253                                 G_TYPE_BOOLEAN, FALSE,
1254                                 G_TYPE_BOOLEAN, FALSE,
1255                                 G_TYPE_BOOLEAN, TRUE);
1256   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1257                                 "expand-collapse-cursor-row", 3,
1258                                 G_TYPE_BOOLEAN, FALSE,
1259                                 G_TYPE_BOOLEAN, FALSE,
1260                                 G_TYPE_BOOLEAN, TRUE);
1261   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1262                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1263                                 "expand-collapse-cursor-row", 3,
1264                                 G_TYPE_BOOLEAN, FALSE,
1265                                 G_TYPE_BOOLEAN, FALSE,
1266                                 G_TYPE_BOOLEAN, TRUE);
1267   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1268                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1269                                 "expand-collapse-cursor-row", 3,
1270                                 G_TYPE_BOOLEAN, FALSE,
1271                                 G_TYPE_BOOLEAN, FALSE,
1272                                 G_TYPE_BOOLEAN, TRUE);
1273
1274   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1275   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1276
1277   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1278
1279   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1280
1281   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1282 }
1283
1284 static void
1285 gtk_tree_view_init (GtkTreeView *tree_view)
1286 {
1287   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1288
1289   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1290   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1291
1292   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1293                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1294                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1295
1296   /* We need some padding */
1297   tree_view->priv->dy = 0;
1298   tree_view->priv->cursor_offset = 0;
1299   tree_view->priv->n_columns = 0;
1300   tree_view->priv->header_height = 1;
1301   tree_view->priv->x_drag = 0;
1302   tree_view->priv->drag_pos = -1;
1303   tree_view->priv->header_has_focus = FALSE;
1304   tree_view->priv->pressed_button = -1;
1305   tree_view->priv->press_start_x = -1;
1306   tree_view->priv->press_start_y = -1;
1307   tree_view->priv->reorderable = FALSE;
1308   tree_view->priv->presize_handler_timer = 0;
1309   tree_view->priv->scroll_sync_timer = 0;
1310   tree_view->priv->fixed_height = -1;
1311   tree_view->priv->fixed_height_mode = FALSE;
1312   tree_view->priv->fixed_height_check = 0;
1313   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1314   tree_view->priv->enable_search = TRUE;
1315   tree_view->priv->search_column = -1;
1316   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1317   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1318   tree_view->priv->search_custom_entry_set = FALSE;
1319   tree_view->priv->typeselect_flush_timeout = 0;
1320   tree_view->priv->init_hadjust_value = TRUE;    
1321   tree_view->priv->width = 0;
1322           
1323   tree_view->priv->hover_selection = FALSE;
1324   tree_view->priv->hover_expand = FALSE;
1325
1326   tree_view->priv->level_indentation = 0;
1327
1328   tree_view->priv->rubber_banding_enable = FALSE;
1329
1330   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1331   tree_view->priv->tree_lines_enabled = FALSE;
1332
1333   tree_view->priv->tooltip_column = -1;
1334
1335   tree_view->priv->post_validation_flag = FALSE;
1336
1337   tree_view->priv->last_button_x = -1;
1338   tree_view->priv->last_button_y = -1;
1339
1340   tree_view->priv->event_last_x = -10000;
1341   tree_view->priv->event_last_y = -10000;
1342
1343   tree_view->priv->min_display_width  = -1;
1344   tree_view->priv->min_display_height = -1;
1345 }
1346
1347 \f
1348
1349 /* GObject Methods
1350  */
1351
1352 static void
1353 gtk_tree_view_set_property (GObject         *object,
1354                             guint            prop_id,
1355                             const GValue    *value,
1356                             GParamSpec      *pspec)
1357 {
1358   GtkTreeView *tree_view;
1359
1360   tree_view = GTK_TREE_VIEW (object);
1361
1362   switch (prop_id)
1363     {
1364     case PROP_MODEL:
1365       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1366       break;
1367     case PROP_HADJUSTMENT:
1368       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1369       break;
1370     case PROP_VADJUSTMENT:
1371       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1372       break;
1373     case PROP_HEADERS_VISIBLE:
1374       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1375       break;
1376     case PROP_HEADERS_CLICKABLE:
1377       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1378       break;
1379     case PROP_EXPANDER_COLUMN:
1380       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1381       break;
1382     case PROP_REORDERABLE:
1383       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1384       break;
1385     case PROP_RULES_HINT:
1386       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1387       break;
1388     case PROP_ENABLE_SEARCH:
1389       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1390       break;
1391     case PROP_SEARCH_COLUMN:
1392       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1393       break;
1394     case PROP_FIXED_HEIGHT_MODE:
1395       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1396       break;
1397     case PROP_HOVER_SELECTION:
1398       tree_view->priv->hover_selection = g_value_get_boolean (value);
1399       break;
1400     case PROP_HOVER_EXPAND:
1401       tree_view->priv->hover_expand = g_value_get_boolean (value);
1402       break;
1403     case PROP_SHOW_EXPANDERS:
1404       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1405       break;
1406     case PROP_LEVEL_INDENTATION:
1407       tree_view->priv->level_indentation = g_value_get_int (value);
1408       break;
1409     case PROP_RUBBER_BANDING:
1410       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1411       break;
1412     case PROP_ENABLE_GRID_LINES:
1413       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1414       break;
1415     case PROP_ENABLE_TREE_LINES:
1416       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1417       break;
1418     case PROP_TOOLTIP_COLUMN:
1419       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1420       break;
1421     case PROP_MIN_DISPLAY_WIDTH:
1422       tree_view->priv->min_display_width = g_value_get_int (value);
1423       break;
1424     case PROP_MIN_DISPLAY_HEIGHT:
1425       tree_view->priv->min_display_height = g_value_get_int (value);
1426       break;
1427     default:
1428       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1429       break;
1430     }
1431 }
1432
1433 static void
1434 gtk_tree_view_get_property (GObject    *object,
1435                             guint       prop_id,
1436                             GValue     *value,
1437                             GParamSpec *pspec)
1438 {
1439   GtkTreeView *tree_view;
1440
1441   tree_view = GTK_TREE_VIEW (object);
1442
1443   switch (prop_id)
1444     {
1445     case PROP_MODEL:
1446       g_value_set_object (value, tree_view->priv->model);
1447       break;
1448     case PROP_HADJUSTMENT:
1449       g_value_set_object (value, tree_view->priv->hadjustment);
1450       break;
1451     case PROP_VADJUSTMENT:
1452       g_value_set_object (value, tree_view->priv->vadjustment);
1453       break;
1454     case PROP_HEADERS_VISIBLE:
1455       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1456       break;
1457     case PROP_HEADERS_CLICKABLE:
1458       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1459       break;
1460     case PROP_EXPANDER_COLUMN:
1461       g_value_set_object (value, tree_view->priv->expander_column);
1462       break;
1463     case PROP_REORDERABLE:
1464       g_value_set_boolean (value, tree_view->priv->reorderable);
1465       break;
1466     case PROP_RULES_HINT:
1467       g_value_set_boolean (value, tree_view->priv->has_rules);
1468       break;
1469     case PROP_ENABLE_SEARCH:
1470       g_value_set_boolean (value, tree_view->priv->enable_search);
1471       break;
1472     case PROP_SEARCH_COLUMN:
1473       g_value_set_int (value, tree_view->priv->search_column);
1474       break;
1475     case PROP_FIXED_HEIGHT_MODE:
1476       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1477       break;
1478     case PROP_HOVER_SELECTION:
1479       g_value_set_boolean (value, tree_view->priv->hover_selection);
1480       break;
1481     case PROP_HOVER_EXPAND:
1482       g_value_set_boolean (value, tree_view->priv->hover_expand);
1483       break;
1484     case PROP_SHOW_EXPANDERS:
1485       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1486       break;
1487     case PROP_LEVEL_INDENTATION:
1488       g_value_set_int (value, tree_view->priv->level_indentation);
1489       break;
1490     case PROP_RUBBER_BANDING:
1491       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1492       break;
1493     case PROP_ENABLE_GRID_LINES:
1494       g_value_set_enum (value, tree_view->priv->grid_lines);
1495       break;
1496     case PROP_ENABLE_TREE_LINES:
1497       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1498       break;
1499     case PROP_TOOLTIP_COLUMN:
1500       g_value_set_int (value, tree_view->priv->tooltip_column);
1501       break;
1502     case PROP_MIN_DISPLAY_WIDTH:
1503       g_value_set_int (value, tree_view->priv->min_display_width);
1504       break;
1505     case PROP_MIN_DISPLAY_HEIGHT:
1506       g_value_set_int (value, tree_view->priv->min_display_height);
1507       break;
1508     default:
1509       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1510       break;
1511     }
1512 }
1513
1514 static void
1515 gtk_tree_view_finalize (GObject *object)
1516 {
1517   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1518 }
1519
1520
1521 static GtkBuildableIface *parent_buildable_iface;
1522
1523 static void
1524 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1525 {
1526   parent_buildable_iface = g_type_interface_peek_parent (iface);
1527   iface->add_child = gtk_tree_view_buildable_add_child;
1528   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1529 }
1530
1531 static void
1532 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1533                                    GtkBuilder  *builder,
1534                                    GObject     *child,
1535                                    const gchar *type)
1536 {
1537   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1538 }
1539
1540 static GObject *
1541 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1542                                             GtkBuilder        *builder,
1543                                             const gchar       *childname)
1544 {
1545     if (strcmp (childname, "selection") == 0)
1546       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1547     
1548     return parent_buildable_iface->get_internal_child (buildable,
1549                                                        builder,
1550                                                        childname);
1551 }
1552
1553 /* GtkWidget Methods
1554  */
1555
1556 static void
1557 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1558 {
1559   _gtk_rbtree_free (tree_view->priv->tree);
1560   
1561   tree_view->priv->tree = NULL;
1562   tree_view->priv->button_pressed_node = NULL;
1563   tree_view->priv->button_pressed_tree = NULL;
1564   tree_view->priv->prelight_tree = NULL;
1565   tree_view->priv->prelight_node = NULL;
1566   tree_view->priv->expanded_collapsed_node = NULL;
1567   tree_view->priv->expanded_collapsed_tree = NULL;
1568 }
1569
1570 static void
1571 gtk_tree_view_destroy (GtkWidget *widget)
1572 {
1573   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1574   GList *list;
1575
1576   gtk_tree_view_stop_editing (tree_view, TRUE);
1577
1578   if (tree_view->priv->columns != NULL)
1579     {
1580       list = tree_view->priv->columns;
1581       while (list)
1582         {
1583           GtkTreeViewColumn *column;
1584           column = GTK_TREE_VIEW_COLUMN (list->data);
1585           list = list->next;
1586           gtk_tree_view_remove_column (tree_view, column);
1587         }
1588       tree_view->priv->columns = NULL;
1589     }
1590
1591   if (tree_view->priv->tree != NULL)
1592     {
1593       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1594
1595       gtk_tree_view_free_rbtree (tree_view);
1596     }
1597
1598   if (tree_view->priv->selection != NULL)
1599     {
1600       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1601       g_object_unref (tree_view->priv->selection);
1602       tree_view->priv->selection = NULL;
1603     }
1604
1605   if (tree_view->priv->scroll_to_path != NULL)
1606     {
1607       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1608       tree_view->priv->scroll_to_path = NULL;
1609     }
1610
1611   if (tree_view->priv->drag_dest_row != NULL)
1612     {
1613       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1614       tree_view->priv->drag_dest_row = NULL;
1615     }
1616
1617   if (tree_view->priv->top_row != NULL)
1618     {
1619       gtk_tree_row_reference_free (tree_view->priv->top_row);
1620       tree_view->priv->top_row = NULL;
1621     }
1622
1623   if (tree_view->priv->column_drop_func_data &&
1624       tree_view->priv->column_drop_func_data_destroy)
1625     {
1626       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1627       tree_view->priv->column_drop_func_data = NULL;
1628     }
1629
1630   if (tree_view->priv->destroy_count_destroy &&
1631       tree_view->priv->destroy_count_data)
1632     {
1633       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1634       tree_view->priv->destroy_count_data = NULL;
1635     }
1636
1637   gtk_tree_row_reference_free (tree_view->priv->cursor);
1638   tree_view->priv->cursor = NULL;
1639
1640   gtk_tree_row_reference_free (tree_view->priv->anchor);
1641   tree_view->priv->anchor = NULL;
1642
1643   /* destroy interactive search dialog */
1644   if (tree_view->priv->search_window)
1645     {
1646       gtk_widget_destroy (tree_view->priv->search_window);
1647       tree_view->priv->search_window = NULL;
1648       tree_view->priv->search_entry = NULL;
1649       if (tree_view->priv->typeselect_flush_timeout)
1650         {
1651           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1652           tree_view->priv->typeselect_flush_timeout = 0;
1653         }
1654     }
1655
1656   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1657     {
1658       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1659       tree_view->priv->search_user_data = NULL;
1660     }
1661
1662   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1663     {
1664       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1665       tree_view->priv->search_position_user_data = NULL;
1666     }
1667
1668   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1669     {
1670       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1671       tree_view->priv->row_separator_data = NULL;
1672     }
1673   
1674   gtk_tree_view_set_model (tree_view, NULL);
1675
1676   if (tree_view->priv->hadjustment)
1677     {
1678       g_object_unref (tree_view->priv->hadjustment);
1679       tree_view->priv->hadjustment = NULL;
1680     }
1681   if (tree_view->priv->vadjustment)
1682     {
1683       g_object_unref (tree_view->priv->vadjustment);
1684       tree_view->priv->vadjustment = NULL;
1685     }
1686
1687   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
1688 }
1689
1690 /* GtkWidget::map helper */
1691 static void
1692 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1693 {
1694   GList *list;
1695
1696   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
1697
1698   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1699     {
1700       GtkTreeViewColumn *column;
1701
1702       for (list = tree_view->priv->columns; list; list = list->next)
1703         {
1704           column = list->data;
1705           if (gtk_widget_get_visible (column->button) &&
1706               !gtk_widget_get_mapped (column->button))
1707             gtk_widget_map (column->button);
1708         }
1709       for (list = tree_view->priv->columns; list; list = list->next)
1710         {
1711           column = list->data;
1712           if (column->visible == FALSE)
1713             continue;
1714           if (column->resizable)
1715             {
1716               gdk_window_raise (column->window);
1717               gdk_window_show (column->window);
1718             }
1719           else
1720             gdk_window_hide (column->window);
1721         }
1722       gdk_window_show (tree_view->priv->header_window);
1723     }
1724 }
1725
1726 static void
1727 gtk_tree_view_map (GtkWidget *widget)
1728 {
1729   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1730   GList *tmp_list;
1731
1732   gtk_widget_set_mapped (widget, TRUE);
1733
1734   tmp_list = tree_view->priv->children;
1735   while (tmp_list)
1736     {
1737       GtkTreeViewChild *child = tmp_list->data;
1738       tmp_list = tmp_list->next;
1739
1740       if (gtk_widget_get_visible (child->widget))
1741         {
1742           if (!gtk_widget_get_mapped (child->widget))
1743             gtk_widget_map (child->widget);
1744         }
1745     }
1746   gdk_window_show (tree_view->priv->bin_window);
1747
1748   gtk_tree_view_map_buttons (tree_view);
1749
1750   gdk_window_show (gtk_widget_get_window (widget));
1751 }
1752
1753 static void
1754 gtk_tree_view_realize (GtkWidget *widget)
1755 {
1756   GtkAllocation allocation;
1757   GtkStyle *style;
1758   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1759   GdkWindow *window;
1760   GdkWindowAttr attributes;
1761   GList *tmp_list;
1762   gint attributes_mask;
1763
1764   gtk_widget_set_realized (widget, TRUE);
1765
1766   gtk_widget_get_allocation (widget, &allocation);
1767
1768   /* Make the main, clipping window */
1769   attributes.window_type = GDK_WINDOW_CHILD;
1770   attributes.x = allocation.x;
1771   attributes.y = allocation.y;
1772   attributes.width = allocation.width;
1773   attributes.height = allocation.height;
1774   attributes.wclass = GDK_INPUT_OUTPUT;
1775   attributes.visual = gtk_widget_get_visual (widget);
1776   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1777
1778   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1779
1780   window = gdk_window_new (gtk_widget_get_parent_window (widget),
1781                            &attributes, attributes_mask);
1782   gtk_widget_set_window (widget, window);
1783   gdk_window_set_user_data (window, widget);
1784
1785   gtk_widget_get_allocation (widget, &allocation);
1786
1787   /* Make the window for the tree */
1788   attributes.x = 0;
1789   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1790   attributes.width = MAX (tree_view->priv->width, allocation.width);
1791   attributes.height = allocation.height;
1792   attributes.event_mask = (GDK_EXPOSURE_MASK |
1793                            GDK_SCROLL_MASK |
1794                            GDK_POINTER_MOTION_MASK |
1795                            GDK_ENTER_NOTIFY_MASK |
1796                            GDK_LEAVE_NOTIFY_MASK |
1797                            GDK_BUTTON_PRESS_MASK |
1798                            GDK_BUTTON_RELEASE_MASK |
1799                            gtk_widget_get_events (widget));
1800
1801   tree_view->priv->bin_window = gdk_window_new (window,
1802                                                 &attributes, attributes_mask);
1803   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1804
1805   gtk_widget_get_allocation (widget, &allocation);
1806
1807   /* Make the column header window */
1808   attributes.x = 0;
1809   attributes.y = 0;
1810   attributes.width = MAX (tree_view->priv->width, allocation.width);
1811   attributes.height = tree_view->priv->header_height;
1812   attributes.event_mask = (GDK_EXPOSURE_MASK |
1813                            GDK_SCROLL_MASK |
1814                            GDK_ENTER_NOTIFY_MASK |
1815                            GDK_LEAVE_NOTIFY_MASK |
1816                            GDK_BUTTON_PRESS_MASK |
1817                            GDK_BUTTON_RELEASE_MASK |
1818                            GDK_KEY_PRESS_MASK |
1819                            GDK_KEY_RELEASE_MASK |
1820                            gtk_widget_get_events (widget));
1821
1822   tree_view->priv->header_window = gdk_window_new (window,
1823                                                    &attributes, attributes_mask);
1824   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1825
1826   /* Add them all up. */
1827   gtk_widget_style_attach (widget);
1828   style = gtk_widget_get_style (widget);
1829   gdk_window_set_background (tree_view->priv->bin_window,
1830                              &style->base[gtk_widget_get_state (widget)]);
1831   gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1832
1833   tmp_list = tree_view->priv->children;
1834   while (tmp_list)
1835     {
1836       GtkTreeViewChild *child = tmp_list->data;
1837       tmp_list = tmp_list->next;
1838
1839       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1840     }
1841
1842   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1843     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1844
1845   /* Need to call those here, since they create GCs */
1846   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1847   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1848
1849   install_presize_handler (tree_view); 
1850 }
1851
1852 static void
1853 gtk_tree_view_unrealize (GtkWidget *widget)
1854 {
1855   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1856   GtkTreeViewPrivate *priv = tree_view->priv;
1857   GList *list;
1858
1859   if (priv->scroll_timeout != 0)
1860     {
1861       g_source_remove (priv->scroll_timeout);
1862       priv->scroll_timeout = 0;
1863     }
1864
1865   if (priv->auto_expand_timeout != 0)
1866     {
1867       g_source_remove (priv->auto_expand_timeout);
1868       priv->auto_expand_timeout = 0;
1869     }
1870
1871   if (priv->open_dest_timeout != 0)
1872     {
1873       g_source_remove (priv->open_dest_timeout);
1874       priv->open_dest_timeout = 0;
1875     }
1876
1877   remove_expand_collapse_timeout (tree_view);
1878   
1879   if (priv->presize_handler_timer != 0)
1880     {
1881       g_source_remove (priv->presize_handler_timer);
1882       priv->presize_handler_timer = 0;
1883     }
1884
1885   if (priv->validate_rows_timer != 0)
1886     {
1887       g_source_remove (priv->validate_rows_timer);
1888       priv->validate_rows_timer = 0;
1889     }
1890
1891   if (priv->scroll_sync_timer != 0)
1892     {
1893       g_source_remove (priv->scroll_sync_timer);
1894       priv->scroll_sync_timer = 0;
1895     }
1896
1897   if (priv->typeselect_flush_timeout)
1898     {
1899       g_source_remove (priv->typeselect_flush_timeout);
1900       priv->typeselect_flush_timeout = 0;
1901     }
1902   
1903   for (list = priv->columns; list; list = list->next)
1904     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1905
1906   gdk_window_set_user_data (priv->bin_window, NULL);
1907   gdk_window_destroy (priv->bin_window);
1908   priv->bin_window = NULL;
1909
1910   gdk_window_set_user_data (priv->header_window, NULL);
1911   gdk_window_destroy (priv->header_window);
1912   priv->header_window = NULL;
1913
1914   if (priv->drag_window)
1915     {
1916       gdk_window_set_user_data (priv->drag_window, NULL);
1917       gdk_window_destroy (priv->drag_window);
1918       priv->drag_window = NULL;
1919     }
1920
1921   if (priv->drag_highlight_window)
1922     {
1923       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1924       gdk_window_destroy (priv->drag_highlight_window);
1925       priv->drag_highlight_window = NULL;
1926     }
1927
1928   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1929 }
1930
1931 /* GtkWidget::size_request helper */
1932 static void
1933 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1934 {
1935   GList *list;
1936
1937   tree_view->priv->header_height = 0;
1938
1939   if (tree_view->priv->model)
1940     {
1941       for (list = tree_view->priv->columns; list; list = list->next)
1942         {
1943           GtkRequisition requisition;
1944           GtkTreeViewColumn *column = list->data;
1945
1946           if (column->button == NULL)
1947             continue;
1948
1949           column = list->data;
1950
1951           gtk_widget_get_preferred_size (column->button, &requisition, NULL);
1952           column->button_request = requisition.width;
1953           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1954         }
1955     }
1956 }
1957
1958
1959 /* Called only by ::size_request */
1960 static void
1961 gtk_tree_view_update_size (GtkTreeView *tree_view)
1962 {
1963   GList *list;
1964   GtkTreeViewColumn *column;
1965   gint i;
1966
1967   if (tree_view->priv->model == NULL)
1968     {
1969       tree_view->priv->width = 0;
1970       tree_view->priv->prev_width = 0;                   
1971       tree_view->priv->height = 0;
1972       return;
1973     }
1974
1975   tree_view->priv->prev_width = tree_view->priv->width;  
1976   tree_view->priv->width = 0;
1977
1978   /* keep this in sync with size_allocate below */
1979   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1980     {
1981       gint real_requested_width = 0;
1982       column = list->data;
1983       if (!column->visible)
1984         continue;
1985
1986       if (column->use_resized_width)
1987         {
1988           real_requested_width = column->resized_width;
1989         }
1990       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1991         {
1992           real_requested_width = column->fixed_width;
1993         }
1994       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1995         {
1996           real_requested_width = MAX (column->requested_width, column->button_request);
1997         }
1998       else
1999         {
2000           real_requested_width = column->requested_width;
2001         }
2002
2003       if (column->min_width != -1)
2004         real_requested_width = MAX (real_requested_width, column->min_width);
2005       if (column->max_width != -1)
2006         real_requested_width = MIN (real_requested_width, column->max_width);
2007
2008       tree_view->priv->width += real_requested_width;
2009     }
2010
2011   if (tree_view->priv->tree == NULL)
2012     tree_view->priv->height = 0;
2013   else
2014     tree_view->priv->height = tree_view->priv->tree->root->offset;
2015 }
2016
2017 static void
2018 gtk_tree_view_size_request (GtkWidget      *widget,
2019                             GtkRequisition *requisition)
2020 {
2021   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2022   GList *tmp_list;
2023
2024   /* we validate some rows initially just to make sure we have some size. 
2025    * In practice, with a lot of static lists, this should get a good width.
2026    */
2027   do_validate_rows (tree_view, FALSE);
2028   gtk_tree_view_size_request_columns (tree_view);
2029   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2030
2031   requisition->width = tree_view->priv->width;
2032   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2033
2034   tmp_list = tree_view->priv->children;
2035
2036   while (tmp_list)
2037     {
2038       GtkTreeViewChild *child = tmp_list->data;
2039       GtkRequisition child_requisition;
2040
2041       tmp_list = tmp_list->next;
2042
2043       if (gtk_widget_get_visible (child->widget))
2044         gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
2045     }
2046 }
2047
2048 static int
2049 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2050 {
2051   int width = 0;
2052   GList *list;
2053   gboolean rtl;
2054
2055   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2056   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2057        list->data != tree_view->priv->expander_column;
2058        list = (rtl ? list->prev : list->next))
2059     {
2060       GtkTreeViewColumn *column = list->data;
2061
2062       width += column->width;
2063     }
2064
2065   return width;
2066 }
2067
2068 static void
2069 invalidate_column (GtkTreeView       *tree_view,
2070                    GtkTreeViewColumn *column)
2071 {
2072   gint column_offset = 0;
2073   GList *list;
2074   GtkWidget *widget = GTK_WIDGET (tree_view);
2075   gboolean rtl;
2076
2077   if (!gtk_widget_get_realized (widget))
2078     return;
2079
2080   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2081   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2082        list;
2083        list = (rtl ? list->prev : list->next))
2084     {
2085       GtkTreeViewColumn *tmpcolumn = list->data;
2086       if (tmpcolumn == column)
2087         {
2088           GtkAllocation allocation;
2089           GdkRectangle invalid_rect;
2090
2091           gtk_widget_get_allocation (widget, &allocation);
2092           invalid_rect.x = column_offset;
2093           invalid_rect.y = 0;
2094           invalid_rect.width = column->width;
2095           invalid_rect.height = allocation.height;
2096
2097           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2098           break;
2099         }
2100       
2101       column_offset += tmpcolumn->width;
2102     }
2103 }
2104
2105 static void
2106 invalidate_last_column (GtkTreeView *tree_view)
2107 {
2108   GList *last_column;
2109   gboolean rtl;
2110
2111   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2112
2113   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2114        last_column;
2115        last_column = (rtl ? last_column->next : last_column->prev))
2116     {
2117       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2118         {
2119           invalidate_column (tree_view, last_column->data);
2120           return;
2121         }
2122     }
2123 }
2124
2125 static gint
2126 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2127                                                     GtkTreeViewColumn *column)
2128 {
2129   gint real_requested_width;
2130
2131   if (column->use_resized_width)
2132     {
2133       real_requested_width = column->resized_width;
2134     }
2135   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2136     {
2137       real_requested_width = column->fixed_width;
2138     }
2139   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2140     {
2141       real_requested_width = MAX (column->requested_width, column->button_request);
2142     }
2143   else
2144     {
2145       real_requested_width = column->requested_width;
2146       if (real_requested_width < 0)
2147         real_requested_width = 0;
2148     }
2149
2150   if (column->min_width != -1)
2151     real_requested_width = MAX (real_requested_width, column->min_width);
2152   if (column->max_width != -1)
2153     real_requested_width = MIN (real_requested_width, column->max_width);
2154
2155   return real_requested_width;
2156 }
2157
2158 /* GtkWidget::size_allocate helper */
2159 static void
2160 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2161                                      gboolean  *width_changed)
2162 {
2163   GtkTreeView *tree_view;
2164   GList *list, *first_column, *last_column;
2165   GtkTreeViewColumn *column;
2166   GtkAllocation allocation;
2167   GtkAllocation widget_allocation;
2168   gint width = 0;
2169   gint extra, extra_per_column, extra_for_last;
2170   gint full_requested_width = 0;
2171   gint number_of_expand_columns = 0;
2172   gboolean column_changed = FALSE;
2173   gboolean rtl;
2174   gboolean update_expand;
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   /* Only update the expand value if the width of the widget has changed,
2210    * or the number of expand columns has changed, or if there are no expand
2211    * columns, or if we didn't have an size-allocation yet after the
2212    * last validated node.
2213    */
2214   update_expand = (width_changed && *width_changed == TRUE)
2215       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2216       || number_of_expand_columns == 0
2217       || tree_view->priv->post_validation_flag == TRUE;
2218
2219   tree_view->priv->post_validation_flag = FALSE;
2220
2221   gtk_widget_get_allocation (widget, &widget_allocation);
2222   if (!update_expand)
2223     {
2224       extra = tree_view->priv->last_extra_space;
2225       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2226     }
2227   else
2228     {
2229       extra = MAX (widget_allocation.width - full_requested_width, 0);
2230       extra_for_last = 0;
2231
2232       tree_view->priv->last_extra_space = extra;
2233     }
2234
2235   if (number_of_expand_columns > 0)
2236     extra_per_column = extra/number_of_expand_columns;
2237   else
2238     extra_per_column = 0;
2239
2240   if (update_expand)
2241     {
2242       tree_view->priv->last_extra_space_per_column = extra_per_column;
2243       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2244     }
2245
2246   for (list = (rtl ? last_column : first_column); 
2247        list != (rtl ? first_column->prev : last_column->next);
2248        list = (rtl ? list->prev : list->next)) 
2249     {
2250       gint real_requested_width = 0;
2251       gint old_width;
2252
2253       column = list->data;
2254       old_width = column->width;
2255
2256       if (!column->visible)
2257         continue;
2258
2259       /* We need to handle the dragged button specially.
2260        */
2261       if (column == tree_view->priv->drag_column)
2262         {
2263           GtkAllocation drag_allocation;
2264
2265           drag_allocation.x = 0;
2266           drag_allocation.y = 0;
2267           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2268           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2269           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2270                                     &drag_allocation);
2271           width += drag_allocation.width;
2272           continue;
2273         }
2274
2275       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2276
2277       allocation.x = width;
2278       column->width = real_requested_width;
2279
2280       if (column->expand)
2281         {
2282           if (number_of_expand_columns == 1)
2283             {
2284               /* We add the remander to the last column as
2285                * */
2286               column->width += extra;
2287             }
2288           else
2289             {
2290               column->width += extra_per_column;
2291               extra -= extra_per_column;
2292               number_of_expand_columns --;
2293             }
2294         }
2295       else if (number_of_expand_columns == 0 &&
2296                list == last_column)
2297         {
2298           column->width += extra;
2299         }
2300
2301       /* In addition to expand, the last column can get even more
2302        * extra space so all available space is filled up.
2303        */
2304       if (extra_for_last > 0 && list == last_column)
2305         column->width += extra_for_last;
2306
2307       g_object_notify (G_OBJECT (column), "width");
2308
2309       allocation.width = column->width;
2310       width += column->width;
2311
2312       if (column->width > old_width)
2313         column_changed = TRUE;
2314
2315       gtk_widget_size_allocate (column->button, &allocation);
2316
2317       if (column->window)
2318         gdk_window_move_resize (column->window,
2319                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2320                                 allocation.y,
2321                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2322     }
2323
2324   /* We change the width here.  The user might have been resizing columns,
2325    * so the total width of the tree view changes.
2326    */
2327   tree_view->priv->width = width;
2328   if (width_changed)
2329     *width_changed = TRUE;
2330
2331   if (column_changed)
2332     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2333 }
2334
2335
2336 static void
2337 gtk_tree_view_size_allocate (GtkWidget     *widget,
2338                              GtkAllocation *allocation)
2339 {
2340   GtkAllocation widget_allocation;
2341   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2342   GList *tmp_list;
2343   gboolean width_changed = FALSE;
2344   gint old_width;
2345
2346   gtk_widget_get_allocation (widget, &widget_allocation);
2347   old_width = widget_allocation.width;
2348   if (allocation->width != widget_allocation.width)
2349     width_changed = TRUE;
2350
2351   gtk_widget_set_allocation (widget, allocation);
2352
2353   tmp_list = tree_view->priv->children;
2354
2355   while (tmp_list)
2356     {
2357       GtkAllocation allocation;
2358
2359       GtkTreeViewChild *child = tmp_list->data;
2360       tmp_list = tmp_list->next;
2361
2362       /* totally ignore our child's requisition */
2363       allocation.x = child->x;
2364       allocation.y = child->y;
2365       allocation.width = child->width;
2366       allocation.height = child->height;
2367       gtk_widget_size_allocate (child->widget, &allocation);
2368     }
2369
2370   /* We size-allocate the columns first because the width of the
2371    * tree view (used in updating the adjustments below) might change.
2372    */
2373   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2374
2375   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2376   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2377                                 allocation->width);
2378   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2379                                      allocation->width * 0.9);
2380   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2381                                      allocation->width * 0.1);
2382   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2383   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2384                             MAX (tree_view->priv->hadjustment->page_size,
2385                                  tree_view->priv->width));
2386   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2387
2388   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2389     {
2390       if (allocation->width < tree_view->priv->width)
2391         {
2392           if (tree_view->priv->init_hadjust_value)
2393             {
2394               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2395                                         MAX (tree_view->priv->width -
2396                                              allocation->width, 0));
2397               tree_view->priv->init_hadjust_value = FALSE;
2398             }
2399           else if (allocation->width != old_width)
2400             {
2401               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2402                                         CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width,
2403                                                0,
2404                                                tree_view->priv->width - allocation->width));
2405             }
2406           else
2407             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2408                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value),
2409                                              0,
2410                                              tree_view->priv->width - allocation->width));
2411         }
2412       else
2413         {
2414           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2415           tree_view->priv->init_hadjust_value = TRUE;
2416         }
2417     }
2418   else
2419     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2420       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2421                                 MAX (tree_view->priv->width -
2422                                      allocation->width, 0));
2423
2424   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2425   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2426                                 allocation->height -
2427                                 TREE_VIEW_HEADER_HEIGHT (tree_view));
2428   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2429                                      tree_view->priv->vadjustment->page_size * 0.1);
2430   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2431                                      tree_view->priv->vadjustment->page_size * 0.9);
2432   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2433   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2434                             MAX (tree_view->priv->vadjustment->page_size,
2435                                  tree_view->priv->height));
2436   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2437
2438   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2439   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2440     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2441   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2442     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2443                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2444   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2445     gtk_tree_view_top_row_to_dy (tree_view);
2446   else
2447     gtk_tree_view_dy_to_top_row (tree_view);
2448   
2449   if (gtk_widget_get_realized (widget))
2450     {
2451       gdk_window_move_resize (gtk_widget_get_window (widget),
2452                               allocation->x, allocation->y,
2453                               allocation->width, allocation->height);
2454       gdk_window_move_resize (tree_view->priv->header_window,
2455                               - (gint) tree_view->priv->hadjustment->value,
2456                               0,
2457                               MAX (tree_view->priv->width, allocation->width),
2458                               tree_view->priv->header_height);
2459       gdk_window_move_resize (tree_view->priv->bin_window,
2460                               - (gint) tree_view->priv->hadjustment->value,
2461                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2462                               MAX (tree_view->priv->width, allocation->width),
2463                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2464     }
2465
2466   if (tree_view->priv->tree == NULL)
2467     invalidate_empty_focus (tree_view);
2468
2469   if (gtk_widget_get_realized (widget))
2470     {
2471       gboolean has_expand_column = FALSE;
2472       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2473         {
2474           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2475             {
2476               has_expand_column = TRUE;
2477               break;
2478             }
2479         }
2480
2481       if (width_changed && tree_view->priv->expander_column)
2482         {
2483           /* Might seem awkward, but is the best heuristic I could come up
2484            * with.  Only if the width of the columns before the expander
2485            * changes, we will update the prelight status.  It is this
2486            * width that makes the expander move vertically.  Always updating
2487            * prelight status causes trouble with hover selections.
2488            */
2489           gint width_before_expander;
2490
2491           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2492
2493           if (tree_view->priv->prev_width_before_expander
2494               != width_before_expander)
2495               update_prelight (tree_view,
2496                                tree_view->priv->event_last_x,
2497                                tree_view->priv->event_last_y);
2498
2499           tree_view->priv->prev_width_before_expander = width_before_expander;
2500         }
2501
2502       /* This little hack only works if we have an LTR locale, and no column has the  */
2503       if (width_changed)
2504         {
2505           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2506               ! has_expand_column)
2507             invalidate_last_column (tree_view);
2508           else
2509             gtk_widget_queue_draw (widget);
2510         }
2511     }
2512 }
2513
2514 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2515 static void
2516 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2517 {
2518   GtkWidget *widget = GTK_WIDGET (tree_view);
2519
2520   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2521     gtk_widget_grab_focus (widget);
2522   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2523 }
2524
2525 static inline gboolean
2526 row_is_separator (GtkTreeView *tree_view,
2527                   GtkTreeIter *iter,
2528                   GtkTreePath *path)
2529 {
2530   gboolean is_separator = FALSE;
2531
2532   if (tree_view->priv->row_separator_func)
2533     {
2534       GtkTreeIter tmpiter;
2535
2536       if (iter)
2537         tmpiter = *iter;
2538       else
2539         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2540
2541       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2542                                                           &tmpiter,
2543                                                           tree_view->priv->row_separator_data);
2544     }
2545
2546   return is_separator;
2547 }
2548
2549 static gboolean
2550 gtk_tree_view_button_press (GtkWidget      *widget,
2551                             GdkEventButton *event)
2552 {
2553   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2554   GList *list;
2555   GtkTreeViewColumn *column = NULL;
2556   gint i;
2557   GdkRectangle background_area;
2558   GdkRectangle cell_area;
2559   gint vertical_separator;
2560   gint horizontal_separator;
2561   gboolean path_is_selectable;
2562   gboolean rtl;
2563
2564   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2565   gtk_tree_view_stop_editing (tree_view, FALSE);
2566   gtk_widget_style_get (widget,
2567                         "vertical-separator", &vertical_separator,
2568                         "horizontal-separator", &horizontal_separator,
2569                         NULL);
2570
2571
2572   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2573    * we're done handling the button press.
2574    */
2575
2576   if (event->window == tree_view->priv->bin_window)
2577     {
2578       GtkRBNode *node;
2579       GtkRBTree *tree;
2580       GtkTreePath *path;
2581       gchar *path_string;
2582       gint depth;
2583       gint new_y;
2584       gint y_offset;
2585       gint dval;
2586       gint pre_val, aft_val;
2587       GtkTreeViewColumn *column = NULL;
2588       GtkCellRenderer *focus_cell = NULL;
2589       gint column_handled_click = FALSE;
2590       gboolean row_double_click = FALSE;
2591       gboolean rtl;
2592       gboolean node_selected;
2593
2594       /* Empty tree? */
2595       if (tree_view->priv->tree == NULL)
2596         {
2597           grab_focus_and_unset_draw_keyfocus (tree_view);
2598           return TRUE;
2599         }
2600
2601       /* are we in an arrow? */
2602       if (tree_view->priv->prelight_node &&
2603           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2604           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2605         {
2606           if (event->button == 1)
2607             {
2608               gtk_grab_add (widget);
2609               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2610               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2611               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2612                                               tree_view->priv->prelight_tree,
2613                                               tree_view->priv->prelight_node);
2614             }
2615
2616           grab_focus_and_unset_draw_keyfocus (tree_view);
2617           return TRUE;
2618         }
2619
2620       /* find the node that was clicked */
2621       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2622       if (new_y < 0)
2623         new_y = 0;
2624       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2625
2626       if (node == NULL)
2627         {
2628           /* We clicked in dead space */
2629           grab_focus_and_unset_draw_keyfocus (tree_view);
2630           return TRUE;
2631         }
2632
2633       /* Get the path and the node */
2634       path = _gtk_tree_view_find_path (tree_view, tree, node);
2635       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2636
2637       if (!path_is_selectable)
2638         {
2639           gtk_tree_path_free (path);
2640           grab_focus_and_unset_draw_keyfocus (tree_view);
2641           return TRUE;
2642         }
2643
2644       depth = gtk_tree_path_get_depth (path);
2645       background_area.y = y_offset + event->y;
2646       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2647       background_area.x = 0;
2648
2649
2650       /* Let the column have a chance at selecting it. */
2651       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2652       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2653            list; list = (rtl ? list->prev : list->next))
2654         {
2655           GtkTreeViewColumn *candidate = list->data;
2656
2657           if (!candidate->visible)
2658             continue;
2659
2660           background_area.width = candidate->width;
2661           if ((background_area.x > (gint) event->x) ||
2662               (background_area.x + background_area.width <= (gint) event->x))
2663             {
2664               background_area.x += background_area.width;
2665               continue;
2666             }
2667
2668           /* we found the focus column */
2669           column = candidate;
2670           cell_area = background_area;
2671           cell_area.width -= horizontal_separator;
2672           cell_area.height -= vertical_separator;
2673           cell_area.x += horizontal_separator/2;
2674           cell_area.y += vertical_separator/2;
2675           if (gtk_tree_view_is_expander_column (tree_view, column))
2676             {
2677               if (!rtl)
2678                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2679               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2680
2681               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2682                 {
2683                   if (!rtl)
2684                     cell_area.x += depth * tree_view->priv->expander_size;
2685                   cell_area.width -= depth * tree_view->priv->expander_size;
2686                 }
2687             }
2688           break;
2689         }
2690
2691       if (column == NULL)
2692         {
2693           gtk_tree_path_free (path);
2694           grab_focus_and_unset_draw_keyfocus (tree_view);
2695           return FALSE;
2696         }
2697
2698       tree_view->priv->focus_column = column;
2699
2700       /* decide if we edit */
2701       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2702           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2703         {
2704           GtkTreePath *anchor;
2705           GtkTreeIter iter;
2706
2707           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2708           gtk_tree_view_column_cell_set_cell_data (column,
2709                                                    tree_view->priv->model,
2710                                                    &iter,
2711                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2712                                                    node->children?TRUE:FALSE);
2713
2714           if (tree_view->priv->anchor)
2715             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2716           else
2717             anchor = NULL;
2718
2719           if ((anchor && !gtk_tree_path_compare (anchor, path))
2720               || !_gtk_tree_view_column_has_editable_cell (column))
2721             {
2722               GtkCellEditable *cell_editable = NULL;
2723
2724               /* FIXME: get the right flags */
2725               guint flags = 0;
2726
2727               path_string = gtk_tree_path_to_string (path);
2728
2729               if (_gtk_tree_view_column_cell_event (column,
2730                                                     &cell_editable,
2731                                                     (GdkEvent *)event,
2732                                                     path_string,
2733                                                     &background_area,
2734                                                     &cell_area, flags))
2735                 {
2736                   if (cell_editable != NULL)
2737                     {
2738                       gint left, right;
2739                       GdkRectangle area;
2740
2741                       area = cell_area;
2742                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2743
2744                       area.x += left;
2745                       area.width -= right + left;
2746
2747                       gtk_tree_view_real_start_editing (tree_view,
2748                                                         column,
2749                                                         path,
2750                                                         cell_editable,
2751                                                         &area,
2752                                                         (GdkEvent *)event,
2753                                                         flags);
2754                       g_free (path_string);
2755                       gtk_tree_path_free (path);
2756                       gtk_tree_path_free (anchor);
2757                       return TRUE;
2758                     }
2759                   column_handled_click = TRUE;
2760                 }
2761               g_free (path_string);
2762             }
2763           if (anchor)
2764             gtk_tree_path_free (anchor);
2765         }
2766
2767       /* select */
2768       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2769       pre_val = tree_view->priv->vadjustment->value;
2770
2771       /* we only handle selection modifications on the first button press
2772        */
2773       if (event->type == GDK_BUTTON_PRESS)
2774         {
2775           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2776             tree_view->priv->ctrl_pressed = TRUE;
2777           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2778             tree_view->priv->shift_pressed = TRUE;
2779
2780           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2781           if (focus_cell)
2782             gtk_tree_view_column_focus_cell (column, focus_cell);
2783
2784           if (event->state & GDK_CONTROL_MASK)
2785             {
2786               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2787               gtk_tree_view_real_toggle_cursor_row (tree_view);
2788             }
2789           else if (event->state & GDK_SHIFT_MASK)
2790             {
2791               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2792               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2793             }
2794           else
2795             {
2796               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2797             }
2798
2799           tree_view->priv->ctrl_pressed = FALSE;
2800           tree_view->priv->shift_pressed = FALSE;
2801         }
2802
2803       /* the treeview may have been scrolled because of _set_cursor,
2804        * correct here
2805        */
2806
2807       aft_val = tree_view->priv->vadjustment->value;
2808       dval = pre_val - aft_val;
2809
2810       cell_area.y += dval;
2811       background_area.y += dval;
2812
2813       /* Save press to possibly begin a drag
2814        */
2815       if (!column_handled_click &&
2816           !tree_view->priv->in_grab &&
2817           tree_view->priv->pressed_button < 0)
2818         {
2819           tree_view->priv->pressed_button = event->button;
2820           tree_view->priv->press_start_x = event->x;
2821           tree_view->priv->press_start_y = event->y;
2822
2823           if (tree_view->priv->rubber_banding_enable
2824               && !node_selected
2825               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2826             {
2827               tree_view->priv->press_start_y += tree_view->priv->dy;
2828               tree_view->priv->rubber_band_x = event->x;
2829               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2830               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2831
2832               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2833                 tree_view->priv->rubber_band_ctrl = TRUE;
2834               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2835                 tree_view->priv->rubber_band_shift = TRUE;
2836             }
2837         }
2838
2839       /* Test if a double click happened on the same row. */
2840       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2841         {
2842           int double_click_time, double_click_distance;
2843
2844           g_object_get (gtk_settings_get_default (),
2845                         "gtk-double-click-time", &double_click_time,
2846                         "gtk-double-click-distance", &double_click_distance,
2847                         NULL);
2848
2849           /* Same conditions as _gdk_event_button_generate */
2850           if (tree_view->priv->last_button_x != -1 &&
2851               (event->time < tree_view->priv->last_button_time + double_click_time) &&
2852               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2853               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2854             {
2855               /* We do no longer compare paths of this row and the
2856                * row clicked previously.  We use the double click
2857                * distance to decide whether this is a valid click,
2858                * allowing the mouse to slightly move over another row.
2859                */
2860               row_double_click = TRUE;
2861
2862               tree_view->priv->last_button_time = 0;
2863               tree_view->priv->last_button_x = -1;
2864               tree_view->priv->last_button_y = -1;
2865             }
2866           else
2867             {
2868               tree_view->priv->last_button_time = event->time;
2869               tree_view->priv->last_button_x = event->x;
2870               tree_view->priv->last_button_y = event->y;
2871             }
2872         }
2873
2874       if (row_double_click)
2875         {
2876           gtk_grab_remove (widget);
2877           gtk_tree_view_row_activated (tree_view, path, column);
2878
2879           if (tree_view->priv->pressed_button == event->button)
2880             tree_view->priv->pressed_button = -1;
2881         }
2882
2883       gtk_tree_path_free (path);
2884
2885       /* If we activated the row through a double click we don't want to grab
2886        * focus back, as moving focus to another widget is pretty common.
2887        */
2888       if (!row_double_click)
2889         grab_focus_and_unset_draw_keyfocus (tree_view);
2890
2891       return TRUE;
2892     }
2893
2894   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2895    */
2896   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2897     {
2898       column = list->data;
2899       if (event->window == column->window &&
2900           column->resizable &&
2901           column->window)
2902         {
2903           GtkAllocation button_allocation;
2904           gpointer drag_data;
2905
2906           if (event->type == GDK_2BUTTON_PRESS &&
2907               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2908             {
2909               column->use_resized_width = FALSE;
2910               _gtk_tree_view_column_autosize (tree_view, column);
2911               return TRUE;
2912             }
2913
2914           if (gdk_pointer_grab (column->window, FALSE,
2915                                 GDK_POINTER_MOTION_HINT_MASK |
2916                                 GDK_BUTTON1_MOTION_MASK |
2917                                 GDK_BUTTON_RELEASE_MASK,
2918                                 NULL, NULL, event->time))
2919             return FALSE;
2920
2921           gtk_grab_add (widget);
2922           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2923           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2924
2925           /* block attached dnd signal handler */
2926           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2927           if (drag_data)
2928             g_signal_handlers_block_matched (widget,
2929                                              G_SIGNAL_MATCH_DATA,
2930                                              0, 0, NULL, NULL,
2931                                              drag_data);
2932
2933           gtk_widget_get_allocation (column->button, &button_allocation);
2934           tree_view->priv->drag_pos = i;
2935           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
2936
2937           if (!gtk_widget_has_focus (widget))
2938             gtk_widget_grab_focus (widget);
2939
2940           return TRUE;
2941         }
2942     }
2943   return FALSE;
2944 }
2945
2946 /* GtkWidget::button_release_event helper */
2947 static gboolean
2948 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2949                                           GdkEventButton *event)
2950 {
2951   GtkTreeView *tree_view;
2952   GList *l;
2953   gboolean rtl;
2954
2955   tree_view = GTK_TREE_VIEW (widget);
2956
2957   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2958   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2959   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2960
2961   /* Move the button back */
2962   g_object_ref (tree_view->priv->drag_column->button);
2963   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2964   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2965   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2966   g_object_unref (tree_view->priv->drag_column->button);
2967   gtk_widget_queue_resize (widget);
2968   if (tree_view->priv->drag_column->resizable)
2969     {
2970       gdk_window_raise (tree_view->priv->drag_column->window);
2971       gdk_window_show (tree_view->priv->drag_column->window);
2972     }
2973   else
2974     gdk_window_hide (tree_view->priv->drag_column->window);
2975
2976   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2977
2978   if (rtl)
2979     {
2980       if (tree_view->priv->cur_reorder &&
2981           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2982         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2983                                          tree_view->priv->cur_reorder->right_column);
2984     }
2985   else
2986     {
2987       if (tree_view->priv->cur_reorder &&
2988           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2989         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2990                                          tree_view->priv->cur_reorder->left_column);
2991     }
2992   tree_view->priv->drag_column = NULL;
2993   gdk_window_hide (tree_view->priv->drag_window);
2994
2995   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
2996     g_slice_free (GtkTreeViewColumnReorder, l->data);
2997   g_list_free (tree_view->priv->column_drag_info);
2998   tree_view->priv->column_drag_info = NULL;
2999   tree_view->priv->cur_reorder = NULL;
3000
3001   if (tree_view->priv->drag_highlight_window)
3002     gdk_window_hide (tree_view->priv->drag_highlight_window);
3003
3004   /* Reset our flags */
3005   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3006   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
3007
3008   return TRUE;
3009 }
3010
3011 /* GtkWidget::button_release_event helper */
3012 static gboolean
3013 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3014                                             GdkEventButton *event)
3015 {
3016   GtkTreeView *tree_view;
3017   gpointer drag_data;
3018
3019   tree_view = GTK_TREE_VIEW (widget);
3020
3021   tree_view->priv->drag_pos = -1;
3022
3023   /* unblock attached dnd signal handler */
3024   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3025   if (drag_data)
3026     g_signal_handlers_unblock_matched (widget,
3027                                        G_SIGNAL_MATCH_DATA,
3028                                        0, 0, NULL, NULL,
3029                                        drag_data);
3030
3031   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3032   gtk_grab_remove (widget);
3033   gdk_display_pointer_ungrab (gdk_window_get_display (event->window),
3034                               event->time);
3035   return TRUE;
3036 }
3037
3038 static gboolean
3039 gtk_tree_view_button_release (GtkWidget      *widget,
3040                               GdkEventButton *event)
3041 {
3042   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3043
3044   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3045     return gtk_tree_view_button_release_drag_column (widget, event);
3046
3047   if (tree_view->priv->rubber_band_status)
3048     gtk_tree_view_stop_rubber_band (tree_view);
3049
3050   if (tree_view->priv->pressed_button == event->button)
3051     tree_view->priv->pressed_button = -1;
3052
3053   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3054     return gtk_tree_view_button_release_column_resize (widget, event);
3055
3056   if (tree_view->priv->button_pressed_node == NULL)
3057     return FALSE;
3058
3059   if (event->button == 1)
3060     {
3061       gtk_grab_remove (widget);
3062       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3063           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3064         {
3065           GtkTreePath *path = NULL;
3066
3067           path = _gtk_tree_view_find_path (tree_view,
3068                                            tree_view->priv->button_pressed_tree,
3069                                            tree_view->priv->button_pressed_node);
3070           /* Actually activate the node */
3071           if (tree_view->priv->button_pressed_node->children == NULL)
3072             gtk_tree_view_real_expand_row (tree_view, path,
3073                                            tree_view->priv->button_pressed_tree,
3074                                            tree_view->priv->button_pressed_node,
3075                                            FALSE, TRUE);
3076           else
3077             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3078                                              tree_view->priv->button_pressed_tree,
3079                                              tree_view->priv->button_pressed_node, TRUE);
3080           gtk_tree_path_free (path);
3081         }
3082
3083       tree_view->priv->button_pressed_tree = NULL;
3084       tree_view->priv->button_pressed_node = NULL;
3085     }
3086
3087   return TRUE;
3088 }
3089
3090 static gboolean
3091 gtk_tree_view_grab_broken (GtkWidget          *widget,
3092                            GdkEventGrabBroken *event)
3093 {
3094   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3095
3096   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3097     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3098
3099   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3100     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3101
3102   return TRUE;
3103 }
3104
3105 #if 0
3106 static gboolean
3107 gtk_tree_view_configure (GtkWidget *widget,
3108                          GdkEventConfigure *event)
3109 {
3110   GtkTreeView *tree_view;
3111
3112   tree_view = GTK_TREE_VIEW (widget);
3113   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3114
3115   return FALSE;
3116 }
3117 #endif
3118
3119 /* GtkWidget::motion_event function set.
3120  */
3121
3122 static gboolean
3123 coords_are_over_arrow (GtkTreeView *tree_view,
3124                        GtkRBTree   *tree,
3125                        GtkRBNode   *node,
3126                        /* these are in bin window coords */
3127                        gint         x,
3128                        gint         y)
3129 {
3130   GdkRectangle arrow;
3131   gint x2;
3132
3133   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3134     return FALSE;
3135
3136   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3137     return FALSE;
3138
3139   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3140
3141   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3142
3143   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3144
3145   arrow.width = x2 - arrow.x;
3146
3147   return (x >= arrow.x &&
3148           x < (arrow.x + arrow.width) &&
3149           y >= arrow.y &&
3150           y < (arrow.y + arrow.height));
3151 }
3152
3153 static gboolean
3154 auto_expand_timeout (gpointer data)
3155 {
3156   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3157   GtkTreePath *path;
3158
3159   if (tree_view->priv->prelight_node)
3160     {
3161       path = _gtk_tree_view_find_path (tree_view,
3162                                        tree_view->priv->prelight_tree,
3163                                        tree_view->priv->prelight_node);   
3164
3165       if (tree_view->priv->prelight_node->children)
3166         gtk_tree_view_collapse_row (tree_view, path);
3167       else
3168         gtk_tree_view_expand_row (tree_view, path, FALSE);
3169
3170       gtk_tree_path_free (path);
3171     }
3172
3173   tree_view->priv->auto_expand_timeout = 0;
3174
3175   return FALSE;
3176 }
3177
3178 static void
3179 remove_auto_expand_timeout (GtkTreeView *tree_view)
3180 {
3181   if (tree_view->priv->auto_expand_timeout != 0)
3182     {
3183       g_source_remove (tree_view->priv->auto_expand_timeout);
3184       tree_view->priv->auto_expand_timeout = 0;
3185     }
3186 }
3187
3188 static void
3189 do_prelight (GtkTreeView *tree_view,
3190              GtkRBTree   *tree,
3191              GtkRBNode   *node,
3192              /* these are in bin_window coords */
3193              gint         x,
3194              gint         y)
3195 {
3196   if (tree_view->priv->prelight_tree == tree &&
3197       tree_view->priv->prelight_node == node)
3198     {
3199       /*  We are still on the same node,
3200           but we might need to take care of the arrow  */
3201
3202       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3203         {
3204           gboolean over_arrow;
3205           gboolean flag_set;
3206
3207           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3208           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3209                                              GTK_TREE_VIEW_ARROW_PRELIT);
3210
3211           if (over_arrow != flag_set)
3212             {
3213               if (over_arrow)
3214                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3215                                         GTK_TREE_VIEW_ARROW_PRELIT);
3216               else
3217                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3218                                           GTK_TREE_VIEW_ARROW_PRELIT);
3219
3220               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3221             }
3222         }
3223
3224       return;
3225     }
3226
3227   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3228     {
3229       /*  Unprelight the old node and arrow  */
3230
3231       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3232                              GTK_RBNODE_IS_PRELIT);
3233
3234       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3235           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3236         {
3237           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3238           
3239           gtk_tree_view_queue_draw_arrow (tree_view,
3240                                           tree_view->priv->prelight_tree,
3241                                           tree_view->priv->prelight_node);
3242         }
3243
3244       _gtk_tree_view_queue_draw_node (tree_view,
3245                                       tree_view->priv->prelight_tree,
3246                                       tree_view->priv->prelight_node,
3247                                       NULL);
3248     }
3249
3250
3251   if (tree_view->priv->hover_expand)
3252     remove_auto_expand_timeout (tree_view);
3253
3254   /*  Set the new prelight values  */
3255   tree_view->priv->prelight_node = node;
3256   tree_view->priv->prelight_tree = tree;
3257
3258   if (!node || !tree)
3259     return;
3260
3261   /*  Prelight the new node and arrow  */
3262
3263   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3264       && coords_are_over_arrow (tree_view, tree, node, x, y))
3265     {
3266       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3267
3268       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3269     }
3270
3271   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3272
3273   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3274
3275   if (tree_view->priv->hover_expand)
3276     {
3277       tree_view->priv->auto_expand_timeout = 
3278         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3279     }
3280 }
3281
3282 static void
3283 prelight_or_select (GtkTreeView *tree_view,
3284                     GtkRBTree   *tree,
3285                     GtkRBNode   *node,
3286                     /* these are in bin_window coords */
3287                     gint         x,
3288                     gint         y)
3289 {
3290   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3291   
3292   if (tree_view->priv->hover_selection &&
3293       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3294       !(tree_view->priv->edited_column &&
3295         tree_view->priv->edited_column->editable_widget))
3296     {
3297       if (node)
3298         {
3299           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3300             {
3301               GtkTreePath *path;
3302               
3303               path = _gtk_tree_view_find_path (tree_view, tree, node);
3304               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3305               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3306                 {
3307                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3308                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3309                 }
3310               gtk_tree_path_free (path);
3311             }
3312         }
3313
3314       else if (mode == GTK_SELECTION_SINGLE)
3315         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3316     }
3317
3318     do_prelight (tree_view, tree, node, x, y);
3319 }
3320
3321 static void
3322 ensure_unprelighted (GtkTreeView *tree_view)
3323 {
3324   do_prelight (tree_view,
3325                NULL, NULL,
3326                -1000, -1000); /* coords not possibly over an arrow */
3327
3328   g_assert (tree_view->priv->prelight_node == NULL);
3329 }
3330
3331 static void
3332 update_prelight (GtkTreeView *tree_view,
3333                  gint         x,
3334                  gint         y)
3335 {
3336   int new_y;
3337   GtkRBTree *tree;
3338   GtkRBNode *node;
3339
3340   if (tree_view->priv->tree == NULL)
3341     return;
3342
3343   if (x == -10000)
3344     {
3345       ensure_unprelighted (tree_view);
3346       return;
3347     }
3348
3349   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3350   if (new_y < 0)
3351     new_y = 0;
3352
3353   _gtk_rbtree_find_offset (tree_view->priv->tree,
3354                            new_y, &tree, &node);
3355
3356   if (node)
3357     prelight_or_select (tree_view, tree, node, x, y);
3358 }
3359
3360
3361
3362
3363 /* Our motion arrow is either a box (in the case of the original spot)
3364  * or an arrow.  It is expander_size wide.
3365  */
3366 /*
3367  * 11111111111111
3368  * 01111111111110
3369  * 00111111111100
3370  * 00011111111000
3371  * 00001111110000
3372  * 00000111100000
3373  * 00000111100000
3374  * 00000111100000
3375  * ~ ~ ~ ~ ~ ~ ~
3376  * 00000111100000
3377  * 00000111100000
3378  * 00000111100000
3379  * 00001111110000
3380  * 00011111111000
3381  * 00111111111100
3382  * 01111111111110
3383  * 11111111111111
3384  */
3385
3386 static void
3387 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3388 {
3389   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3390   GtkWidget *widget = GTK_WIDGET (tree_view);
3391   cairo_surface_t *mask_image;
3392   cairo_region_t *mask_region;
3393   gint x;
3394   gint y;
3395   gint width;
3396   gint height;
3397   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3398   GdkWindowAttr attributes;
3399   guint attributes_mask;
3400   cairo_t *cr;
3401
3402   if (!reorder ||
3403       reorder->left_column == tree_view->priv->drag_column ||
3404       reorder->right_column == tree_view->priv->drag_column)
3405     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3406   else if (reorder->left_column || reorder->right_column)
3407     {
3408       GtkAllocation left_allocation, right_allocation;
3409       GdkRectangle visible_rect;
3410
3411       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3412       if (reorder->left_column)
3413         {
3414           gtk_widget_get_allocation (reorder->left_column->button, &left_allocation);
3415           x = left_allocation.x + left_allocation.width;
3416         }
3417       else
3418         {
3419           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
3420           x = right_allocation.x;
3421         }
3422
3423       if (x < visible_rect.x)
3424         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3425       else if (x > visible_rect.x + visible_rect.width)
3426         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3427       else
3428         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3429     }
3430
3431   /* We want to draw the rectangle over the initial location. */
3432   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3433     {
3434       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3435         {
3436           GtkAllocation drag_allocation;
3437
3438           if (tree_view->priv->drag_highlight_window)
3439             {
3440               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3441                                         NULL);
3442               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3443             }
3444
3445           attributes.window_type = GDK_WINDOW_CHILD;
3446           attributes.wclass = GDK_INPUT_OUTPUT;
3447           attributes.x = tree_view->priv->drag_column_x;
3448           attributes.y = 0;
3449           gtk_widget_get_allocation (tree_view->priv->drag_column->button, &drag_allocation);
3450           width = attributes.width = drag_allocation.width;
3451           height = attributes.height = drag_allocation.height;
3452           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3453           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3454           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3455           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3456           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3457
3458           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3459           cr = cairo_create (mask_image);
3460
3461           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3462           cairo_stroke (cr);
3463           cairo_destroy (cr);
3464
3465           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3466           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3467                                            mask_region, 0, 0);
3468
3469           cairo_region_destroy (mask_region);
3470           cairo_surface_destroy (mask_image);
3471
3472           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3473         }
3474     }
3475   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3476     {
3477       GtkAllocation button_allocation;
3478
3479       width = tree_view->priv->expander_size;
3480
3481       /* Get x, y, width, height of arrow */
3482       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3483       if (reorder->left_column)
3484         {
3485           gtk_widget_get_allocation (reorder->left_column->button, &button_allocation);
3486           x += button_allocation.x + button_allocation.width - width/2;
3487           height = button_allocation.height;
3488         }
3489       else
3490         {
3491           gtk_widget_get_allocation (reorder->right_column->button, &button_allocation);
3492           x += button_allocation.x - width/2;
3493           height = button_allocation.height;
3494         }
3495       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3496       height += tree_view->priv->expander_size;
3497
3498       /* Create the new window */
3499       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3500         {
3501           if (tree_view->priv->drag_highlight_window)
3502             {
3503               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3504                                         NULL);
3505               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3506             }
3507
3508           attributes.window_type = GDK_WINDOW_TEMP;
3509           attributes.wclass = GDK_INPUT_OUTPUT;
3510           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3511           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3512           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3513           attributes.x = x;
3514           attributes.y = y;
3515           attributes.width = width;
3516           attributes.height = height;
3517           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3518                                                                    &attributes, attributes_mask);
3519           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3520
3521           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3522
3523           cr = cairo_create (mask_image);
3524           cairo_move_to (cr, 0, 0);
3525           cairo_line_to (cr, width, 0);
3526           cairo_line_to (cr, width / 2., width / 2);
3527           cairo_move_to (cr, 0, height);
3528           cairo_line_to (cr, width, height);
3529           cairo_line_to (cr, width / 2., height - width / 2.);
3530           cairo_fill (cr);
3531           cairo_destroy (cr);
3532
3533           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3534           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3535                                            mask_region, 0, 0);
3536
3537           cairo_region_destroy (mask_region);
3538           cairo_surface_destroy (mask_image);
3539         }
3540
3541       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3542       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3543     }
3544   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3545            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3546     {
3547       GtkAllocation allocation;
3548
3549       width = tree_view->priv->expander_size;
3550
3551       /* Get x, y, width, height of arrow */
3552       width = width/2; /* remember, the arrow only takes half the available width */
3553       gdk_window_get_origin (gtk_widget_get_window (widget),
3554                              &x, &y);
3555       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3556         {
3557           gtk_widget_get_allocation (widget, &allocation);
3558           x += allocation.width - width;
3559         }
3560
3561       if (reorder->left_column)
3562         {
3563           gtk_widget_get_allocation (reorder->left_column->button, &allocation);
3564           height = allocation.height;
3565         }
3566       else
3567         {
3568           gtk_widget_get_allocation (reorder->right_column->button, &allocation);
3569           height = allocation.height;
3570         }
3571
3572       y -= tree_view->priv->expander_size;
3573       height += 2*tree_view->priv->expander_size;
3574
3575       /* Create the new window */
3576       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3577           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3578         {
3579           if (tree_view->priv->drag_highlight_window)
3580             {
3581               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3582                                         NULL);
3583               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3584             }
3585
3586           attributes.window_type = GDK_WINDOW_TEMP;
3587           attributes.wclass = GDK_INPUT_OUTPUT;
3588           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3589           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3590           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3591           attributes.x = x;
3592           attributes.y = y;
3593           attributes.width = width;
3594           attributes.height = height;
3595           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3596           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3597
3598           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3599
3600           cr = cairo_create (mask_image);
3601           /* mirror if we're on the left */
3602           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3603             {
3604               cairo_translate (cr, width, 0);
3605               cairo_scale (cr, -1, 1);
3606             }
3607           cairo_move_to (cr, 0, 0);
3608           cairo_line_to (cr, width, width);
3609           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3610           cairo_move_to (cr, 0, height);
3611           cairo_line_to (cr, width, height - width);
3612           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3613           cairo_fill (cr);
3614           cairo_destroy (cr);
3615
3616           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3617           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3618                                            mask_region, 0, 0);
3619
3620           cairo_region_destroy (mask_region);
3621           cairo_surface_destroy (mask_image);
3622         }
3623
3624       tree_view->priv->drag_column_window_state = arrow_type;
3625       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3626    }
3627   else
3628     {
3629       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3630       gdk_window_hide (tree_view->priv->drag_highlight_window);
3631       return;
3632     }
3633
3634   gdk_window_show (tree_view->priv->drag_highlight_window);
3635   gdk_window_raise (tree_view->priv->drag_highlight_window);
3636 }
3637
3638 static gboolean
3639 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3640                                     GdkEventMotion *event)
3641 {
3642   gint x;
3643   gint new_width;
3644   GtkTreeViewColumn *column;
3645   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3646
3647   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3648
3649   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3650     gtk_widget_get_pointer (widget, &x, NULL);
3651   else
3652     x = event->x;
3653
3654   if (tree_view->priv->hadjustment)
3655     x += tree_view->priv->hadjustment->value;
3656
3657   new_width = gtk_tree_view_new_column_width (tree_view,
3658                                               tree_view->priv->drag_pos, &x);
3659   if (x != tree_view->priv->x_drag &&
3660       (new_width != column->fixed_width))
3661     {
3662       column->use_resized_width = TRUE;
3663       column->resized_width = new_width;
3664       if (column->expand)
3665         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3666       gtk_widget_queue_resize (widget);
3667     }
3668
3669   return FALSE;
3670 }
3671
3672
3673 static void
3674 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3675 {
3676   GtkTreeViewColumnReorder *reorder = NULL;
3677   GList *list;
3678   gint mouse_x;
3679
3680   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3681   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3682     {
3683       reorder = (GtkTreeViewColumnReorder *) list->data;
3684       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3685         break;
3686       reorder = NULL;
3687     }
3688
3689   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3690       return;*/
3691
3692   tree_view->priv->cur_reorder = reorder;
3693   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3694 }
3695
3696 static void
3697 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3698 {
3699   GdkRectangle visible_rect;
3700   gint y;
3701   gint offset;
3702
3703   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3704   y += tree_view->priv->dy;
3705
3706   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3707
3708   /* see if we are near the edge. */
3709   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3710   if (offset > 0)
3711     {
3712       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3713       if (offset < 0)
3714         return;
3715     }
3716
3717   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3718                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3719 }
3720
3721 static gboolean
3722 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3723 {
3724   GdkRectangle visible_rect;
3725   gint x;
3726   gint offset;
3727
3728   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3729
3730   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3731
3732   /* See if we are near the edge. */
3733   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3734   if (offset > 0)
3735     {
3736       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3737       if (offset < 0)
3738         return TRUE;
3739     }
3740   offset = offset/3;
3741
3742   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3743                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3744
3745   return TRUE;
3746
3747 }
3748
3749 static gboolean
3750 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3751                                   GdkEventMotion *event)
3752 {
3753   GtkAllocation allocation, button_allocation;
3754   GtkTreeView *tree_view = (GtkTreeView *) widget;
3755   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3756   gint x, y;
3757
3758   /* Sanity Check */
3759   if ((column == NULL) ||
3760       (event->window != tree_view->priv->drag_window))
3761     return FALSE;
3762
3763   /* Handle moving the header */
3764   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3765   gtk_widget_get_allocation (widget, &allocation);
3766   gtk_widget_get_allocation (column->button, &button_allocation);
3767   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3768              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
3769   gdk_window_move (tree_view->priv->drag_window, x, y);
3770   
3771   /* autoscroll, if needed */
3772   gtk_tree_view_horizontal_autoscroll (tree_view);
3773   /* Update the current reorder position and arrow; */
3774   gtk_tree_view_update_current_reorder (tree_view);
3775
3776   return TRUE;
3777 }
3778
3779 static void
3780 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3781 {
3782   remove_scroll_timeout (tree_view);
3783   gtk_grab_remove (GTK_WIDGET (tree_view));
3784
3785   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3786     {
3787       GtkTreePath *tmp_path;
3788
3789       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3790
3791       /* The anchor path should be set to the start path */
3792       tmp_path = _gtk_tree_view_find_path (tree_view,
3793                                            tree_view->priv->rubber_band_start_tree,
3794                                            tree_view->priv->rubber_band_start_node);
3795
3796       if (tree_view->priv->anchor)
3797         gtk_tree_row_reference_free (tree_view->priv->anchor);
3798
3799       tree_view->priv->anchor =
3800         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3801                                           tree_view->priv->model,
3802                                           tmp_path);
3803
3804       gtk_tree_path_free (tmp_path);
3805
3806       /* ... and the cursor to the end path */
3807       tmp_path = _gtk_tree_view_find_path (tree_view,
3808                                            tree_view->priv->rubber_band_end_tree,
3809                                            tree_view->priv->rubber_band_end_node);
3810       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3811       gtk_tree_path_free (tmp_path);
3812
3813       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3814     }
3815
3816   /* Clear status variables */
3817   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3818   tree_view->priv->rubber_band_shift = 0;
3819   tree_view->priv->rubber_band_ctrl = 0;
3820
3821   tree_view->priv->rubber_band_start_node = NULL;
3822   tree_view->priv->rubber_band_start_tree = NULL;
3823   tree_view->priv->rubber_band_end_node = NULL;
3824   tree_view->priv->rubber_band_end_tree = NULL;
3825 }
3826
3827 static void
3828 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3829                                                  GtkRBTree   *start_tree,
3830                                                  GtkRBNode   *start_node,
3831                                                  GtkRBTree   *end_tree,
3832                                                  GtkRBNode   *end_node,
3833                                                  gboolean     select,
3834                                                  gboolean     skip_start,
3835                                                  gboolean     skip_end)
3836 {
3837   if (start_node == end_node)
3838     return;
3839
3840   /* We skip the first node and jump inside the loop */
3841   if (skip_start)
3842     goto skip_first;
3843
3844   do
3845     {
3846       /* Small optimization by assuming insensitive nodes are never
3847        * selected.
3848        */
3849       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3850         {
3851           GtkTreePath *path;
3852           gboolean selectable;
3853
3854           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3855           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3856           gtk_tree_path_free (path);
3857
3858           if (!selectable)
3859             goto node_not_selectable;
3860         }
3861
3862       if (select)
3863         {
3864           if (tree_view->priv->rubber_band_shift)
3865             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3866           else if (tree_view->priv->rubber_band_ctrl)
3867             {
3868               /* Toggle the selection state */
3869               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3870                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3871               else
3872                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3873             }
3874           else
3875             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3876         }
3877       else
3878         {
3879           /* Mirror the above */
3880           if (tree_view->priv->rubber_band_shift)
3881             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3882           else if (tree_view->priv->rubber_band_ctrl)
3883             {
3884               /* Toggle the selection state */
3885               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3886                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3887               else
3888                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3889             }
3890           else
3891             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3892         }
3893
3894       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3895
3896 node_not_selectable:
3897       if (start_node == end_node)
3898         break;
3899
3900 skip_first:
3901
3902       if (start_node->children)
3903         {
3904           start_tree = start_node->children;
3905           start_node = start_tree->root;
3906           while (start_node->left != start_tree->nil)
3907             start_node = start_node->left;
3908         }
3909       else
3910         {
3911           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3912
3913           if (!start_tree)
3914             /* Ran out of tree */
3915             break;
3916         }
3917
3918       if (skip_end && start_node == end_node)
3919         break;
3920     }
3921   while (TRUE);
3922 }
3923
3924 static void
3925 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3926 {
3927   GtkRBTree *start_tree, *end_tree;
3928   GtkRBNode *start_node, *end_node;
3929
3930   _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);
3931   _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);
3932
3933   /* Handle the start area first */
3934   if (!tree_view->priv->rubber_band_start_node)
3935     {
3936       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3937                                                        start_tree,
3938                                                        start_node,
3939                                                        end_tree,
3940                                                        end_node,
3941                                                        TRUE,
3942                                                        FALSE,
3943                                                        FALSE);
3944     }
3945   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3946            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3947     {
3948       /* New node is above the old one; selection became bigger */
3949       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3950                                                        start_tree,
3951                                                        start_node,
3952                                                        tree_view->priv->rubber_band_start_tree,
3953                                                        tree_view->priv->rubber_band_start_node,
3954                                                        TRUE,
3955                                                        FALSE,
3956                                                        TRUE);
3957     }
3958   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3959            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3960     {
3961       /* New node is below the old one; selection became smaller */
3962       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3963                                                        tree_view->priv->rubber_band_start_tree,
3964                                                        tree_view->priv->rubber_band_start_node,
3965                                                        start_tree,
3966                                                        start_node,
3967                                                        FALSE,
3968                                                        FALSE,
3969                                                        TRUE);
3970     }
3971
3972   tree_view->priv->rubber_band_start_tree = start_tree;
3973   tree_view->priv->rubber_band_start_node = start_node;
3974
3975   /* Next, handle the end area */
3976   if (!tree_view->priv->rubber_band_end_node)
3977     {
3978       /* In the event this happens, start_node was also NULL; this case is
3979        * handled above.
3980        */
3981     }
3982   else if (!end_node)
3983     {
3984       /* Find the last node in the tree */
3985       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3986                                &end_tree, &end_node);
3987
3988       /* Selection reached end of the tree */
3989       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3990                                                        tree_view->priv->rubber_band_end_tree,
3991                                                        tree_view->priv->rubber_band_end_node,
3992                                                        end_tree,
3993                                                        end_node,
3994                                                        TRUE,
3995                                                        TRUE,
3996                                                        FALSE);
3997     }
3998   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3999            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4000     {
4001       /* New node is below the old one; selection became bigger */
4002       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4003                                                        tree_view->priv->rubber_band_end_tree,
4004                                                        tree_view->priv->rubber_band_end_node,
4005                                                        end_tree,
4006                                                        end_node,
4007                                                        TRUE,
4008                                                        TRUE,
4009                                                        FALSE);
4010     }
4011   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4012            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4013     {
4014       /* New node is above the old one; selection became smaller */
4015       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4016                                                        end_tree,
4017                                                        end_node,
4018                                                        tree_view->priv->rubber_band_end_tree,
4019                                                        tree_view->priv->rubber_band_end_node,
4020                                                        FALSE,
4021                                                        TRUE,
4022                                                        FALSE);
4023     }
4024
4025   tree_view->priv->rubber_band_end_tree = end_tree;
4026   tree_view->priv->rubber_band_end_node = end_node;
4027 }
4028
4029 static void
4030 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4031 {
4032   gint x, y;
4033   GdkRectangle old_area;
4034   GdkRectangle new_area;
4035   GdkRectangle common;
4036   cairo_region_t *invalid_region;
4037
4038   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4039   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4040   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4041   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4042
4043   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4044
4045   x = MAX (x, 0);
4046   y = MAX (y, 0) + tree_view->priv->dy;
4047
4048   new_area.x = MIN (tree_view->priv->press_start_x, x);
4049   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4050   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4051   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4052
4053   invalid_region = cairo_region_create_rectangle (&old_area);
4054   cairo_region_union_rectangle (invalid_region, &new_area);
4055
4056   gdk_rectangle_intersect (&old_area, &new_area, &common);
4057   if (common.width > 2 && common.height > 2)
4058     {
4059       cairo_region_t *common_region;
4060
4061       /* make sure the border is invalidated */
4062       common.x += 1;
4063       common.y += 1;
4064       common.width -= 2;
4065       common.height -= 2;
4066
4067       common_region = cairo_region_create_rectangle (&common);
4068
4069       cairo_region_subtract (invalid_region, common_region);
4070       cairo_region_destroy (common_region);
4071     }
4072
4073   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4074
4075   cairo_region_destroy (invalid_region);
4076
4077   tree_view->priv->rubber_band_x = x;
4078   tree_view->priv->rubber_band_y = y;
4079
4080   gtk_tree_view_update_rubber_band_selection (tree_view);
4081 }
4082
4083 static void
4084 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4085                                  cairo_t      *cr)
4086 {
4087   GdkRectangle rect;
4088   GtkStyle *style;
4089
4090   cairo_save (cr);
4091
4092   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4093   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4094   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4095   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4096
4097   cairo_set_line_width (cr, 1.0);
4098
4099   style = gtk_widget_get_style (GTK_WIDGET (tree_view));
4100
4101   gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
4102
4103   gdk_cairo_rectangle (cr, &rect);
4104   cairo_clip (cr);
4105   cairo_paint_with_alpha (cr, 0.25);
4106
4107   cairo_rectangle (cr,
4108                    rect.x + 0.5, rect.y + 0.5,
4109                    rect.width - 1, rect.height - 1);
4110   cairo_stroke (cr);
4111
4112   cairo_restore (cr);
4113 }
4114
4115 static gboolean
4116 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4117                                  GdkEventMotion *event)
4118 {
4119   GtkTreeView *tree_view;
4120   GtkRBTree *tree;
4121   GtkRBNode *node;
4122   gint new_y;
4123
4124   tree_view = (GtkTreeView *) widget;
4125
4126   if (tree_view->priv->tree == NULL)
4127     return FALSE;
4128
4129   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4130     {
4131       gtk_grab_add (GTK_WIDGET (tree_view));
4132       gtk_tree_view_update_rubber_band (tree_view);
4133
4134       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4135     }
4136   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4137     {
4138       gtk_tree_view_update_rubber_band (tree_view);
4139
4140       add_scroll_timeout (tree_view);
4141     }
4142
4143   /* only check for an initiated drag when a button is pressed */
4144   if (tree_view->priv->pressed_button >= 0
4145       && !tree_view->priv->rubber_band_status)
4146     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4147
4148   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4149   if (new_y < 0)
4150     new_y = 0;
4151
4152   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4153
4154   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4155   if ((tree_view->priv->button_pressed_node != NULL) &&
4156       (tree_view->priv->button_pressed_node != node))
4157     node = NULL;
4158
4159   tree_view->priv->event_last_x = event->x;
4160   tree_view->priv->event_last_y = event->y;
4161
4162   prelight_or_select (tree_view, tree, node, event->x, event->y);
4163
4164   return TRUE;
4165 }
4166
4167 static gboolean
4168 gtk_tree_view_motion (GtkWidget      *widget,
4169                       GdkEventMotion *event)
4170 {
4171   GtkTreeView *tree_view;
4172
4173   tree_view = (GtkTreeView *) widget;
4174
4175   /* Resizing a column */
4176   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4177     return gtk_tree_view_motion_resize_column (widget, event);
4178
4179   /* Drag column */
4180   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4181     return gtk_tree_view_motion_drag_column (widget, event);
4182
4183   /* Sanity check it */
4184   if (event->window == tree_view->priv->bin_window)
4185     return gtk_tree_view_motion_bin_window (widget, event);
4186
4187   return FALSE;
4188 }
4189
4190 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4191  * the tree is empty.
4192  */
4193 static void
4194 invalidate_empty_focus (GtkTreeView *tree_view)
4195 {
4196   GdkRectangle area;
4197
4198   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4199     return;
4200
4201   area.x = 0;
4202   area.y = 0;
4203   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4204   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4205   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4206 }
4207
4208 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4209  * is empty.
4210  */
4211 static void
4212 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4213 {
4214   GtkWidget *widget = GTK_WIDGET (tree_view);
4215   gint w, h;
4216
4217   if (!gtk_widget_has_focus (widget))
4218     return;
4219
4220   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4221   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4222
4223   if (w > 0 && h > 0)
4224     gtk_paint_focus (gtk_widget_get_style (widget),
4225                      cr,
4226                      gtk_widget_get_state (widget),
4227                      widget,
4228                      NULL,
4229                      1, 1, w, h);
4230 }
4231
4232 typedef enum {
4233   GTK_TREE_VIEW_GRID_LINE,
4234   GTK_TREE_VIEW_TREE_LINE,
4235   GTK_TREE_VIEW_FOREGROUND_LINE
4236 } GtkTreeViewLineType;
4237
4238 static void
4239 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4240                          cairo_t             *cr,
4241                          GtkTreeViewLineType  type,
4242                          int                  x1,
4243                          int                  y1,
4244                          int                  x2,
4245                          int                  y2)
4246 {
4247   cairo_save (cr);
4248
4249   switch (type)
4250     {
4251     case GTK_TREE_VIEW_TREE_LINE:
4252       cairo_set_source_rgb (cr, 0, 0, 0);
4253       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4254       if (tree_view->priv->tree_line_dashes[0])
4255         cairo_set_dash (cr, 
4256                         tree_view->priv->tree_line_dashes,
4257                         2, 0.5);
4258       break;
4259     case GTK_TREE_VIEW_GRID_LINE:
4260       cairo_set_source_rgb (cr, 0, 0, 0);
4261       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4262       if (tree_view->priv->grid_line_dashes[0])
4263         cairo_set_dash (cr, 
4264                         tree_view->priv->grid_line_dashes,
4265                         2, 0.5);
4266       break;
4267     default:
4268       g_assert_not_reached ();
4269       /* fall through */
4270     case GTK_TREE_VIEW_FOREGROUND_LINE:
4271       cairo_set_line_width (cr, 1.0);
4272       gdk_cairo_set_source_color (cr,
4273                                   &gtk_widget_get_style (GTK_WIDGET (tree_view))->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4274       break;
4275     }
4276
4277   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4278   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4279   cairo_stroke (cr);
4280
4281   cairo_restore (cr);
4282 }
4283                          
4284 static void
4285 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4286                                cairo_t        *cr,
4287                                gint            n_visible_columns)
4288 {
4289   GList *list = tree_view->priv->columns;
4290   gint i = 0;
4291   gint current_x = 0;
4292
4293   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4294       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4295     return;
4296
4297   /* Only draw the lines for visible rows and columns */
4298   for (list = tree_view->priv->columns; list; list = list->next, i++)
4299     {
4300       GtkTreeViewColumn *column = list->data;
4301
4302       /* We don't want a line for the last column */
4303       if (i == n_visible_columns - 1)
4304         break;
4305
4306       if (! column->visible)
4307         continue;
4308
4309       current_x += column->width;
4310
4311       gtk_tree_view_draw_line (tree_view, cr,
4312                                GTK_TREE_VIEW_GRID_LINE,
4313                                current_x - 1, 0,
4314                                current_x - 1, tree_view->priv->height);
4315     }
4316 }
4317
4318 /* Warning: Very scary function.
4319  * Modify at your own risk
4320  *
4321  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4322  * FIXME: It's not...
4323  */
4324 static gboolean
4325 gtk_tree_view_bin_draw (GtkWidget      *widget,
4326                         cairo_t        *cr)
4327 {
4328   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4329   GtkTreePath *path;
4330   GtkStyle *style;
4331   GtkRBTree *tree;
4332   GList *list;
4333   GtkRBNode *node;
4334   GtkRBNode *cursor = NULL;
4335   GtkRBTree *cursor_tree = NULL;
4336   GtkRBNode *drag_highlight = NULL;
4337   GtkRBTree *drag_highlight_tree = NULL;
4338   GtkTreeIter iter;
4339   gint new_y;
4340   gint y_offset, cell_offset;
4341   gint max_height;
4342   gint depth;
4343   GdkRectangle background_area;
4344   GdkRectangle cell_area;
4345   GdkRectangle clip;
4346   guint flags;
4347   gint highlight_x;
4348   gint expander_cell_width;
4349   gint bin_window_width;
4350   gint bin_window_height;
4351   GtkTreePath *cursor_path;
4352   GtkTreePath *drag_dest_path;
4353   GList *first_column, *last_column;
4354   gint vertical_separator;
4355   gint horizontal_separator;
4356   gint focus_line_width;
4357   gboolean allow_rules;
4358   gboolean has_special_cell;
4359   gboolean rtl;
4360   gint n_visible_columns;
4361   gint pointer_x, pointer_y;
4362   gint grid_line_width;
4363   gboolean got_pointer = FALSE;
4364   gboolean draw_vgrid_lines, draw_hgrid_lines;
4365
4366   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4367
4368   gtk_widget_style_get (widget,
4369                         "horizontal-separator", &horizontal_separator,
4370                         "vertical-separator", &vertical_separator,
4371                         "allow-rules", &allow_rules,
4372                         "focus-line-width", &focus_line_width,
4373                         NULL);
4374
4375   if (tree_view->priv->tree == NULL)
4376     {
4377       draw_empty_focus (tree_view, cr);
4378       return TRUE;
4379     }
4380
4381   style = gtk_widget_get_style (widget);
4382
4383   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4384   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4385   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4386   cairo_clip (cr);
4387   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4388     return TRUE;
4389
4390   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4391
4392   if (new_y < 0)
4393     new_y = 0;
4394   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4395
4396   if (tree_view->priv->height < bin_window_height)
4397     {
4398       gtk_paint_flat_box (style,
4399                           cr,
4400                           gtk_widget_get_state (widget),
4401                           GTK_SHADOW_NONE,
4402                           widget,
4403                           "cell_even",
4404                           0, tree_view->priv->height,
4405                           bin_window_width,
4406                           bin_window_height - tree_view->priv->height);
4407     }
4408
4409   if (node == NULL)
4410     return TRUE;
4411
4412   /* find the path for the node */
4413   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4414                                    tree,
4415                                    node);
4416   gtk_tree_model_get_iter (tree_view->priv->model,
4417                            &iter,
4418                            path);
4419   depth = gtk_tree_path_get_depth (path);
4420   gtk_tree_path_free (path);
4421   
4422   cursor_path = NULL;
4423   drag_dest_path = NULL;
4424
4425   if (tree_view->priv->cursor)
4426     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4427
4428   if (cursor_path)
4429     _gtk_tree_view_find_node (tree_view, cursor_path,
4430                               &cursor_tree, &cursor);
4431
4432   if (tree_view->priv->drag_dest_row)
4433     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4434
4435   if (drag_dest_path)
4436     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4437                               &drag_highlight_tree, &drag_highlight);
4438
4439   draw_vgrid_lines =
4440     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4441     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4442   draw_hgrid_lines =
4443     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4444     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4445
4446   if (draw_vgrid_lines || draw_hgrid_lines)
4447     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4448   
4449   n_visible_columns = 0;
4450   for (list = tree_view->priv->columns; list; list = list->next)
4451     {
4452       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4453         continue;
4454       n_visible_columns ++;
4455     }
4456
4457   /* Find the last column */
4458   for (last_column = g_list_last (tree_view->priv->columns);
4459        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4460        last_column = last_column->prev)
4461     ;
4462
4463   /* and the first */
4464   for (first_column = g_list_first (tree_view->priv->columns);
4465        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4466        first_column = first_column->next)
4467     ;
4468
4469   /* Actually process the expose event.  To do this, we want to
4470    * start at the first node of the event, and walk the tree in
4471    * order, drawing each successive node.
4472    */
4473
4474   do
4475     {
4476       gboolean parity;
4477       gboolean is_separator = FALSE;
4478       gboolean is_first = FALSE;
4479       gboolean is_last = FALSE;
4480       
4481       is_separator = row_is_separator (tree_view, &iter, NULL);
4482
4483       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4484
4485       cell_offset = 0;
4486       highlight_x = 0; /* should match x coord of first cell */
4487       expander_cell_width = 0;
4488
4489       background_area.y = y_offset + clip.y;
4490       background_area.height = max_height;
4491
4492       flags = 0;
4493
4494       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4495         flags |= GTK_CELL_RENDERER_PRELIT;
4496
4497       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4498         flags |= GTK_CELL_RENDERER_SELECTED;
4499
4500       parity = _gtk_rbtree_node_find_parity (tree, node);
4501
4502       /* we *need* to set cell data on all cells before the call
4503        * to _has_special_cell, else _has_special_cell() does not
4504        * return a correct value.
4505        */
4506       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4507            list;
4508            list = (rtl ? list->prev : list->next))
4509         {
4510           GtkTreeViewColumn *column = list->data;
4511           gtk_tree_view_column_cell_set_cell_data (column,
4512                                                    tree_view->priv->model,
4513                                                    &iter,
4514                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4515                                                    node->children?TRUE:FALSE);
4516         }
4517
4518       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4519
4520       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4521            list;
4522            list = (rtl ? list->prev : list->next))
4523         {
4524           GtkTreeViewColumn *column = list->data;
4525           const gchar *detail = NULL;
4526           gchar new_detail[128];
4527           GtkStateType state;
4528
4529           if (!column->visible)
4530             continue;
4531
4532           if (cell_offset > clip.x + clip.width ||
4533               cell_offset + column->width < clip.x)
4534             {
4535               cell_offset += column->width;
4536               continue;
4537             }
4538
4539           if (column->show_sort_indicator)
4540             flags |= GTK_CELL_RENDERER_SORTED;
4541           else
4542             flags &= ~GTK_CELL_RENDERER_SORTED;
4543
4544           if (cursor == node)
4545             flags |= GTK_CELL_RENDERER_FOCUSED;
4546           else
4547             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4548
4549           background_area.x = cell_offset;
4550           background_area.width = column->width;
4551
4552           cell_area = background_area;
4553           cell_area.y += vertical_separator / 2;
4554           cell_area.x += horizontal_separator / 2;
4555           cell_area.height -= vertical_separator;
4556           cell_area.width -= horizontal_separator;
4557
4558           if (draw_vgrid_lines)
4559             {
4560               if (list == first_column)
4561                 {
4562                   cell_area.width -= grid_line_width / 2;
4563                 }
4564               else if (list == last_column)
4565                 {
4566                   cell_area.x += grid_line_width / 2;
4567                   cell_area.width -= grid_line_width / 2;
4568                 }
4569               else
4570                 {
4571                   cell_area.x += grid_line_width / 2;
4572                   cell_area.width -= grid_line_width;
4573                 }
4574             }
4575
4576           if (draw_hgrid_lines)
4577             {
4578               cell_area.y += grid_line_width / 2;
4579               cell_area.height -= grid_line_width;
4580             }
4581
4582           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4583             {
4584               cell_offset += column->width;
4585               continue;
4586             }
4587
4588           gtk_tree_view_column_cell_set_cell_data (column,
4589                                                    tree_view->priv->model,
4590                                                    &iter,
4591                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4592                                                    node->children?TRUE:FALSE);
4593
4594           /* Select the detail for drawing the cell.  relevant
4595            * factors are parity, sortedness, and whether to
4596            * display rules.
4597            */
4598           if (allow_rules && tree_view->priv->has_rules)
4599             {
4600               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4601                   n_visible_columns >= 3)
4602                 {
4603                   if (parity)
4604                     detail = "cell_odd_ruled_sorted";
4605                   else
4606                     detail = "cell_even_ruled_sorted";
4607                 }
4608               else
4609                 {
4610                   if (parity)
4611                     detail = "cell_odd_ruled";
4612                   else
4613                     detail = "cell_even_ruled";
4614                 }
4615             }
4616           else
4617             {
4618               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4619                   n_visible_columns >= 3)
4620                 {
4621                   if (parity)
4622                     detail = "cell_odd_sorted";
4623                   else
4624                     detail = "cell_even_sorted";
4625                 }
4626               else
4627                 {
4628                   if (parity)
4629                     detail = "cell_odd";
4630                   else
4631                     detail = "cell_even";
4632                 }
4633             }
4634
4635           g_assert (detail);
4636
4637           if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
4638             state = GTK_STATE_INSENSITIVE;          
4639           else if (flags & GTK_CELL_RENDERER_SELECTED)
4640             state = GTK_STATE_SELECTED;
4641           else
4642             state = GTK_STATE_NORMAL;
4643
4644           /* Draw background */
4645           is_first = (rtl ? !list->next : !list->prev);
4646           is_last = (rtl ? !list->prev : !list->next);
4647
4648           /* (I don't like the snprintfs either, but couldn't find a
4649            * less messy way).
4650            */
4651           if (is_first && is_last)
4652             g_snprintf (new_detail, 127, "%s", detail);
4653           else if (is_first)
4654             g_snprintf (new_detail, 127, "%s_start", detail);
4655           else if (is_last)
4656             g_snprintf (new_detail, 127, "%s_end", detail);
4657           else
4658             g_snprintf (new_detail, 127, "%s_middle", detail);
4659
4660           gtk_paint_flat_box (style,
4661                               cr,
4662                               state,
4663                               GTK_SHADOW_NONE,
4664                               widget,
4665                               new_detail,
4666                               background_area.x,
4667                               background_area.y,
4668                               background_area.width,
4669                               background_area.height);
4670
4671           if (gtk_tree_view_is_expander_column (tree_view, column))
4672             {
4673               if (!rtl)
4674                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4675               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4676
4677               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4678                 {
4679                   if (!rtl)
4680                     cell_area.x += depth * tree_view->priv->expander_size;
4681                   cell_area.width -= depth * tree_view->priv->expander_size;
4682                 }
4683
4684               /* If we have an expander column, the highlight underline
4685                * starts with that column, so that it indicates which
4686                * level of the tree we're dropping at.
4687                */
4688               highlight_x = cell_area.x;
4689               expander_cell_width = cell_area.width;
4690
4691               if (is_separator)
4692                 gtk_paint_hline (style,
4693                                  cr,
4694                                  state,
4695                                  widget,
4696                                  NULL,
4697                                  cell_area.x,
4698                                  cell_area.x + cell_area.width,
4699                                  cell_area.y + cell_area.height / 2);
4700               else
4701                 _gtk_tree_view_column_cell_render (column,
4702                                                    cr,
4703                                                    &background_area,
4704                                                    &cell_area,
4705                                                    flags);
4706               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4707                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4708                 {
4709                   if (!got_pointer)
4710                     {
4711                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4712                                               &pointer_x, &pointer_y, NULL);
4713                       got_pointer = TRUE;
4714                     }
4715
4716                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4717                                             cr,
4718                                             tree,
4719                                             node,
4720                                             pointer_x, pointer_y);
4721                 }
4722             }
4723           else
4724             {
4725               if (is_separator)
4726                 gtk_paint_hline (style,
4727                                  cr,
4728                                  state,
4729                                  widget,
4730                                  NULL,
4731                                  cell_area.x,
4732                                  cell_area.x + cell_area.width,
4733                                  cell_area.y + cell_area.height / 2);
4734               else
4735                 _gtk_tree_view_column_cell_render (column,
4736                                                    cr,
4737                                                    &background_area,
4738                                                    &cell_area,
4739                                                    flags);
4740             }
4741
4742           if (draw_hgrid_lines)
4743             {
4744               if (background_area.y > 0)
4745                 gtk_tree_view_draw_line (tree_view, cr,
4746                                          GTK_TREE_VIEW_GRID_LINE,
4747                                          background_area.x, background_area.y,
4748                                          background_area.x + background_area.width,
4749                                          background_area.y);
4750
4751               if (y_offset + max_height >= clip.height)
4752                 gtk_tree_view_draw_line (tree_view, cr,
4753                                          GTK_TREE_VIEW_GRID_LINE,
4754                                          background_area.x, background_area.y + max_height,
4755                                          background_area.x + background_area.width,
4756                                          background_area.y + max_height);
4757             }
4758
4759           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4760               tree_view->priv->tree_lines_enabled)
4761             {
4762               gint x = background_area.x;
4763               gint mult = rtl ? -1 : 1;
4764               gint y0 = background_area.y;
4765               gint y1 = background_area.y + background_area.height/2;
4766               gint y2 = background_area.y + background_area.height;
4767
4768               if (rtl)
4769                 x += background_area.width - 1;
4770
4771               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4772                   && depth > 1)
4773                 {
4774                   gtk_tree_view_draw_line (tree_view, cr,
4775                                            GTK_TREE_VIEW_TREE_LINE,
4776                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4777                                            y1,
4778                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4779                                            y1);
4780                 }
4781               else if (depth > 1)
4782                 {
4783                   gtk_tree_view_draw_line (tree_view, cr,
4784                                            GTK_TREE_VIEW_TREE_LINE,
4785                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4786                                            y1,
4787                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4788                                            y1);
4789                 }
4790
4791               if (depth > 1)
4792                 {
4793                   gint i;
4794                   GtkRBNode *tmp_node;
4795                   GtkRBTree *tmp_tree;
4796
4797                   if (!_gtk_rbtree_next (tree, node))
4798                     gtk_tree_view_draw_line (tree_view, cr,
4799                                              GTK_TREE_VIEW_TREE_LINE,
4800                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4801                                              y0,
4802                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4803                                              y1);
4804                   else
4805                     gtk_tree_view_draw_line (tree_view, cr,
4806                                              GTK_TREE_VIEW_TREE_LINE,
4807                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4808                                              y0,
4809                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4810                                              y2);
4811
4812                   tmp_node = tree->parent_node;
4813                   tmp_tree = tree->parent_tree;
4814
4815                   for (i = depth - 2; i > 0; i--)
4816                     {
4817                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4818                         gtk_tree_view_draw_line (tree_view, cr,
4819                                                  GTK_TREE_VIEW_TREE_LINE,
4820                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4821                                                  y0,
4822                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4823                                                  y2);
4824
4825                       tmp_node = tmp_tree->parent_node;
4826                       tmp_tree = tmp_tree->parent_tree;
4827                     }
4828                 }
4829             }
4830
4831           if (node == cursor && has_special_cell &&
4832               ((column == tree_view->priv->focus_column &&
4833                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4834                 gtk_widget_has_focus (widget)) ||
4835                (column == tree_view->priv->edited_column)))
4836             {
4837               _gtk_tree_view_column_cell_draw_focus (column,
4838                                                      cr,
4839                                                      &background_area,
4840                                                      &cell_area,
4841                                                      flags);
4842             }
4843
4844           cell_offset += column->width;
4845         }
4846
4847       if (node == drag_highlight)
4848         {
4849           /* Draw indicator for the drop
4850            */
4851           gint highlight_y = -1;
4852           GtkRBTree *tree = NULL;
4853           GtkRBNode *node = NULL;
4854
4855           switch (tree_view->priv->drag_dest_pos)
4856             {
4857             case GTK_TREE_VIEW_DROP_BEFORE:
4858               highlight_y = background_area.y - 1;
4859               if (highlight_y < 0)
4860                       highlight_y = 0;
4861               break;
4862
4863             case GTK_TREE_VIEW_DROP_AFTER:
4864               highlight_y = background_area.y + background_area.height - 1;
4865               break;
4866
4867             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4868             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4869               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4870
4871               if (tree == NULL)
4872                 break;
4873
4874               gtk_paint_focus (style,
4875                                cr,
4876                                gtk_widget_get_state (widget),
4877                                widget,
4878                                (is_first
4879                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4880                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4881                                 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4882                                    - focus_line_width / 2,
4883                                 gdk_window_get_width (tree_view->priv->bin_window),
4884                                 ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4885                                    - focus_line_width + 1);
4886               break;
4887             }
4888
4889           if (highlight_y >= 0)
4890             {
4891               gtk_tree_view_draw_line (tree_view, cr,
4892                                        GTK_TREE_VIEW_FOREGROUND_LINE,
4893                                        rtl ? highlight_x + expander_cell_width : highlight_x,
4894                                        highlight_y,
4895                                        rtl ? 0 : bin_window_width,
4896                                        highlight_y);
4897             }
4898         }
4899
4900       /* draw the big row-spanning focus rectangle, if needed */
4901       if (!has_special_cell && node == cursor &&
4902           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4903           gtk_widget_has_focus (widget))
4904         {
4905           gint tmp_y, tmp_height;
4906           GtkStateType focus_rect_state;
4907
4908           focus_rect_state =
4909             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4910             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4911              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4912               GTK_STATE_NORMAL));
4913
4914           if (draw_hgrid_lines)
4915             {
4916               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4917               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4918             }
4919           else
4920             {
4921               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4922               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4923             }
4924
4925           gtk_paint_focus (style,
4926                            cr,
4927                            focus_rect_state,
4928                            widget,
4929                            (is_first
4930                             ? (is_last ? "treeview" : "treeview-left" )
4931                             : (is_last ? "treeview-right" : "treeview-middle" )),
4932                            0, tmp_y,
4933                            gdk_window_get_width (tree_view->priv->bin_window),
4934                            tmp_height);
4935         }
4936
4937       y_offset += max_height;
4938       if (node->children)
4939         {
4940           GtkTreeIter parent = iter;
4941           gboolean has_child;
4942
4943           tree = node->children;
4944           node = tree->root;
4945
4946           g_assert (node != tree->nil);
4947
4948           while (node->left != tree->nil)
4949             node = node->left;
4950           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4951                                                     &iter,
4952                                                     &parent);
4953           depth++;
4954
4955           /* Sanity Check! */
4956           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4957         }
4958       else
4959         {
4960           gboolean done = FALSE;
4961
4962           do
4963             {
4964               node = _gtk_rbtree_next (tree, node);
4965               if (node != NULL)
4966                 {
4967                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4968                   done = TRUE;
4969
4970                   /* Sanity Check! */
4971                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4972                 }
4973               else
4974                 {
4975                   GtkTreeIter parent_iter = iter;
4976                   gboolean has_parent;
4977
4978                   node = tree->parent_node;
4979                   tree = tree->parent_tree;
4980                   if (tree == NULL)
4981                     /* we should go to done to free some memory */
4982                     goto done;
4983                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4984                                                            &iter,
4985                                                            &parent_iter);
4986                   depth--;
4987
4988                   /* Sanity check */
4989                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
4990                 }
4991             }
4992           while (!done);
4993         }
4994     }
4995   while (y_offset < clip.height);
4996
4997 done:
4998   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
4999
5000   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5001     gtk_tree_view_paint_rubber_band (tree_view, cr);
5002
5003   if (cursor_path)
5004     gtk_tree_path_free (cursor_path);
5005
5006   if (drag_dest_path)
5007     gtk_tree_path_free (drag_dest_path);
5008
5009   return FALSE;
5010 }
5011
5012 static gboolean
5013 gtk_tree_view_draw (GtkWidget *widget,
5014                     cairo_t   *cr)
5015 {
5016   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5017
5018   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5019     {
5020       GList *tmp_list;
5021
5022       cairo_save (cr);
5023
5024       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5025
5026       gtk_tree_view_bin_draw (widget, cr);
5027
5028       cairo_restore (cr);
5029
5030       /* We can't just chain up to Container::draw as it will try to send the
5031        * event to the headers, so we handle propagating it to our children
5032        * (eg. widgets being edited) ourselves.
5033        */
5034       tmp_list = tree_view->priv->children;
5035       while (tmp_list)
5036         {
5037           GtkTreeViewChild *child = tmp_list->data;
5038           tmp_list = tmp_list->next;
5039
5040           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5041         }
5042     }
5043
5044   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5045     {
5046       GList *list;
5047       
5048       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5049         {
5050           GtkTreeViewColumn *column = list->data;
5051
5052           if (column == tree_view->priv->drag_column)
5053             continue;
5054
5055           if (column->visible)
5056             gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5057                                           column->button,
5058                                           cr);
5059         }
5060     }
5061   
5062   if (tree_view->priv->drag_window &&
5063       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5064     {
5065       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5066                                     tree_view->priv->drag_column->button,
5067                                     cr);
5068     }
5069
5070   return TRUE;
5071 }
5072
5073 enum
5074 {
5075   DROP_HOME,
5076   DROP_RIGHT,
5077   DROP_LEFT,
5078   DROP_END
5079 };
5080
5081 /* returns 0x1 when no column has been found -- yes it's hackish */
5082 static GtkTreeViewColumn *
5083 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5084                                GtkTreeViewColumn *column,
5085                                gint               drop_position)
5086 {
5087   GtkTreeViewColumn *left_column = NULL;
5088   GtkTreeViewColumn *cur_column = NULL;
5089   GList *tmp_list;
5090
5091   if (!column->reorderable)
5092     return (GtkTreeViewColumn *)0x1;
5093
5094   switch (drop_position)
5095     {
5096       case DROP_HOME:
5097         /* find first column where we can drop */
5098         tmp_list = tree_view->priv->columns;
5099         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5100           return (GtkTreeViewColumn *)0x1;
5101
5102         while (tmp_list)
5103           {
5104             g_assert (tmp_list);
5105
5106             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5107             tmp_list = tmp_list->next;
5108
5109             if (left_column && left_column->visible == FALSE)
5110               continue;
5111
5112             if (!tree_view->priv->column_drop_func)
5113               return left_column;
5114
5115             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5116               {
5117                 left_column = cur_column;
5118                 continue;
5119               }
5120
5121             return left_column;
5122           }
5123
5124         if (!tree_view->priv->column_drop_func)
5125           return left_column;
5126
5127         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5128           return left_column;
5129         else
5130           return (GtkTreeViewColumn *)0x1;
5131         break;
5132
5133       case DROP_RIGHT:
5134         /* find first column after column where we can drop */
5135         tmp_list = tree_view->priv->columns;
5136
5137         for (; tmp_list; tmp_list = tmp_list->next)
5138           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5139             break;
5140
5141         if (!tmp_list || !tmp_list->next)
5142           return (GtkTreeViewColumn *)0x1;
5143
5144         tmp_list = tmp_list->next;
5145         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5146         tmp_list = tmp_list->next;
5147
5148         while (tmp_list)
5149           {
5150             g_assert (tmp_list);
5151
5152             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5153             tmp_list = tmp_list->next;
5154
5155             if (left_column && left_column->visible == FALSE)
5156               {
5157                 left_column = cur_column;
5158                 if (tmp_list)
5159                   tmp_list = tmp_list->next;
5160                 continue;
5161               }
5162
5163             if (!tree_view->priv->column_drop_func)
5164               return left_column;
5165
5166             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5167               {
5168                 left_column = cur_column;
5169                 continue;
5170               }
5171
5172             return left_column;
5173           }
5174
5175         if (!tree_view->priv->column_drop_func)
5176           return left_column;
5177
5178         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5179           return left_column;
5180         else
5181           return (GtkTreeViewColumn *)0x1;
5182         break;
5183
5184       case DROP_LEFT:
5185         /* find first column before column where we can drop */
5186         tmp_list = tree_view->priv->columns;
5187
5188         for (; tmp_list; tmp_list = tmp_list->next)
5189           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5190             break;
5191
5192         if (!tmp_list || !tmp_list->prev)
5193           return (GtkTreeViewColumn *)0x1;
5194
5195         tmp_list = tmp_list->prev;
5196         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5197         tmp_list = tmp_list->prev;
5198
5199         while (tmp_list)
5200           {
5201             g_assert (tmp_list);
5202
5203             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5204
5205             if (left_column && !left_column->visible)
5206               {
5207                 /*if (!tmp_list->prev)
5208                   return (GtkTreeViewColumn *)0x1;
5209                   */
5210 /*
5211                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5212                 tmp_list = tmp_list->prev->prev;
5213                 continue;*/
5214
5215                 cur_column = left_column;
5216                 if (tmp_list)
5217                   tmp_list = tmp_list->prev;
5218                 continue;
5219               }
5220
5221             if (!tree_view->priv->column_drop_func)
5222               return left_column;
5223
5224             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5225               return left_column;
5226
5227             cur_column = left_column;
5228             tmp_list = tmp_list->prev;
5229           }
5230
5231         if (!tree_view->priv->column_drop_func)
5232           return NULL;
5233
5234         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5235           return NULL;
5236         else
5237           return (GtkTreeViewColumn *)0x1;
5238         break;
5239
5240       case DROP_END:
5241         /* same as DROP_HOME case, but doing it backwards */
5242         tmp_list = g_list_last (tree_view->priv->columns);
5243         cur_column = NULL;
5244
5245         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5246           return (GtkTreeViewColumn *)0x1;
5247
5248         while (tmp_list)
5249           {
5250             g_assert (tmp_list);
5251
5252             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5253
5254             if (left_column && !left_column->visible)
5255               {
5256                 cur_column = left_column;
5257                 tmp_list = tmp_list->prev;
5258               }
5259
5260             if (!tree_view->priv->column_drop_func)
5261               return left_column;
5262
5263             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5264               return left_column;
5265
5266             cur_column = left_column;
5267             tmp_list = tmp_list->prev;
5268           }
5269
5270         if (!tree_view->priv->column_drop_func)
5271           return NULL;
5272
5273         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5274           return NULL;
5275         else
5276           return (GtkTreeViewColumn *)0x1;
5277         break;
5278     }
5279
5280   return (GtkTreeViewColumn *)0x1;
5281 }
5282
5283 static gboolean
5284 gtk_tree_view_key_press (GtkWidget   *widget,
5285                          GdkEventKey *event)
5286 {
5287   GtkTreeView *tree_view = (GtkTreeView *) widget;
5288
5289   if (tree_view->priv->rubber_band_status)
5290     {
5291       if (event->keyval == GDK_KEY_Escape)
5292         gtk_tree_view_stop_rubber_band (tree_view);
5293
5294       return TRUE;
5295     }
5296
5297   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5298     {
5299       if (event->keyval == GDK_KEY_Escape)
5300         {
5301           tree_view->priv->cur_reorder = NULL;
5302           gtk_tree_view_button_release_drag_column (widget, NULL);
5303         }
5304       return TRUE;
5305     }
5306
5307   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5308     {
5309       GList *focus_column;
5310       gboolean rtl;
5311
5312       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5313
5314       for (focus_column = tree_view->priv->columns;
5315            focus_column;
5316            focus_column = focus_column->next)
5317         {
5318           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5319
5320           if (gtk_widget_has_focus (column->button))
5321             break;
5322         }
5323
5324       if (focus_column &&
5325           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5326           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5327            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5328         {
5329           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5330
5331           if (!column->resizable)
5332             {
5333               gtk_widget_error_bell (widget);
5334               return TRUE;
5335             }
5336
5337           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5338               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5339             {
5340               GtkRequisition button_req;
5341               gint old_width = column->resized_width;
5342
5343               gtk_widget_get_preferred_size (column->button, &button_req, NULL);
5344
5345               column->resized_width = MAX (column->resized_width,
5346                                            column->width);
5347               column->resized_width -= 2;
5348               if (column->resized_width < 0)
5349                 column->resized_width = 0;
5350
5351               if (column->min_width == -1)
5352                 column->resized_width = MAX (button_req.width,
5353                                              column->resized_width);
5354               else
5355                 {
5356                   column->resized_width = MAX (column->min_width,
5357                                                column->resized_width);
5358                 }
5359
5360               if (column->max_width != -1)
5361                 column->resized_width = MIN (column->resized_width,
5362                                              column->max_width);
5363
5364               column->use_resized_width = TRUE;
5365
5366               if (column->resized_width != old_width)
5367                 gtk_widget_queue_resize (widget);
5368               else
5369                 gtk_widget_error_bell (widget);
5370             }
5371           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5372                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5373             {
5374               gint old_width = column->resized_width;
5375
5376               column->resized_width = MAX (column->resized_width,
5377                                            column->width);
5378               column->resized_width += 2;
5379
5380               if (column->max_width != -1)
5381                 column->resized_width = MIN (column->resized_width,
5382                                              column->max_width);
5383
5384               column->use_resized_width = TRUE;
5385
5386               if (column->resized_width != old_width)
5387                 gtk_widget_queue_resize (widget);
5388               else
5389                 gtk_widget_error_bell (widget);
5390             }
5391
5392           return TRUE;
5393         }
5394
5395       if (focus_column &&
5396           (event->state & GDK_MOD1_MASK) &&
5397           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5398            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5399            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5400            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5401         {
5402           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5403
5404           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5405               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5406             {
5407               GtkTreeViewColumn *col;
5408               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5409               if (col != (GtkTreeViewColumn *)0x1)
5410                 gtk_tree_view_move_column_after (tree_view, column, col);
5411               else
5412                 gtk_widget_error_bell (widget);
5413             }
5414           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5415                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5416             {
5417               GtkTreeViewColumn *col;
5418               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5419               if (col != (GtkTreeViewColumn *)0x1)
5420                 gtk_tree_view_move_column_after (tree_view, column, col);
5421               else
5422                 gtk_widget_error_bell (widget);
5423             }
5424           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5425             {
5426               GtkTreeViewColumn *col;
5427               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5428               if (col != (GtkTreeViewColumn *)0x1)
5429                 gtk_tree_view_move_column_after (tree_view, column, col);
5430               else
5431                 gtk_widget_error_bell (widget);
5432             }
5433           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5434             {
5435               GtkTreeViewColumn *col;
5436               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5437               if (col != (GtkTreeViewColumn *)0x1)
5438                 gtk_tree_view_move_column_after (tree_view, column, col);
5439               else
5440                 gtk_widget_error_bell (widget);
5441             }
5442
5443           return TRUE;
5444         }
5445     }
5446
5447   /* Chain up to the parent class.  It handles the keybindings. */
5448   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5449     return TRUE;
5450
5451   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5452     {
5453       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5454       return FALSE;
5455     }
5456
5457   /* We pass the event to the search_entry.  If its text changes, then we start
5458    * the typeahead find capabilities. */
5459   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5460       && tree_view->priv->enable_search
5461       && !tree_view->priv->search_custom_entry_set)
5462     {
5463       GdkEvent *new_event;
5464       char *old_text;
5465       const char *new_text;
5466       gboolean retval;
5467       GdkScreen *screen;
5468       gboolean text_modified;
5469       gulong popup_menu_id;
5470
5471       gtk_tree_view_ensure_interactive_directory (tree_view);
5472
5473       /* Make a copy of the current text */
5474       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5475       new_event = gdk_event_copy ((GdkEvent *) event);
5476       g_object_unref (((GdkEventKey *) new_event)->window);
5477       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5478       gtk_widget_realize (tree_view->priv->search_window);
5479
5480       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5481                                         "popup-menu", G_CALLBACK (gtk_true),
5482                                         NULL);
5483
5484       /* Move the entry off screen */
5485       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5486       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5487                        gdk_screen_get_width (screen) + 1,
5488                        gdk_screen_get_height (screen) + 1);
5489       gtk_widget_show (tree_view->priv->search_window);
5490
5491       /* Send the event to the window.  If the preedit_changed signal is emitted
5492        * during this event, we will set priv->imcontext_changed  */
5493       tree_view->priv->imcontext_changed = FALSE;
5494       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5495       gdk_event_free (new_event);
5496       gtk_widget_hide (tree_view->priv->search_window);
5497
5498       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5499                                    popup_menu_id);
5500
5501       /* We check to make sure that the entry tried to handle the text, and that
5502        * the text has changed.
5503        */
5504       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5505       text_modified = strcmp (old_text, new_text) != 0;
5506       g_free (old_text);
5507       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5508           (retval && text_modified))               /* ...or the text was modified */
5509         {
5510           if (gtk_tree_view_real_start_interactive_search (tree_view,
5511                                                            gdk_event_get_device ((GdkEvent *) event),
5512                                                            FALSE))
5513             {
5514               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5515               return TRUE;
5516             }
5517           else
5518             {
5519               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5520               return FALSE;
5521             }
5522         }
5523     }
5524
5525   return FALSE;
5526 }
5527
5528 static gboolean
5529 gtk_tree_view_key_release (GtkWidget   *widget,
5530                            GdkEventKey *event)
5531 {
5532   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5533
5534   if (tree_view->priv->rubber_band_status)
5535     return TRUE;
5536
5537   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5538 }
5539
5540 /* FIXME Is this function necessary? Can I get an enter_notify event
5541  * w/o either an expose event or a mouse motion event?
5542  */
5543 static gboolean
5544 gtk_tree_view_enter_notify (GtkWidget        *widget,
5545                             GdkEventCrossing *event)
5546 {
5547   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5548   GtkRBTree *tree;
5549   GtkRBNode *node;
5550   gint new_y;
5551
5552   /* Sanity check it */
5553   if (event->window != tree_view->priv->bin_window)
5554     return FALSE;
5555
5556   if (tree_view->priv->tree == NULL)
5557     return FALSE;
5558
5559   if (event->mode == GDK_CROSSING_GRAB ||
5560       event->mode == GDK_CROSSING_GTK_GRAB ||
5561       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5562       event->mode == GDK_CROSSING_STATE_CHANGED)
5563     return TRUE;
5564
5565   /* find the node internally */
5566   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5567   if (new_y < 0)
5568     new_y = 0;
5569   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5570
5571   tree_view->priv->event_last_x = event->x;
5572   tree_view->priv->event_last_y = event->y;
5573
5574   if ((tree_view->priv->button_pressed_node == NULL) ||
5575       (tree_view->priv->button_pressed_node == node))
5576     prelight_or_select (tree_view, tree, node, event->x, event->y);
5577
5578   return TRUE;
5579 }
5580
5581 static gboolean
5582 gtk_tree_view_leave_notify (GtkWidget        *widget,
5583                             GdkEventCrossing *event)
5584 {
5585   GtkTreeView *tree_view;
5586
5587   if (event->mode == GDK_CROSSING_GRAB)
5588     return TRUE;
5589
5590   tree_view = GTK_TREE_VIEW (widget);
5591
5592   if (tree_view->priv->prelight_node)
5593     _gtk_tree_view_queue_draw_node (tree_view,
5594                                    tree_view->priv->prelight_tree,
5595                                    tree_view->priv->prelight_node,
5596                                    NULL);
5597
5598   tree_view->priv->event_last_x = -10000;
5599   tree_view->priv->event_last_y = -10000;
5600
5601   prelight_or_select (tree_view,
5602                       NULL, NULL,
5603                       -1000, -1000); /* coords not possibly over an arrow */
5604
5605   return TRUE;
5606 }
5607
5608
5609 static gint
5610 gtk_tree_view_focus_out (GtkWidget     *widget,
5611                          GdkEventFocus *event)
5612 {
5613   GtkTreeView *tree_view;
5614
5615   tree_view = GTK_TREE_VIEW (widget);
5616
5617   gtk_widget_queue_draw (widget);
5618
5619   /* destroy interactive search dialog */
5620   if (tree_view->priv->search_window)
5621     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5622                                       gdk_event_get_device ((GdkEvent *) event));
5623
5624   return FALSE;
5625 }
5626
5627
5628 /* Incremental Reflow
5629  */
5630
5631 static void
5632 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5633                                  GtkRBTree   *tree,
5634                                  GtkRBNode   *node)
5635 {
5636   GtkAllocation allocation;
5637   gint y;
5638
5639   y = _gtk_rbtree_node_find_offset (tree, node)
5640     - tree_view->priv->vadjustment->value
5641     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5642
5643   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5644   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5645                               0, y,
5646                               allocation.width,
5647                               GTK_RBNODE_GET_HEIGHT (node));
5648 }
5649
5650 static gboolean
5651 node_is_visible (GtkTreeView *tree_view,
5652                  GtkRBTree   *tree,
5653                  GtkRBNode   *node)
5654 {
5655   int y;
5656   int height;
5657
5658   y = _gtk_rbtree_node_find_offset (tree, node);
5659   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5660
5661   if (y >= tree_view->priv->vadjustment->value &&
5662       y + height <= (tree_view->priv->vadjustment->value
5663                      + tree_view->priv->vadjustment->page_size))
5664     return TRUE;
5665
5666   return FALSE;
5667 }
5668
5669 /* Returns TRUE if it updated the size
5670  */
5671 static gboolean
5672 validate_row (GtkTreeView *tree_view,
5673               GtkRBTree   *tree,
5674               GtkRBNode   *node,
5675               GtkTreeIter *iter,
5676               GtkTreePath *path)
5677 {
5678   GtkTreeViewColumn *column;
5679   GList *list, *first_column, *last_column;
5680   gint height = 0;
5681   gint horizontal_separator;
5682   gint vertical_separator;
5683   gint focus_line_width;
5684   gint depth = gtk_tree_path_get_depth (path);
5685   gboolean retval = FALSE;
5686   gboolean is_separator = FALSE;
5687   gboolean draw_vgrid_lines, draw_hgrid_lines;
5688   gint focus_pad;
5689   gint grid_line_width;
5690   gboolean wide_separators;
5691   gint separator_height;
5692
5693   /* double check the row needs validating */
5694   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5695       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5696     return FALSE;
5697
5698   is_separator = row_is_separator (tree_view, iter, NULL);
5699
5700   gtk_widget_style_get (GTK_WIDGET (tree_view),
5701                         "focus-padding", &focus_pad,
5702                         "focus-line-width", &focus_line_width,
5703                         "horizontal-separator", &horizontal_separator,
5704                         "vertical-separator", &vertical_separator,
5705                         "grid-line-width", &grid_line_width,
5706                         "wide-separators",  &wide_separators,
5707                         "separator-height", &separator_height,
5708                         NULL);
5709   
5710   draw_vgrid_lines =
5711     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5712     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5713   draw_hgrid_lines =
5714     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5715     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5716
5717   for (last_column = g_list_last (tree_view->priv->columns);
5718        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5719        last_column = last_column->prev)
5720     ;
5721
5722   for (first_column = g_list_first (tree_view->priv->columns);
5723        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5724        first_column = first_column->next)
5725     ;
5726
5727   for (list = tree_view->priv->columns; list; list = list->next)
5728     {
5729       gint tmp_width;
5730       gint tmp_height;
5731
5732       column = list->data;
5733
5734       if (! column->visible)
5735         continue;
5736
5737       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5738         continue;
5739
5740       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5741                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5742                                                node->children?TRUE:FALSE);
5743       gtk_tree_view_column_cell_get_size (column,
5744                                           NULL, NULL, NULL,
5745                                           &tmp_width, &tmp_height);
5746
5747       if (!is_separator)
5748         {
5749           tmp_height += vertical_separator;
5750           height = MAX (height, tmp_height);
5751           height = MAX (height, tree_view->priv->expander_size);
5752         }
5753       else
5754         {
5755           if (wide_separators)
5756             height = separator_height + 2 * focus_pad;
5757           else
5758             height = 2 + 2 * focus_pad;
5759         }
5760
5761       if (gtk_tree_view_is_expander_column (tree_view, column))
5762         {
5763           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5764
5765           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5766             tmp_width += depth * tree_view->priv->expander_size;
5767         }
5768       else
5769         tmp_width = tmp_width + horizontal_separator;
5770
5771       if (draw_vgrid_lines)
5772         {
5773           if (list->data == first_column || list->data == last_column)
5774             tmp_width += grid_line_width / 2.0;
5775           else
5776             tmp_width += grid_line_width;
5777         }
5778
5779       if (tmp_width > column->requested_width)
5780         {
5781           retval = TRUE;
5782           column->requested_width = tmp_width;
5783         }
5784     }
5785
5786   if (draw_hgrid_lines)
5787     height += grid_line_width;
5788
5789   if (height != GTK_RBNODE_GET_HEIGHT (node))
5790     {
5791       retval = TRUE;
5792       _gtk_rbtree_node_set_height (tree, node, height);
5793     }
5794   _gtk_rbtree_node_mark_valid (tree, node);
5795   tree_view->priv->post_validation_flag = TRUE;
5796
5797   return retval;
5798 }
5799
5800
5801 static void
5802 validate_visible_area (GtkTreeView *tree_view)
5803 {
5804   GtkAllocation allocation;
5805   GtkTreePath *path = NULL;
5806   GtkTreePath *above_path = NULL;
5807   GtkTreeIter iter;
5808   GtkRBTree *tree = NULL;
5809   GtkRBNode *node = NULL;
5810   gboolean need_redraw = FALSE;
5811   gboolean size_changed = FALSE;
5812   gint total_height;
5813   gint area_above = 0;
5814   gint area_below = 0;
5815
5816   if (tree_view->priv->tree == NULL)
5817     return;
5818
5819   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5820       tree_view->priv->scroll_to_path == NULL)
5821     return;
5822
5823   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5824   total_height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5825
5826   if (total_height == 0)
5827     return;
5828
5829   /* First, we check to see if we need to scroll anywhere
5830    */
5831   if (tree_view->priv->scroll_to_path)
5832     {
5833       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5834       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5835         {
5836           /* we are going to scroll, and will update dy */
5837           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5838           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5839               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5840             {
5841               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5842               if (validate_row (tree_view, tree, node, &iter, path))
5843                 size_changed = TRUE;
5844             }
5845
5846           if (tree_view->priv->scroll_to_use_align)
5847             {
5848               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5849               area_above = (total_height - height) *
5850                 tree_view->priv->scroll_to_row_align;
5851               area_below = total_height - area_above - height;
5852               area_above = MAX (area_above, 0);
5853               area_below = MAX (area_below, 0);
5854             }
5855           else
5856             {
5857               /* two cases:
5858                * 1) row not visible
5859                * 2) row visible
5860                */
5861               gint dy;
5862               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5863
5864               dy = _gtk_rbtree_node_find_offset (tree, node);
5865
5866               if (dy >= tree_view->priv->vadjustment->value &&
5867                   dy + height <= (tree_view->priv->vadjustment->value
5868                                   + tree_view->priv->vadjustment->page_size))
5869                 {
5870                   /* row visible: keep the row at the same position */
5871                   area_above = dy - tree_view->priv->vadjustment->value;
5872                   area_below = (tree_view->priv->vadjustment->value +
5873                                 tree_view->priv->vadjustment->page_size)
5874                                - dy - height;
5875                 }
5876               else
5877                 {
5878                   /* row not visible */
5879                   if (dy >= 0
5880                       && dy + height <= tree_view->priv->vadjustment->page_size)
5881                     {
5882                       /* row at the beginning -- fixed */
5883                       area_above = dy;
5884                       area_below = tree_view->priv->vadjustment->page_size
5885                                    - area_above - height;
5886                     }
5887                   else if (dy >= (tree_view->priv->vadjustment->upper -
5888                                   tree_view->priv->vadjustment->page_size))
5889                     {
5890                       /* row at the end -- fixed */
5891                       area_above = dy - (tree_view->priv->vadjustment->upper -
5892                                    tree_view->priv->vadjustment->page_size);
5893                       area_below = tree_view->priv->vadjustment->page_size -
5894                                    area_above - height;
5895
5896                       if (area_below < 0)
5897                         {
5898                           area_above = tree_view->priv->vadjustment->page_size - height;
5899                           area_below = 0;
5900                         }
5901                     }
5902                   else
5903                     {
5904                       /* row somewhere in the middle, bring it to the top
5905                        * of the view
5906                        */
5907                       area_above = 0;
5908                       area_below = total_height - height;
5909                     }
5910                 }
5911             }
5912         }
5913       else
5914         /* the scroll to isn't valid; ignore it.
5915          */
5916         {
5917           if (tree_view->priv->scroll_to_path && !path)
5918             {
5919               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5920               tree_view->priv->scroll_to_path = NULL;
5921             }
5922           if (path)
5923             gtk_tree_path_free (path);
5924           path = NULL;
5925         }      
5926     }
5927
5928   /* We didn't have a scroll_to set, so we just handle things normally
5929    */
5930   if (path == NULL)
5931     {
5932       gint offset;
5933
5934       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5935                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5936                                         &tree, &node);
5937       if (node == NULL)
5938         {
5939           /* In this case, nothing has been validated */
5940           path = gtk_tree_path_new_first ();
5941           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5942         }
5943       else
5944         {
5945           path = _gtk_tree_view_find_path (tree_view, tree, node);
5946           total_height += offset;
5947         }
5948
5949       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5950
5951       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5952           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5953         {
5954           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5955           if (validate_row (tree_view, tree, node, &iter, path))
5956             size_changed = TRUE;
5957         }
5958       area_above = 0;
5959       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5960     }
5961
5962   above_path = gtk_tree_path_copy (path);
5963
5964   /* if we do not validate any row above the new top_row, we will make sure
5965    * that the row immediately above top_row has been validated. (if we do not
5966    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5967    * when invalidated that row's height will be zero. and this will mess up
5968    * scrolling).
5969    */
5970   if (area_above == 0)
5971     {
5972       GtkRBTree *tmptree;
5973       GtkRBNode *tmpnode;
5974
5975       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5976       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5977
5978       if (tmpnode)
5979         {
5980           GtkTreePath *tmppath;
5981           GtkTreeIter tmpiter;
5982
5983           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5984           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5985
5986           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
5987               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
5988             {
5989               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
5990               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
5991                 size_changed = TRUE;
5992             }
5993
5994           gtk_tree_path_free (tmppath);
5995         }
5996     }
5997
5998   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
5999    * backwards is much slower then forward, as there is no iter_prev function.
6000    * We go forwards first in case we run out of tree.  Then we go backwards to
6001    * fill out the top.
6002    */
6003   while (node && area_below > 0)
6004     {
6005       if (node->children)
6006         {
6007           GtkTreeIter parent = iter;
6008           gboolean has_child;
6009
6010           tree = node->children;
6011           node = tree->root;
6012
6013           g_assert (node != tree->nil);
6014
6015           while (node->left != tree->nil)
6016             node = node->left;
6017           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6018                                                     &iter,
6019                                                     &parent);
6020           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6021           gtk_tree_path_down (path);
6022         }
6023       else
6024         {
6025           gboolean done = FALSE;
6026           do
6027             {
6028               node = _gtk_rbtree_next (tree, node);
6029               if (node != NULL)
6030                 {
6031                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6032                   done = TRUE;
6033                   gtk_tree_path_next (path);
6034
6035                   /* Sanity Check! */
6036                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6037                 }
6038               else
6039                 {
6040                   GtkTreeIter parent_iter = iter;
6041                   gboolean has_parent;
6042
6043                   node = tree->parent_node;
6044                   tree = tree->parent_tree;
6045                   if (tree == NULL)
6046                     break;
6047                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6048                                                            &iter,
6049                                                            &parent_iter);
6050                   gtk_tree_path_up (path);
6051
6052                   /* Sanity check */
6053                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6054                 }
6055             }
6056           while (!done);
6057         }
6058
6059       if (!node)
6060         break;
6061
6062       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6063           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6064         {
6065           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6066           if (validate_row (tree_view, tree, node, &iter, path))
6067               size_changed = TRUE;
6068         }
6069
6070       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6071     }
6072   gtk_tree_path_free (path);
6073
6074   /* If we ran out of tree, and have extra area_below left, we need to add it
6075    * to area_above */
6076   if (area_below > 0)
6077     area_above += area_below;
6078
6079   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6080
6081   /* We walk backwards */
6082   while (area_above > 0)
6083     {
6084       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6085
6086       /* Always find the new path in the tree.  We cannot just assume
6087        * a gtk_tree_path_prev() is enough here, as there might be children
6088        * in between this node and the previous sibling node.  If this
6089        * appears to be a performance hotspot in profiles, we can look into
6090        * intrigate logic for keeping path, node and iter in sync like
6091        * we do for forward walks.  (Which will be hard because of the lacking
6092        * iter_prev).
6093        */
6094
6095       if (node == NULL)
6096         break;
6097
6098       gtk_tree_path_free (above_path);
6099       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6100
6101       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6102
6103       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6104           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6105         {
6106           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6107           if (validate_row (tree_view, tree, node, &iter, above_path))
6108             size_changed = TRUE;
6109         }
6110       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6111     }
6112
6113   /* if we scrolled to a path, we need to set the dy here,
6114    * and sync the top row accordingly
6115    */
6116   if (tree_view->priv->scroll_to_path)
6117     {
6118       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6119       gtk_tree_view_top_row_to_dy (tree_view);
6120
6121       need_redraw = TRUE;
6122     }
6123   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6124     {
6125       /* when we are not scrolling, we should never set dy to something
6126        * else than zero. we update top_row to be in sync with dy = 0.
6127        */
6128       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6129       gtk_tree_view_dy_to_top_row (tree_view);
6130     }
6131   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6132     {
6133       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6134       gtk_tree_view_dy_to_top_row (tree_view);
6135     }
6136   else
6137     gtk_tree_view_top_row_to_dy (tree_view);
6138
6139   /* update width/height and queue a resize */
6140   if (size_changed)
6141     {
6142       GtkRequisition requisition;
6143
6144       /* We temporarily guess a size, under the assumption that it will be the
6145        * same when we get our next size_allocate.  If we don't do this, we'll be
6146        * in an inconsistent state if we call top_row_to_dy. */
6147
6148       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6149                                      &requisition, NULL);
6150       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6151       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6152       gtk_adjustment_changed (tree_view->priv->hadjustment);
6153       gtk_adjustment_changed (tree_view->priv->vadjustment);
6154       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6155     }
6156
6157   if (tree_view->priv->scroll_to_path)
6158     {
6159       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6160       tree_view->priv->scroll_to_path = NULL;
6161     }
6162
6163   if (above_path)
6164     gtk_tree_path_free (above_path);
6165
6166   if (tree_view->priv->scroll_to_column)
6167     {
6168       tree_view->priv->scroll_to_column = NULL;
6169     }
6170   if (need_redraw)
6171     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6172 }
6173
6174 static void
6175 initialize_fixed_height_mode (GtkTreeView *tree_view)
6176 {
6177   if (!tree_view->priv->tree)
6178     return;
6179
6180   if (tree_view->priv->fixed_height < 0)
6181     {
6182       GtkTreeIter iter;
6183       GtkTreePath *path;
6184
6185       GtkRBTree *tree = NULL;
6186       GtkRBNode *node = NULL;
6187
6188       tree = tree_view->priv->tree;
6189       node = tree->root;
6190
6191       path = _gtk_tree_view_find_path (tree_view, tree, node);
6192       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6193
6194       validate_row (tree_view, tree, node, &iter, path);
6195
6196       gtk_tree_path_free (path);
6197
6198       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6199     }
6200
6201    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6202                                  tree_view->priv->fixed_height, TRUE);
6203 }
6204
6205 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6206  * the left-most uninvalidated node.  We then try walking right, validating
6207  * nodes.  Once we find a valid node, we repeat the previous process of finding
6208  * the first invalid node.
6209  */
6210
6211 static gboolean
6212 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6213 {
6214   GtkRBTree *tree = NULL;
6215   GtkRBNode *node = NULL;
6216   gboolean validated_area = FALSE;
6217   gint retval = TRUE;
6218   GtkTreePath *path = NULL;
6219   GtkTreeIter iter;
6220   GTimer *timer;
6221   gint i = 0;
6222
6223   gint prev_height = -1;
6224   gboolean fixed_height = TRUE;
6225
6226   g_assert (tree_view);
6227
6228   if (tree_view->priv->tree == NULL)
6229       return FALSE;
6230
6231   if (tree_view->priv->fixed_height_mode)
6232     {
6233       if (tree_view->priv->fixed_height < 0)
6234         initialize_fixed_height_mode (tree_view);
6235
6236       return FALSE;
6237     }
6238
6239   timer = g_timer_new ();
6240   g_timer_start (timer);
6241
6242   do
6243     {
6244       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6245         {
6246           retval = FALSE;
6247           goto done;
6248         }
6249
6250       if (path != NULL)
6251         {
6252           node = _gtk_rbtree_next (tree, node);
6253           if (node != NULL)
6254             {
6255               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6256               gtk_tree_path_next (path);
6257             }
6258           else
6259             {
6260               gtk_tree_path_free (path);
6261               path = NULL;
6262             }
6263         }
6264
6265       if (path == NULL)
6266         {
6267           tree = tree_view->priv->tree;
6268           node = tree_view->priv->tree->root;
6269
6270           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6271
6272           do
6273             {
6274               if (node->left != tree->nil &&
6275                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6276                 {
6277                   node = node->left;
6278                 }
6279               else if (node->right != tree->nil &&
6280                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6281                 {
6282                   node = node->right;
6283                 }
6284               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6285                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6286                 {
6287                   break;
6288                 }
6289               else if (node->children != NULL)
6290                 {
6291                   tree = node->children;
6292                   node = tree->root;
6293                 }
6294               else
6295                 /* RBTree corruption!  All bad */
6296                 g_assert_not_reached ();
6297             }
6298           while (TRUE);
6299           path = _gtk_tree_view_find_path (tree_view, tree, node);
6300           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6301         }
6302
6303       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6304                        validated_area;
6305
6306       if (!tree_view->priv->fixed_height_check)
6307         {
6308           gint height;
6309
6310           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6311           if (prev_height < 0)
6312             prev_height = height;
6313           else if (prev_height != height)
6314             fixed_height = FALSE;
6315         }
6316
6317       i++;
6318     }
6319   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6320
6321   if (!tree_view->priv->fixed_height_check)
6322    {
6323      if (fixed_height)
6324        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6325
6326      tree_view->priv->fixed_height_check = 1;
6327    }
6328   
6329  done:
6330   if (validated_area)
6331     {
6332       GtkRequisition requisition;
6333       /* We temporarily guess a size, under the assumption that it will be the
6334        * same when we get our next size_allocate.  If we don't do this, we'll be
6335        * in an inconsistent state when we call top_row_to_dy. */
6336
6337       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6338                                      &requisition, NULL);
6339       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6340       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6341       gtk_adjustment_changed (tree_view->priv->hadjustment);
6342       gtk_adjustment_changed (tree_view->priv->vadjustment);
6343
6344       if (queue_resize)
6345         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6346     }
6347
6348   if (path) gtk_tree_path_free (path);
6349   g_timer_destroy (timer);
6350
6351   return retval;
6352 }
6353
6354 static gboolean
6355 validate_rows (GtkTreeView *tree_view)
6356 {
6357   gboolean retval;
6358   
6359   retval = do_validate_rows (tree_view, TRUE);
6360   
6361   if (! retval && tree_view->priv->validate_rows_timer)
6362     {
6363       g_source_remove (tree_view->priv->validate_rows_timer);
6364       tree_view->priv->validate_rows_timer = 0;
6365     }
6366
6367   return retval;
6368 }
6369
6370 static gboolean
6371 validate_rows_handler (GtkTreeView *tree_view)
6372 {
6373   gboolean retval;
6374
6375   retval = do_validate_rows (tree_view, TRUE);
6376   if (! retval && tree_view->priv->validate_rows_timer)
6377     {
6378       g_source_remove (tree_view->priv->validate_rows_timer);
6379       tree_view->priv->validate_rows_timer = 0;
6380     }
6381
6382   return retval;
6383 }
6384
6385 static gboolean
6386 do_presize_handler (GtkTreeView *tree_view)
6387 {
6388   if (tree_view->priv->mark_rows_col_dirty)
6389     {
6390       if (tree_view->priv->tree)
6391         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6392       tree_view->priv->mark_rows_col_dirty = FALSE;
6393     }
6394   validate_visible_area (tree_view);
6395   tree_view->priv->presize_handler_timer = 0;
6396
6397   if (tree_view->priv->fixed_height_mode)
6398     {
6399       GtkRequisition requisition;
6400
6401       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6402                                      &requisition, NULL);
6403
6404       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6405       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6406       gtk_adjustment_changed (tree_view->priv->hadjustment);
6407       gtk_adjustment_changed (tree_view->priv->vadjustment);
6408       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6409     }
6410                    
6411   return FALSE;
6412 }
6413
6414 static gboolean
6415 presize_handler_callback (gpointer data)
6416 {
6417   do_presize_handler (GTK_TREE_VIEW (data));
6418                    
6419   return FALSE;
6420 }
6421
6422 static void
6423 install_presize_handler (GtkTreeView *tree_view)
6424 {
6425   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6426     return;
6427
6428   if (! tree_view->priv->presize_handler_timer)
6429     {
6430       tree_view->priv->presize_handler_timer =
6431         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6432     }
6433   if (! tree_view->priv->validate_rows_timer)
6434     {
6435       tree_view->priv->validate_rows_timer =
6436         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6437     }
6438 }
6439
6440 static void
6441 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6442 {
6443   /* Prior to drawing, we make sure the visible area is validated. */
6444   if (tree_view->priv->presize_handler_timer)
6445     {
6446       g_source_remove (tree_view->priv->presize_handler_timer);
6447       tree_view->priv->presize_handler_timer = 0;
6448
6449       do_presize_handler (tree_view);
6450     }
6451
6452   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6453 }
6454
6455 static gboolean
6456 scroll_sync_handler (GtkTreeView *tree_view)
6457 {
6458   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6459     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6460   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6461     gtk_tree_view_top_row_to_dy (tree_view);
6462   else
6463     gtk_tree_view_dy_to_top_row (tree_view);
6464
6465   tree_view->priv->scroll_sync_timer = 0;
6466
6467   return FALSE;
6468 }
6469
6470 static void
6471 install_scroll_sync_handler (GtkTreeView *tree_view)
6472 {
6473   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6474     return;
6475
6476   if (!tree_view->priv->scroll_sync_timer)
6477     {
6478       tree_view->priv->scroll_sync_timer =
6479         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6480     }
6481 }
6482
6483 static void
6484 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6485                            GtkTreePath *path,
6486                            gint         offset)
6487 {
6488   gtk_tree_row_reference_free (tree_view->priv->top_row);
6489
6490   if (!path)
6491     {
6492       tree_view->priv->top_row = NULL;
6493       tree_view->priv->top_row_dy = 0;
6494     }
6495   else
6496     {
6497       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6498       tree_view->priv->top_row_dy = offset;
6499     }
6500 }
6501
6502 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6503  * it's set to be NULL, and top_row_dy is 0;
6504  */
6505 static void
6506 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6507 {
6508   gint offset;
6509   GtkTreePath *path;
6510   GtkRBTree *tree;
6511   GtkRBNode *node;
6512
6513   if (tree_view->priv->tree == NULL)
6514     {
6515       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6516     }
6517   else
6518     {
6519       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6520                                         tree_view->priv->dy,
6521                                         &tree, &node);
6522
6523       if (tree == NULL)
6524         {
6525           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6526         }
6527       else
6528         {
6529           path = _gtk_tree_view_find_path (tree_view, tree, node);
6530           gtk_tree_view_set_top_row (tree_view, path, offset);
6531           gtk_tree_path_free (path);
6532         }
6533     }
6534 }
6535
6536 static void
6537 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6538 {
6539   GtkTreePath *path;
6540   GtkRBTree *tree;
6541   GtkRBNode *node;
6542   int new_dy;
6543
6544   /* Avoid recursive calls */
6545   if (tree_view->priv->in_top_row_to_dy)
6546     return;
6547
6548   if (tree_view->priv->top_row)
6549     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6550   else
6551     path = NULL;
6552
6553   if (!path)
6554     tree = NULL;
6555   else
6556     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6557
6558   if (path)
6559     gtk_tree_path_free (path);
6560
6561   if (tree == NULL)
6562     {
6563       /* keep dy and set new toprow */
6564       gtk_tree_row_reference_free (tree_view->priv->top_row);
6565       tree_view->priv->top_row = NULL;
6566       tree_view->priv->top_row_dy = 0;
6567       /* DO NOT install the idle handler */
6568       gtk_tree_view_dy_to_top_row (tree_view);
6569       return;
6570     }
6571
6572   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6573       < tree_view->priv->top_row_dy)
6574     {
6575       /* new top row -- do NOT install the idle handler */
6576       gtk_tree_view_dy_to_top_row (tree_view);
6577       return;
6578     }
6579
6580   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6581   new_dy += tree_view->priv->top_row_dy;
6582
6583   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6584     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6585
6586   new_dy = MAX (0, new_dy);
6587
6588   tree_view->priv->in_top_row_to_dy = TRUE;
6589   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6590   tree_view->priv->in_top_row_to_dy = FALSE;
6591 }
6592
6593
6594 void
6595 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6596 {
6597   tree_view->priv->mark_rows_col_dirty = TRUE;
6598
6599   install_presize_handler (tree_view);
6600 }
6601
6602 /*
6603  * This function works synchronously (due to the while (validate_rows...)
6604  * loop).
6605  *
6606  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6607  * here. You now need to check that yourself.
6608  */
6609 void
6610 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6611                                 GtkTreeViewColumn *column)
6612 {
6613   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6614   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6615
6616   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6617
6618   do_presize_handler (tree_view);
6619   while (validate_rows (tree_view));
6620
6621   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6622 }
6623
6624 /* Drag-and-drop */
6625
6626 static void
6627 set_source_row (GdkDragContext *context,
6628                 GtkTreeModel   *model,
6629                 GtkTreePath    *source_row)
6630 {
6631   g_object_set_data_full (G_OBJECT (context),
6632                           I_("gtk-tree-view-source-row"),
6633                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6634                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6635 }
6636
6637 static GtkTreePath*
6638 get_source_row (GdkDragContext *context)
6639 {
6640   GtkTreeRowReference *ref =
6641     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6642
6643   if (ref)
6644     return gtk_tree_row_reference_get_path (ref);
6645   else
6646     return NULL;
6647 }
6648
6649 typedef struct
6650 {
6651   GtkTreeRowReference *dest_row;
6652   guint                path_down_mode   : 1;
6653   guint                empty_view_drop  : 1;
6654   guint                drop_append_mode : 1;
6655 }
6656 DestRow;
6657
6658 static void
6659 dest_row_free (gpointer data)
6660 {
6661   DestRow *dr = (DestRow *)data;
6662
6663   gtk_tree_row_reference_free (dr->dest_row);
6664   g_slice_free (DestRow, dr);
6665 }
6666
6667 static void
6668 set_dest_row (GdkDragContext *context,
6669               GtkTreeModel   *model,
6670               GtkTreePath    *dest_row,
6671               gboolean        path_down_mode,
6672               gboolean        empty_view_drop,
6673               gboolean        drop_append_mode)
6674 {
6675   DestRow *dr;
6676
6677   if (!dest_row)
6678     {
6679       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6680                               NULL, NULL);
6681       return;
6682     }
6683
6684   dr = g_slice_new (DestRow);
6685
6686   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6687   dr->path_down_mode = path_down_mode != FALSE;
6688   dr->empty_view_drop = empty_view_drop != FALSE;
6689   dr->drop_append_mode = drop_append_mode != FALSE;
6690
6691   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6692                           dr, (GDestroyNotify) dest_row_free);
6693 }
6694
6695 static GtkTreePath*
6696 get_dest_row (GdkDragContext *context,
6697               gboolean       *path_down_mode)
6698 {
6699   DestRow *dr =
6700     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6701
6702   if (dr)
6703     {
6704       GtkTreePath *path = NULL;
6705
6706       if (path_down_mode)
6707         *path_down_mode = dr->path_down_mode;
6708
6709       if (dr->dest_row)
6710         path = gtk_tree_row_reference_get_path (dr->dest_row);
6711       else if (dr->empty_view_drop)
6712         path = gtk_tree_path_new_from_indices (0, -1);
6713       else
6714         path = NULL;
6715
6716       if (path && dr->drop_append_mode)
6717         gtk_tree_path_next (path);
6718
6719       return path;
6720     }
6721   else
6722     return NULL;
6723 }
6724
6725 /* Get/set whether drag_motion requested the drag data and
6726  * drag_data_received should thus not actually insert the data,
6727  * since the data doesn't result from a drop.
6728  */
6729 static void
6730 set_status_pending (GdkDragContext *context,
6731                     GdkDragAction   suggested_action)
6732 {
6733   g_object_set_data (G_OBJECT (context),
6734                      I_("gtk-tree-view-status-pending"),
6735                      GINT_TO_POINTER (suggested_action));
6736 }
6737
6738 static GdkDragAction
6739 get_status_pending (GdkDragContext *context)
6740 {
6741   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6742                                              "gtk-tree-view-status-pending"));
6743 }
6744
6745 static TreeViewDragInfo*
6746 get_info (GtkTreeView *tree_view)
6747 {
6748   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6749 }
6750
6751 static void
6752 destroy_info (TreeViewDragInfo *di)
6753 {
6754   g_slice_free (TreeViewDragInfo, di);
6755 }
6756
6757 static TreeViewDragInfo*
6758 ensure_info (GtkTreeView *tree_view)
6759 {
6760   TreeViewDragInfo *di;
6761
6762   di = get_info (tree_view);
6763
6764   if (di == NULL)
6765     {
6766       di = g_slice_new0 (TreeViewDragInfo);
6767
6768       g_object_set_data_full (G_OBJECT (tree_view),
6769                               I_("gtk-tree-view-drag-info"),
6770                               di,
6771                               (GDestroyNotify) destroy_info);
6772     }
6773
6774   return di;
6775 }
6776
6777 static void
6778 remove_info (GtkTreeView *tree_view)
6779 {
6780   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6781 }
6782
6783 #if 0
6784 static gint
6785 drag_scan_timeout (gpointer data)
6786 {
6787   GtkTreeView *tree_view;
6788   gint x, y;
6789   GdkModifierType state;
6790   GtkTreePath *path = NULL;
6791   GtkTreeViewColumn *column = NULL;
6792   GdkRectangle visible_rect;
6793
6794   GDK_THREADS_ENTER ();
6795
6796   tree_view = GTK_TREE_VIEW (data);
6797
6798   gdk_window_get_pointer (tree_view->priv->bin_window,
6799                           &x, &y, &state);
6800
6801   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6802
6803   /* See if we are near the edge. */
6804   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6805       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6806       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6807       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6808     {
6809       gtk_tree_view_get_path_at_pos (tree_view,
6810                                      tree_view->priv->bin_window,
6811                                      x, y,
6812                                      &path,
6813                                      &column,
6814                                      NULL,
6815                                      NULL);
6816
6817       if (path != NULL)
6818         {
6819           gtk_tree_view_scroll_to_cell (tree_view,
6820                                         path,
6821                                         column,
6822                                         TRUE,
6823                                         0.5, 0.5);
6824
6825           gtk_tree_path_free (path);
6826         }
6827     }
6828
6829   GDK_THREADS_LEAVE ();
6830
6831   return TRUE;
6832 }
6833 #endif /* 0 */
6834
6835 static void
6836 add_scroll_timeout (GtkTreeView *tree_view)
6837 {
6838   if (tree_view->priv->scroll_timeout == 0)
6839     {
6840       tree_view->priv->scroll_timeout =
6841         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6842     }
6843 }
6844
6845 static void
6846 remove_scroll_timeout (GtkTreeView *tree_view)
6847 {
6848   if (tree_view->priv->scroll_timeout != 0)
6849     {
6850       g_source_remove (tree_view->priv->scroll_timeout);
6851       tree_view->priv->scroll_timeout = 0;
6852     }
6853 }
6854
6855 static gboolean
6856 check_model_dnd (GtkTreeModel *model,
6857                  GType         required_iface,
6858                  const gchar  *signal)
6859 {
6860   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6861     {
6862       g_warning ("You must override the default '%s' handler "
6863                  "on GtkTreeView when using models that don't support "
6864                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6865                  "is to connect to '%s' and call "
6866                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6867                  "the default handler from running. Look at the source code "
6868                  "for the default handler in gtktreeview.c to get an idea what "
6869                  "your handler should do. (gtktreeview.c is in the GTK source "
6870                  "code.) If you're using GTK from a language other than C, "
6871                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6872                  signal, g_type_name (required_iface), signal);
6873       return FALSE;
6874     }
6875   else
6876     return TRUE;
6877 }
6878
6879 static void
6880 remove_open_timeout (GtkTreeView *tree_view)
6881 {
6882   if (tree_view->priv->open_dest_timeout != 0)
6883     {
6884       g_source_remove (tree_view->priv->open_dest_timeout);
6885       tree_view->priv->open_dest_timeout = 0;
6886     }
6887 }
6888
6889
6890 static gint
6891 open_row_timeout (gpointer data)
6892 {
6893   GtkTreeView *tree_view = data;
6894   GtkTreePath *dest_path = NULL;
6895   GtkTreeViewDropPosition pos;
6896   gboolean result = FALSE;
6897
6898   gtk_tree_view_get_drag_dest_row (tree_view,
6899                                    &dest_path,
6900                                    &pos);
6901
6902   if (dest_path &&
6903       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6904        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6905     {
6906       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6907       tree_view->priv->open_dest_timeout = 0;
6908
6909       gtk_tree_path_free (dest_path);
6910     }
6911   else
6912     {
6913       if (dest_path)
6914         gtk_tree_path_free (dest_path);
6915
6916       result = TRUE;
6917     }
6918
6919   return result;
6920 }
6921
6922 static gboolean
6923 scroll_row_timeout (gpointer data)
6924 {
6925   GtkTreeView *tree_view = data;
6926
6927   gtk_tree_view_vertical_autoscroll (tree_view);
6928
6929   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6930     gtk_tree_view_update_rubber_band (tree_view);
6931
6932   return TRUE;
6933 }
6934
6935 /* Returns TRUE if event should not be propagated to parent widgets */
6936 static gboolean
6937 set_destination_row (GtkTreeView    *tree_view,
6938                      GdkDragContext *context,
6939                      /* coordinates relative to the widget */
6940                      gint            x,
6941                      gint            y,
6942                      GdkDragAction  *suggested_action,
6943                      GdkAtom        *target)
6944 {
6945   GtkTreePath *path = NULL;
6946   GtkTreeViewDropPosition pos;
6947   GtkTreeViewDropPosition old_pos;
6948   TreeViewDragInfo *di;
6949   GtkWidget *widget;
6950   GtkTreePath *old_dest_path = NULL;
6951   gboolean can_drop = FALSE;
6952
6953   *suggested_action = 0;
6954   *target = GDK_NONE;
6955
6956   widget = GTK_WIDGET (tree_view);
6957
6958   di = get_info (tree_view);
6959
6960   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6961     {
6962       /* someone unset us as a drag dest, note that if
6963        * we return FALSE drag_leave isn't called
6964        */
6965
6966       gtk_tree_view_set_drag_dest_row (tree_view,
6967                                        NULL,
6968                                        GTK_TREE_VIEW_DROP_BEFORE);
6969
6970       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6971       remove_open_timeout (GTK_TREE_VIEW (widget));
6972
6973       return FALSE; /* no longer a drop site */
6974     }
6975
6976   *target = gtk_drag_dest_find_target (widget, context,
6977                                        gtk_drag_dest_get_target_list (widget));
6978   if (*target == GDK_NONE)
6979     {
6980       return FALSE;
6981     }
6982
6983   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6984                                           x, y,
6985                                           &path,
6986                                           &pos))
6987     {
6988       gint n_children;
6989       GtkTreeModel *model;
6990
6991       remove_open_timeout (tree_view);
6992
6993       /* the row got dropped on empty space, let's setup a special case
6994        */
6995
6996       if (path)
6997         gtk_tree_path_free (path);
6998
6999       model = gtk_tree_view_get_model (tree_view);
7000
7001       n_children = gtk_tree_model_iter_n_children (model, NULL);
7002       if (n_children)
7003         {
7004           pos = GTK_TREE_VIEW_DROP_AFTER;
7005           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7006         }
7007       else
7008         {
7009           pos = GTK_TREE_VIEW_DROP_BEFORE;
7010           path = gtk_tree_path_new_from_indices (0, -1);
7011         }
7012
7013       can_drop = TRUE;
7014
7015       goto out;
7016     }
7017
7018   g_assert (path);
7019
7020   /* If we left the current row's "open" zone, unset the timeout for
7021    * opening the row
7022    */
7023   gtk_tree_view_get_drag_dest_row (tree_view,
7024                                    &old_dest_path,
7025                                    &old_pos);
7026
7027   if (old_dest_path &&
7028       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7029        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7030          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7031     remove_open_timeout (tree_view);
7032
7033   if (old_dest_path)
7034     gtk_tree_path_free (old_dest_path);
7035
7036   if (TRUE /* FIXME if the location droppable predicate */)
7037     {
7038       can_drop = TRUE;
7039     }
7040
7041 out:
7042   if (can_drop)
7043     {
7044       GtkWidget *source_widget;
7045
7046       *suggested_action = context->suggested_action;
7047       source_widget = gtk_drag_get_source_widget (context);
7048
7049       if (source_widget == widget)
7050         {
7051           /* Default to MOVE, unless the user has
7052            * pressed ctrl or shift to affect available actions
7053            */
7054           if ((context->actions & GDK_ACTION_MOVE) != 0)
7055             *suggested_action = GDK_ACTION_MOVE;
7056         }
7057
7058       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7059                                        path, pos);
7060     }
7061   else
7062     {
7063       /* can't drop here */
7064       remove_open_timeout (tree_view);
7065
7066       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7067                                        NULL,
7068                                        GTK_TREE_VIEW_DROP_BEFORE);
7069     }
7070
7071   if (path)
7072     gtk_tree_path_free (path);
7073
7074   return TRUE;
7075 }
7076
7077 static GtkTreePath*
7078 get_logical_dest_row (GtkTreeView *tree_view,
7079                       gboolean    *path_down_mode,
7080                       gboolean    *drop_append_mode)
7081 {
7082   /* adjust path to point to the row the drop goes in front of */
7083   GtkTreePath *path = NULL;
7084   GtkTreeViewDropPosition pos;
7085
7086   g_return_val_if_fail (path_down_mode != NULL, NULL);
7087   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7088
7089   *path_down_mode = FALSE;
7090   *drop_append_mode = 0;
7091
7092   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7093
7094   if (path == NULL)
7095     return NULL;
7096
7097   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7098     ; /* do nothing */
7099   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7100            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7101     *path_down_mode = TRUE;
7102   else
7103     {
7104       GtkTreeIter iter;
7105       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7106
7107       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7108
7109       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7110           !gtk_tree_model_iter_next (model, &iter))
7111         *drop_append_mode = 1;
7112       else
7113         {
7114           *drop_append_mode = 0;
7115           gtk_tree_path_next (path);
7116         }
7117     }
7118
7119   return path;
7120 }
7121
7122 static gboolean
7123 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7124                                         GdkEventMotion   *event)
7125 {
7126   GtkWidget *widget = GTK_WIDGET (tree_view);
7127   GdkDragContext *context;
7128   TreeViewDragInfo *di;
7129   GtkTreePath *path = NULL;
7130   gint button;
7131   gint cell_x, cell_y;
7132   GtkTreeModel *model;
7133   gboolean retval = FALSE;
7134
7135   di = get_info (tree_view);
7136
7137   if (di == NULL || !di->source_set)
7138     goto out;
7139
7140   if (tree_view->priv->pressed_button < 0)
7141     goto out;
7142
7143   if (!gtk_drag_check_threshold (widget,
7144                                  tree_view->priv->press_start_x,
7145                                  tree_view->priv->press_start_y,
7146                                  event->x, event->y))
7147     goto out;
7148
7149   model = gtk_tree_view_get_model (tree_view);
7150
7151   if (model == NULL)
7152     goto out;
7153
7154   button = tree_view->priv->pressed_button;
7155   tree_view->priv->pressed_button = -1;
7156
7157   gtk_tree_view_get_path_at_pos (tree_view,
7158                                  tree_view->priv->press_start_x,
7159                                  tree_view->priv->press_start_y,
7160                                  &path,
7161                                  NULL,
7162                                  &cell_x,
7163                                  &cell_y);
7164
7165   if (path == NULL)
7166     goto out;
7167
7168   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7169       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7170                                            path))
7171     goto out;
7172
7173   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7174     goto out;
7175
7176   /* Now we can begin the drag */
7177
7178   retval = TRUE;
7179
7180   context = gtk_drag_begin (widget,
7181                             gtk_drag_source_get_target_list (widget),
7182                             di->source_actions,
7183                             button,
7184                             (GdkEvent*)event);
7185
7186   set_source_row (context, model, path);
7187
7188  out:
7189   if (path)
7190     gtk_tree_path_free (path);
7191
7192   return retval;
7193 }
7194
7195
7196 static void
7197 gtk_tree_view_drag_begin (GtkWidget      *widget,
7198                           GdkDragContext *context)
7199 {
7200   GtkTreeView *tree_view;
7201   GtkTreePath *path = NULL;
7202   gint cell_x, cell_y;
7203   cairo_surface_t *row_pix;
7204   TreeViewDragInfo *di;
7205
7206   tree_view = GTK_TREE_VIEW (widget);
7207
7208   /* if the user uses a custom DND source impl, we don't set the icon here */
7209   di = get_info (tree_view);
7210
7211   if (di == NULL || !di->source_set)
7212     return;
7213
7214   gtk_tree_view_get_path_at_pos (tree_view,
7215                                  tree_view->priv->press_start_x,
7216                                  tree_view->priv->press_start_y,
7217                                  &path,
7218                                  NULL,
7219                                  &cell_x,
7220                                  &cell_y);
7221
7222   g_return_if_fail (path != NULL);
7223
7224   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7225                                                 path);
7226   cairo_surface_set_device_offset (row_pix,
7227                                    /* the + 1 is for the black border in the icon */
7228                                    - (tree_view->priv->press_start_x + 1),
7229                                    - (cell_y + 1));
7230
7231   gtk_drag_set_icon_surface (context, row_pix);
7232
7233   cairo_surface_destroy (row_pix);
7234   gtk_tree_path_free (path);
7235 }
7236
7237 static void
7238 gtk_tree_view_drag_end (GtkWidget      *widget,
7239                         GdkDragContext *context)
7240 {
7241   /* do nothing */
7242 }
7243
7244 /* Default signal implementations for the drag signals */
7245 static void
7246 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7247                              GdkDragContext   *context,
7248                              GtkSelectionData *selection_data,
7249                              guint             info,
7250                              guint             time)
7251 {
7252   GtkTreeView *tree_view;
7253   GtkTreeModel *model;
7254   TreeViewDragInfo *di;
7255   GtkTreePath *source_row;
7256
7257   tree_view = GTK_TREE_VIEW (widget);
7258
7259   model = gtk_tree_view_get_model (tree_view);
7260
7261   if (model == NULL)
7262     return;
7263
7264   di = get_info (GTK_TREE_VIEW (widget));
7265
7266   if (di == NULL)
7267     return;
7268
7269   source_row = get_source_row (context);
7270
7271   if (source_row == NULL)
7272     return;
7273
7274   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7275    * any model; for DragSource models there are some other targets
7276    * we also support.
7277    */
7278
7279   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7280       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7281                                           source_row,
7282                                           selection_data))
7283     goto done;
7284
7285   /* If drag_data_get does nothing, try providing row data. */
7286   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7287     {
7288       gtk_tree_set_row_drag_data (selection_data,
7289                                   model,
7290                                   source_row);
7291     }
7292
7293  done:
7294   gtk_tree_path_free (source_row);
7295 }
7296
7297
7298 static void
7299 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7300                                 GdkDragContext *context)
7301 {
7302   TreeViewDragInfo *di;
7303   GtkTreeModel *model;
7304   GtkTreeView *tree_view;
7305   GtkTreePath *source_row;
7306
7307   tree_view = GTK_TREE_VIEW (widget);
7308   model = gtk_tree_view_get_model (tree_view);
7309
7310   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7311     return;
7312
7313   di = get_info (tree_view);
7314
7315   if (di == NULL)
7316     return;
7317
7318   source_row = get_source_row (context);
7319
7320   if (source_row == NULL)
7321     return;
7322
7323   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7324                                          source_row);
7325
7326   gtk_tree_path_free (source_row);
7327
7328   set_source_row (context, NULL, NULL);
7329 }
7330
7331 static void
7332 gtk_tree_view_drag_leave (GtkWidget      *widget,
7333                           GdkDragContext *context,
7334                           guint             time)
7335 {
7336   /* unset any highlight row */
7337   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7338                                    NULL,
7339                                    GTK_TREE_VIEW_DROP_BEFORE);
7340
7341   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7342   remove_open_timeout (GTK_TREE_VIEW (widget));
7343 }
7344
7345
7346 static gboolean
7347 gtk_tree_view_drag_motion (GtkWidget        *widget,
7348                            GdkDragContext   *context,
7349                            /* coordinates relative to the widget */
7350                            gint              x,
7351                            gint              y,
7352                            guint             time)
7353 {
7354   gboolean empty;
7355   GtkTreePath *path = NULL;
7356   GtkTreeViewDropPosition pos;
7357   GtkTreeView *tree_view;
7358   GdkDragAction suggested_action = 0;
7359   GdkAtom target;
7360
7361   tree_view = GTK_TREE_VIEW (widget);
7362
7363   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7364     return FALSE;
7365
7366   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7367
7368   /* we only know this *after* set_desination_row */
7369   empty = tree_view->priv->empty_view_drop;
7370
7371   if (path == NULL && !empty)
7372     {
7373       /* Can't drop here. */
7374       gdk_drag_status (context, 0, time);
7375     }
7376   else
7377     {
7378       if (tree_view->priv->open_dest_timeout == 0 &&
7379           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7380            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7381         {
7382           tree_view->priv->open_dest_timeout =
7383             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7384         }
7385       else
7386         {
7387           add_scroll_timeout (tree_view);
7388         }
7389
7390       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7391         {
7392           /* Request data so we can use the source row when
7393            * determining whether to accept the drop
7394            */
7395           set_status_pending (context, suggested_action);
7396           gtk_drag_get_data (widget, context, target, time);
7397         }
7398       else
7399         {
7400           set_status_pending (context, 0);
7401           gdk_drag_status (context, suggested_action, time);
7402         }
7403     }
7404
7405   if (path)
7406     gtk_tree_path_free (path);
7407
7408   return TRUE;
7409 }
7410
7411
7412 static gboolean
7413 gtk_tree_view_drag_drop (GtkWidget        *widget,
7414                          GdkDragContext   *context,
7415                          /* coordinates relative to the widget */
7416                          gint              x,
7417                          gint              y,
7418                          guint             time)
7419 {
7420   GtkTreeView *tree_view;
7421   GtkTreePath *path;
7422   GdkDragAction suggested_action = 0;
7423   GdkAtom target = GDK_NONE;
7424   TreeViewDragInfo *di;
7425   GtkTreeModel *model;
7426   gboolean path_down_mode;
7427   gboolean drop_append_mode;
7428
7429   tree_view = GTK_TREE_VIEW (widget);
7430
7431   model = gtk_tree_view_get_model (tree_view);
7432
7433   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7434   remove_open_timeout (GTK_TREE_VIEW (widget));
7435
7436   di = get_info (tree_view);
7437
7438   if (di == NULL)
7439     return FALSE;
7440
7441   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7442     return FALSE;
7443
7444   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7445     return FALSE;
7446
7447   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7448
7449   if (target != GDK_NONE && path != NULL)
7450     {
7451       /* in case a motion had requested drag data, change things so we
7452        * treat drag data receives as a drop.
7453        */
7454       set_status_pending (context, 0);
7455       set_dest_row (context, model, path,
7456                     path_down_mode, tree_view->priv->empty_view_drop,
7457                     drop_append_mode);
7458     }
7459
7460   if (path)
7461     gtk_tree_path_free (path);
7462
7463   /* Unset this thing */
7464   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7465                                    NULL,
7466                                    GTK_TREE_VIEW_DROP_BEFORE);
7467
7468   if (target != GDK_NONE)
7469     {
7470       gtk_drag_get_data (widget, context, target, time);
7471       return TRUE;
7472     }
7473   else
7474     return FALSE;
7475 }
7476
7477 static void
7478 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7479                                   GdkDragContext   *context,
7480                                   /* coordinates relative to the widget */
7481                                   gint              x,
7482                                   gint              y,
7483                                   GtkSelectionData *selection_data,
7484                                   guint             info,
7485                                   guint             time)
7486 {
7487   GtkTreePath *path;
7488   TreeViewDragInfo *di;
7489   gboolean accepted = FALSE;
7490   GtkTreeModel *model;
7491   GtkTreeView *tree_view;
7492   GtkTreePath *dest_row;
7493   GdkDragAction suggested_action;
7494   gboolean path_down_mode;
7495   gboolean drop_append_mode;
7496
7497   tree_view = GTK_TREE_VIEW (widget);
7498
7499   model = gtk_tree_view_get_model (tree_view);
7500
7501   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7502     return;
7503
7504   di = get_info (tree_view);
7505
7506   if (di == NULL)
7507     return;
7508
7509   suggested_action = get_status_pending (context);
7510
7511   if (suggested_action)
7512     {
7513       /* We are getting this data due to a request in drag_motion,
7514        * rather than due to a request in drag_drop, so we are just
7515        * supposed to call drag_status, not actually paste in the
7516        * data.
7517        */
7518       path = get_logical_dest_row (tree_view, &path_down_mode,
7519                                    &drop_append_mode);
7520
7521       if (path == NULL)
7522         suggested_action = 0;
7523       else if (path_down_mode)
7524         gtk_tree_path_down (path);
7525
7526       if (suggested_action)
7527         {
7528           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7529                                                      path,
7530                                                      selection_data))
7531             {
7532               if (path_down_mode)
7533                 {
7534                   path_down_mode = FALSE;
7535                   gtk_tree_path_up (path);
7536
7537                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7538                                                              path,
7539                                                              selection_data))
7540                     suggested_action = 0;
7541                 }
7542               else
7543                 suggested_action = 0;
7544             }
7545         }
7546
7547       gdk_drag_status (context, suggested_action, time);
7548
7549       if (path)
7550         gtk_tree_path_free (path);
7551
7552       /* If you can't drop, remove user drop indicator until the next motion */
7553       if (suggested_action == 0)
7554         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7555                                          NULL,
7556                                          GTK_TREE_VIEW_DROP_BEFORE);
7557
7558       return;
7559     }
7560
7561   dest_row = get_dest_row (context, &path_down_mode);
7562
7563   if (dest_row == NULL)
7564     return;
7565
7566   if (selection_data->length >= 0)
7567     {
7568       if (path_down_mode)
7569         {
7570           gtk_tree_path_down (dest_row);
7571           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7572                                                      dest_row, selection_data))
7573             gtk_tree_path_up (dest_row);
7574         }
7575     }
7576
7577   if (selection_data->length >= 0)
7578     {
7579       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7580                                                  dest_row,
7581                                                  selection_data))
7582         accepted = TRUE;
7583     }
7584
7585   gtk_drag_finish (context,
7586                    accepted,
7587                    (context->action == GDK_ACTION_MOVE),
7588                    time);
7589
7590   if (gtk_tree_path_get_depth (dest_row) == 1
7591       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7592     {
7593       /* special special case drag to "0", scroll to first item */
7594       if (!tree_view->priv->scroll_to_path)
7595         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7596     }
7597
7598   gtk_tree_path_free (dest_row);
7599
7600   /* drop dest_row */
7601   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7602 }
7603
7604
7605
7606 /* GtkContainer Methods
7607  */
7608
7609
7610 static void
7611 gtk_tree_view_remove (GtkContainer *container,
7612                       GtkWidget    *widget)
7613 {
7614   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7615   GtkTreeViewChild *child = NULL;
7616   GList *tmp_list;
7617
7618   tmp_list = tree_view->priv->children;
7619   while (tmp_list)
7620     {
7621       child = tmp_list->data;
7622       if (child->widget == widget)
7623         {
7624           gtk_widget_unparent (widget);
7625
7626           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7627           g_list_free_1 (tmp_list);
7628           g_slice_free (GtkTreeViewChild, child);
7629           return;
7630         }
7631
7632       tmp_list = tmp_list->next;
7633     }
7634
7635   tmp_list = tree_view->priv->columns;
7636
7637   while (tmp_list)
7638     {
7639       GtkTreeViewColumn *column;
7640       column = tmp_list->data;
7641       if (column->button == widget)
7642         {
7643           gtk_widget_unparent (widget);
7644           return;
7645         }
7646       tmp_list = tmp_list->next;
7647     }
7648 }
7649
7650 static void
7651 gtk_tree_view_forall (GtkContainer *container,
7652                       gboolean      include_internals,
7653                       GtkCallback   callback,
7654                       gpointer      callback_data)
7655 {
7656   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7657   GtkTreeViewChild *child = NULL;
7658   GtkTreeViewColumn *column;
7659   GList *tmp_list;
7660
7661   tmp_list = tree_view->priv->children;
7662   while (tmp_list)
7663     {
7664       child = tmp_list->data;
7665       tmp_list = tmp_list->next;
7666
7667       (* callback) (child->widget, callback_data);
7668     }
7669   if (include_internals == FALSE)
7670     return;
7671
7672   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7673     {
7674       column = tmp_list->data;
7675
7676       if (column->button)
7677         (* callback) (column->button, callback_data);
7678     }
7679 }
7680
7681 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7682  * cells. If so we draw one big row-spanning focus rectangle.
7683  */
7684 static gboolean
7685 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7686 {
7687   GList *list;
7688
7689   for (list = tree_view->priv->columns; list; list = list->next)
7690     {
7691       if (!((GtkTreeViewColumn *)list->data)->visible)
7692         continue;
7693       if (_gtk_tree_view_column_count_special_cells (list->data))
7694         return TRUE;
7695     }
7696
7697   return FALSE;
7698 }
7699
7700 static void
7701 column_sizing_notify (GObject    *object,
7702                       GParamSpec *pspec,
7703                       gpointer    data)
7704 {
7705   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7706
7707   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7708     /* disable fixed height mode */
7709     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7710 }
7711
7712 /**
7713  * gtk_tree_view_set_fixed_height_mode:
7714  * @tree_view: a #GtkTreeView 
7715  * @enable: %TRUE to enable fixed height mode
7716  * 
7717  * Enables or disables the fixed height mode of @tree_view. 
7718  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7719  * rows have the same height. 
7720  * Only enable this option if all rows are the same height and all
7721  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7722  *
7723  * Since: 2.6 
7724  **/
7725 void
7726 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7727                                      gboolean     enable)
7728 {
7729   GList *l;
7730   
7731   enable = enable != FALSE;
7732
7733   if (enable == tree_view->priv->fixed_height_mode)
7734     return;
7735
7736   if (!enable)
7737     {
7738       tree_view->priv->fixed_height_mode = 0;
7739       tree_view->priv->fixed_height = -1;
7740
7741       /* force a revalidation */
7742       install_presize_handler (tree_view);
7743     }
7744   else 
7745     {
7746       /* make sure all columns are of type FIXED */
7747       for (l = tree_view->priv->columns; l; l = l->next)
7748         {
7749           GtkTreeViewColumn *c = l->data;
7750           
7751           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7752         }
7753       
7754       /* yes, we really have to do this is in a separate loop */
7755       for (l = tree_view->priv->columns; l; l = l->next)
7756         g_signal_connect (l->data, "notify::sizing",
7757                           G_CALLBACK (column_sizing_notify), tree_view);
7758       
7759       tree_view->priv->fixed_height_mode = 1;
7760       tree_view->priv->fixed_height = -1;
7761       
7762       if (tree_view->priv->tree)
7763         initialize_fixed_height_mode (tree_view);
7764     }
7765
7766   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7767 }
7768
7769 /**
7770  * gtk_tree_view_get_fixed_height_mode:
7771  * @tree_view: a #GtkTreeView
7772  * 
7773  * Returns whether fixed height mode is turned on for @tree_view.
7774  * 
7775  * Return value: %TRUE if @tree_view is in fixed height mode
7776  * 
7777  * Since: 2.6
7778  **/
7779 gboolean
7780 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7781 {
7782   return tree_view->priv->fixed_height_mode;
7783 }
7784
7785 /* Returns TRUE if the focus is within the headers, after the focus operation is
7786  * done
7787  */
7788 static gboolean
7789 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7790                             GtkDirectionType  dir,
7791                             gboolean          clamp_column_visible)
7792 {
7793   GtkWidget *focus_child;
7794
7795   GList *last_column, *first_column;
7796   GList *tmp_list;
7797   gboolean rtl;
7798
7799   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7800     return FALSE;
7801
7802   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
7803
7804   first_column = tree_view->priv->columns;
7805   while (first_column)
7806     {
7807       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7808           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7809           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7810            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7811         break;
7812       first_column = first_column->next;
7813     }
7814
7815   /* No headers are visible, or are focusable.  We can't focus in or out.
7816    */
7817   if (first_column == NULL)
7818     return FALSE;
7819
7820   last_column = g_list_last (tree_view->priv->columns);
7821   while (last_column)
7822     {
7823       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7824           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7825           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7826            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7827         break;
7828       last_column = last_column->prev;
7829     }
7830
7831
7832   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7833
7834   switch (dir)
7835     {
7836     case GTK_DIR_TAB_BACKWARD:
7837     case GTK_DIR_TAB_FORWARD:
7838     case GTK_DIR_UP:
7839     case GTK_DIR_DOWN:
7840       if (focus_child == NULL)
7841         {
7842           if (tree_view->priv->focus_column != NULL &&
7843               gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
7844             focus_child = tree_view->priv->focus_column->button;
7845           else
7846             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7847           gtk_widget_grab_focus (focus_child);
7848           break;
7849         }
7850       return FALSE;
7851
7852     case GTK_DIR_LEFT:
7853     case GTK_DIR_RIGHT:
7854       if (focus_child == NULL)
7855         {
7856           if (tree_view->priv->focus_column != NULL)
7857             focus_child = tree_view->priv->focus_column->button;
7858           else if (dir == GTK_DIR_LEFT)
7859             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7860           else
7861             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7862           gtk_widget_grab_focus (focus_child);
7863           break;
7864         }
7865
7866       if (gtk_widget_child_focus (focus_child, dir))
7867         {
7868           /* The focus moves inside the button. */
7869           /* This is probably a great example of bad UI */
7870           break;
7871         }
7872
7873       /* We need to move the focus among the row of buttons. */
7874       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7875         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7876           break;
7877
7878       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7879           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7880         {
7881           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7882           break;
7883         }
7884
7885       while (tmp_list)
7886         {
7887           GtkTreeViewColumn *column;
7888
7889           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7890             tmp_list = tmp_list->next;
7891           else
7892             tmp_list = tmp_list->prev;
7893
7894           if (tmp_list == NULL)
7895             {
7896               g_warning ("Internal button not found");
7897               break;
7898             }
7899           column = tmp_list->data;
7900           if (column->button &&
7901               column->visible &&
7902               gtk_widget_get_can_focus (column->button))
7903             {
7904               focus_child = column->button;
7905               gtk_widget_grab_focus (column->button);
7906               break;
7907             }
7908         }
7909       break;
7910     default:
7911       g_assert_not_reached ();
7912       break;
7913     }
7914
7915   /* if focus child is non-null, we assume it's been set to the current focus child
7916    */
7917   if (focus_child)
7918     {
7919       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7920         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7921           {
7922             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7923             break;
7924           }
7925
7926       if (clamp_column_visible)
7927         {
7928           gtk_tree_view_clamp_column_visible (tree_view,
7929                                               tree_view->priv->focus_column,
7930                                               FALSE);
7931         }
7932     }
7933
7934   return (focus_child != NULL);
7935 }
7936
7937 /* This function returns in 'path' the first focusable path, if the given path
7938  * is already focusable, it's the returned one.
7939  */
7940 static gboolean
7941 search_first_focusable_path (GtkTreeView  *tree_view,
7942                              GtkTreePath **path,
7943                              gboolean      search_forward,
7944                              GtkRBTree   **new_tree,
7945                              GtkRBNode   **new_node)
7946 {
7947   GtkRBTree *tree = NULL;
7948   GtkRBNode *node = NULL;
7949
7950   if (!path || !*path)
7951     return FALSE;
7952
7953   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7954
7955   if (!tree || !node)
7956     return FALSE;
7957
7958   while (node && row_is_separator (tree_view, NULL, *path))
7959     {
7960       if (search_forward)
7961         _gtk_rbtree_next_full (tree, node, &tree, &node);
7962       else
7963         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7964
7965       if (*path)
7966         gtk_tree_path_free (*path);
7967
7968       if (node)
7969         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7970       else
7971         *path = NULL;
7972     }
7973
7974   if (new_tree)
7975     *new_tree = tree;
7976
7977   if (new_node)
7978     *new_node = node;
7979
7980   return (*path != NULL);
7981 }
7982
7983 static gint
7984 gtk_tree_view_focus (GtkWidget        *widget,
7985                      GtkDirectionType  direction)
7986 {
7987   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7988   GtkContainer *container = GTK_CONTAINER (widget);
7989   GtkWidget *focus_child;
7990
7991   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
7992     return FALSE;
7993
7994   focus_child = gtk_container_get_focus_child (container);
7995
7996   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
7997   /* Case 1.  Headers currently have focus. */
7998   if (focus_child)
7999     {
8000       switch (direction)
8001         {
8002         case GTK_DIR_LEFT:
8003         case GTK_DIR_RIGHT:
8004           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8005           return TRUE;
8006         case GTK_DIR_TAB_BACKWARD:
8007         case GTK_DIR_UP:
8008           return FALSE;
8009         case GTK_DIR_TAB_FORWARD:
8010         case GTK_DIR_DOWN:
8011           gtk_widget_grab_focus (widget);
8012           return TRUE;
8013         default:
8014           g_assert_not_reached ();
8015           return FALSE;
8016         }
8017     }
8018
8019   /* Case 2. We don't have focus at all. */
8020   if (!gtk_widget_has_focus (widget))
8021     {
8022       gtk_widget_grab_focus (widget);
8023       return TRUE;
8024     }
8025
8026   /* Case 3. We have focus already. */
8027   if (direction == GTK_DIR_TAB_BACKWARD)
8028     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8029   else if (direction == GTK_DIR_TAB_FORWARD)
8030     return FALSE;
8031
8032   /* Other directions caught by the keybindings */
8033   gtk_widget_grab_focus (widget);
8034   return TRUE;
8035 }
8036
8037 static void
8038 gtk_tree_view_grab_focus (GtkWidget *widget)
8039 {
8040   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8041
8042   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8043 }
8044
8045 static void
8046 gtk_tree_view_style_set (GtkWidget *widget,
8047                          GtkStyle *previous_style)
8048 {
8049   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8050   GtkStyle *style;
8051   GList *list;
8052   GtkTreeViewColumn *column;
8053
8054   if (gtk_widget_get_realized (widget))
8055     {
8056       style = gtk_widget_get_style (widget);
8057       gdk_window_set_background (tree_view->priv->bin_window,
8058                                  &style->base[gtk_widget_get_state (widget)]);
8059       gtk_style_set_background (style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8060
8061       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8062       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8063     }
8064
8065   gtk_widget_style_get (widget,
8066                         "expander-size", &tree_view->priv->expander_size,
8067                         NULL);
8068   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8069
8070   for (list = tree_view->priv->columns; list; list = list->next)
8071     {
8072       column = list->data;
8073       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8074     }
8075
8076   tree_view->priv->fixed_height = -1;
8077   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8078
8079   gtk_widget_queue_resize (widget);
8080 }
8081
8082
8083 static void
8084 gtk_tree_view_set_focus_child (GtkContainer *container,
8085                                GtkWidget    *child)
8086 {
8087   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8088   GList *list;
8089
8090   for (list = tree_view->priv->columns; list; list = list->next)
8091     {
8092       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8093         {
8094           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8095           break;
8096         }
8097     }
8098
8099   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8100 }
8101
8102 static gboolean
8103 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8104                                 GtkMovementStep    step,
8105                                 gint               count)
8106 {
8107   GdkModifierType state;
8108
8109   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8110   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8111                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8112                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8113                         step == GTK_MOVEMENT_PAGES ||
8114                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8115
8116   if (tree_view->priv->tree == NULL)
8117     return FALSE;
8118   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8119     return FALSE;
8120
8121   gtk_tree_view_stop_editing (tree_view, FALSE);
8122   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8123   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8124
8125   if (gtk_get_current_event_state (&state))
8126     {
8127       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8128         tree_view->priv->ctrl_pressed = TRUE;
8129       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8130         tree_view->priv->shift_pressed = TRUE;
8131     }
8132   /* else we assume not pressed */
8133
8134   switch (step)
8135     {
8136       /* currently we make no distinction.  When we go bi-di, we need to */
8137     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8138     case GTK_MOVEMENT_VISUAL_POSITIONS:
8139       gtk_tree_view_move_cursor_left_right (tree_view, count);
8140       break;
8141     case GTK_MOVEMENT_DISPLAY_LINES:
8142       gtk_tree_view_move_cursor_up_down (tree_view, count);
8143       break;
8144     case GTK_MOVEMENT_PAGES:
8145       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8146       break;
8147     case GTK_MOVEMENT_BUFFER_ENDS:
8148       gtk_tree_view_move_cursor_start_end (tree_view, count);
8149       break;
8150     default:
8151       g_assert_not_reached ();
8152     }
8153
8154   tree_view->priv->ctrl_pressed = FALSE;
8155   tree_view->priv->shift_pressed = FALSE;
8156
8157   return TRUE;
8158 }
8159
8160 static void
8161 gtk_tree_view_put (GtkTreeView *tree_view,
8162                    GtkWidget   *child_widget,
8163                    /* in bin_window coordinates */
8164                    gint         x,
8165                    gint         y,
8166                    gint         width,
8167                    gint         height)
8168 {
8169   GtkTreeViewChild *child;
8170   
8171   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8172   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8173
8174   child = g_slice_new (GtkTreeViewChild);
8175
8176   child->widget = child_widget;
8177   child->x = x;
8178   child->y = y;
8179   child->width = width;
8180   child->height = height;
8181
8182   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8183
8184   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8185     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8186   
8187   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8188 }
8189
8190 void
8191 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8192                                   GtkWidget   *widget,
8193                                   /* in tree coordinates */
8194                                   gint         x,
8195                                   gint         y,
8196                                   gint         width,
8197                                   gint         height)
8198 {
8199   GtkTreeViewChild *child = NULL;
8200   GList *list;
8201   GdkRectangle allocation;
8202
8203   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8204   g_return_if_fail (GTK_IS_WIDGET (widget));
8205
8206   for (list = tree_view->priv->children; list; list = list->next)
8207     {
8208       if (((GtkTreeViewChild *)list->data)->widget == widget)
8209         {
8210           child = list->data;
8211           break;
8212         }
8213     }
8214   if (child == NULL)
8215     return;
8216
8217   allocation.x = child->x = x;
8218   allocation.y = child->y = y;
8219   allocation.width = child->width = width;
8220   allocation.height = child->height = height;
8221
8222   if (gtk_widget_get_realized (widget))
8223     gtk_widget_size_allocate (widget, &allocation);
8224 }
8225
8226
8227 /* TreeModel Callbacks
8228  */
8229
8230 static void
8231 gtk_tree_view_row_changed (GtkTreeModel *model,
8232                            GtkTreePath  *path,
8233                            GtkTreeIter  *iter,
8234                            gpointer      data)
8235 {
8236   GtkTreeView *tree_view = (GtkTreeView *)data;
8237   GtkRBTree *tree;
8238   GtkRBNode *node;
8239   gboolean free_path = FALSE;
8240   GList *list;
8241   GtkTreePath *cursor_path;
8242
8243   g_return_if_fail (path != NULL || iter != NULL);
8244
8245   if (tree_view->priv->cursor != NULL)
8246     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8247   else
8248     cursor_path = NULL;
8249
8250   if (tree_view->priv->edited_column &&
8251       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8252     gtk_tree_view_stop_editing (tree_view, TRUE);
8253
8254   if (cursor_path != NULL)
8255     gtk_tree_path_free (cursor_path);
8256
8257   if (path == NULL)
8258     {
8259       path = gtk_tree_model_get_path (model, iter);
8260       free_path = TRUE;
8261     }
8262   else if (iter == NULL)
8263     gtk_tree_model_get_iter (model, iter, path);
8264
8265   if (_gtk_tree_view_find_node (tree_view,
8266                                 path,
8267                                 &tree,
8268                                 &node))
8269     /* We aren't actually showing the node */
8270     goto done;
8271
8272   if (tree == NULL)
8273     goto done;
8274
8275   if (tree_view->priv->fixed_height_mode
8276       && tree_view->priv->fixed_height >= 0)
8277     {
8278       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8279       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8280         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8281     }
8282   else
8283     {
8284       _gtk_rbtree_node_mark_invalid (tree, node);
8285       for (list = tree_view->priv->columns; list; list = list->next)
8286         {
8287           GtkTreeViewColumn *column;
8288
8289           column = list->data;
8290           if (! column->visible)
8291             continue;
8292
8293           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8294             {
8295               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8296             }
8297         }
8298     }
8299
8300  done:
8301   if (!tree_view->priv->fixed_height_mode &&
8302       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8303     install_presize_handler (tree_view);
8304   if (free_path)
8305     gtk_tree_path_free (path);
8306 }
8307
8308 static void
8309 gtk_tree_view_row_inserted (GtkTreeModel *model,
8310                             GtkTreePath  *path,
8311                             GtkTreeIter  *iter,
8312                             gpointer      data)
8313 {
8314   GtkTreeView *tree_view = (GtkTreeView *) data;
8315   gint *indices;
8316   GtkRBTree *tmptree, *tree;
8317   GtkRBNode *tmpnode = NULL;
8318   gint depth;
8319   gint i = 0;
8320   gint height;
8321   gboolean free_path = FALSE;
8322   gboolean node_visible = TRUE;
8323
8324   g_return_if_fail (path != NULL || iter != NULL);
8325
8326   if (tree_view->priv->fixed_height_mode
8327       && tree_view->priv->fixed_height >= 0)
8328     height = tree_view->priv->fixed_height;
8329   else
8330     height = 0;
8331
8332   if (path == NULL)
8333     {
8334       path = gtk_tree_model_get_path (model, iter);
8335       free_path = TRUE;
8336     }
8337   else if (iter == NULL)
8338     gtk_tree_model_get_iter (model, iter, path);
8339
8340   if (tree_view->priv->tree == NULL)
8341     tree_view->priv->tree = _gtk_rbtree_new ();
8342
8343   tmptree = tree = tree_view->priv->tree;
8344
8345   /* Update all row-references */
8346   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8347   depth = gtk_tree_path_get_depth (path);
8348   indices = gtk_tree_path_get_indices (path);
8349
8350   /* First, find the parent tree */
8351   while (i < depth - 1)
8352     {
8353       if (tmptree == NULL)
8354         {
8355           /* We aren't showing the node */
8356           node_visible = FALSE;
8357           goto done;
8358         }
8359
8360       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8361       if (tmpnode == NULL)
8362         {
8363           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8364                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8365                      "before the parent was inserted.");
8366           goto done;
8367         }
8368       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8369         {
8370           /* FIXME enforce correct behavior on model, probably */
8371           /* In theory, the model should have emitted has_child_toggled here.  We
8372            * try to catch it anyway, just to be safe, in case the model hasn't.
8373            */
8374           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8375                                                            tree,
8376                                                            tmpnode);
8377           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8378           gtk_tree_path_free (tmppath);
8379           goto done;
8380         }
8381
8382       tmptree = tmpnode->children;
8383       tree = tmptree;
8384       i++;
8385     }
8386
8387   if (tree == NULL)
8388     {
8389       node_visible = FALSE;
8390       goto done;
8391     }
8392
8393   /* ref the node */
8394   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8395   if (indices[depth - 1] == 0)
8396     {
8397       tmpnode = _gtk_rbtree_find_count (tree, 1);
8398       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8399     }
8400   else
8401     {
8402       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8403       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8404     }
8405
8406  done:
8407   if (height > 0)
8408     {
8409       if (tree)
8410         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8411
8412       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8413         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8414       else
8415         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8416     }
8417   else
8418     install_presize_handler (tree_view);
8419   if (free_path)
8420     gtk_tree_path_free (path);
8421 }
8422
8423 static void
8424 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8425                                      GtkTreePath  *path,
8426                                      GtkTreeIter  *iter,
8427                                      gpointer      data)
8428 {
8429   GtkTreeView *tree_view = (GtkTreeView *)data;
8430   GtkTreeIter real_iter;
8431   gboolean has_child;
8432   GtkRBTree *tree;
8433   GtkRBNode *node;
8434   gboolean free_path = FALSE;
8435
8436   g_return_if_fail (path != NULL || iter != NULL);
8437
8438   if (iter)
8439     real_iter = *iter;
8440
8441   if (path == NULL)
8442     {
8443       path = gtk_tree_model_get_path (model, iter);
8444       free_path = TRUE;
8445     }
8446   else if (iter == NULL)
8447     gtk_tree_model_get_iter (model, &real_iter, path);
8448
8449   if (_gtk_tree_view_find_node (tree_view,
8450                                 path,
8451                                 &tree,
8452                                 &node))
8453     /* We aren't actually showing the node */
8454     goto done;
8455
8456   if (tree == NULL)
8457     goto done;
8458
8459   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8460   /* Sanity check.
8461    */
8462   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8463     goto done;
8464
8465   if (has_child)
8466     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8467   else
8468     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8469
8470   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8471     {
8472       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8473       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8474         {
8475           GList *list;
8476
8477           for (list = tree_view->priv->columns; list; list = list->next)
8478             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8479               {
8480                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8481                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8482                 break;
8483               }
8484         }
8485       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8486     }
8487   else
8488     {
8489       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8490     }
8491
8492  done:
8493   if (free_path)
8494     gtk_tree_path_free (path);
8495 }
8496
8497 static void
8498 count_children_helper (GtkRBTree *tree,
8499                        GtkRBNode *node,
8500                        gpointer   data)
8501 {
8502   if (node->children)
8503     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8504   (*((gint *)data))++;
8505 }
8506
8507 static void
8508 check_selection_helper (GtkRBTree *tree,
8509                         GtkRBNode *node,
8510                         gpointer   data)
8511 {
8512   gint *value = (gint *)data;
8513
8514   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8515
8516   if (node->children && !*value)
8517     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8518 }
8519
8520 static void
8521 gtk_tree_view_row_deleted (GtkTreeModel *model,
8522                            GtkTreePath  *path,
8523                            gpointer      data)
8524 {
8525   GtkTreeView *tree_view = (GtkTreeView *)data;
8526   GtkRBTree *tree;
8527   GtkRBNode *node;
8528   GList *list;
8529   gint selection_changed = FALSE;
8530
8531   g_return_if_fail (path != NULL);
8532
8533   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8534
8535   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8536     return;
8537
8538   if (tree == NULL)
8539     return;
8540
8541   /* check if the selection has been changed */
8542   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8543                         check_selection_helper, &selection_changed);
8544
8545   for (list = tree_view->priv->columns; list; list = list->next)
8546     if (((GtkTreeViewColumn *)list->data)->visible &&
8547         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8548       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8549
8550   /* Ensure we don't have a dangling pointer to a dead node */
8551   ensure_unprelighted (tree_view);
8552
8553   /* Cancel editting if we've started */
8554   gtk_tree_view_stop_editing (tree_view, TRUE);
8555
8556   /* If we have a node expanded/collapsed timeout, remove it */
8557   remove_expand_collapse_timeout (tree_view);
8558
8559   if (tree_view->priv->destroy_count_func)
8560     {
8561       gint child_count = 0;
8562       if (node->children)
8563         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8564       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8565     }
8566
8567   if (tree->root->count == 1)
8568     {
8569       if (tree_view->priv->tree == tree)
8570         tree_view->priv->tree = NULL;
8571
8572       _gtk_rbtree_remove (tree);
8573     }
8574   else
8575     {
8576       _gtk_rbtree_remove_node (tree, node);
8577     }
8578
8579   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8580     {
8581       gtk_tree_row_reference_free (tree_view->priv->top_row);
8582       tree_view->priv->top_row = NULL;
8583     }
8584
8585   install_scroll_sync_handler (tree_view);
8586
8587   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8588
8589   if (selection_changed)
8590     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8591 }
8592
8593 static void
8594 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8595                               GtkTreePath  *parent,
8596                               GtkTreeIter  *iter,
8597                               gint         *new_order,
8598                               gpointer      data)
8599 {
8600   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8601   GtkRBTree *tree;
8602   GtkRBNode *node;
8603   gint len;
8604
8605   len = gtk_tree_model_iter_n_children (model, iter);
8606
8607   if (len < 2)
8608     return;
8609
8610   gtk_tree_row_reference_reordered (G_OBJECT (data),
8611                                     parent,
8612                                     iter,
8613                                     new_order);
8614
8615   if (_gtk_tree_view_find_node (tree_view,
8616                                 parent,
8617                                 &tree,
8618                                 &node))
8619     return;
8620
8621   /* We need to special case the parent path */
8622   if (tree == NULL)
8623     tree = tree_view->priv->tree;
8624   else
8625     tree = node->children;
8626
8627   if (tree == NULL)
8628     return;
8629
8630   if (tree_view->priv->edited_column)
8631     gtk_tree_view_stop_editing (tree_view, TRUE);
8632
8633   /* we need to be unprelighted */
8634   ensure_unprelighted (tree_view);
8635
8636   /* clear the timeout */
8637   cancel_arrow_animation (tree_view);
8638   
8639   _gtk_rbtree_reorder (tree, new_order, len);
8640
8641   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8642
8643   gtk_tree_view_dy_to_top_row (tree_view);
8644 }
8645
8646
8647 /* Internal tree functions
8648  */
8649
8650
8651 static void
8652 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8653                                      GtkRBTree         *tree,
8654                                      GtkTreeViewColumn *column,
8655                                      gint              *x1,
8656                                      gint              *x2)
8657 {
8658   GtkTreeViewColumn *tmp_column = NULL;
8659   gint total_width;
8660   GList *list;
8661   gboolean rtl;
8662
8663   if (x1)
8664     *x1 = 0;
8665
8666   if (x2)
8667     *x2 = 0;
8668
8669   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8670
8671   total_width = 0;
8672   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8673        list;
8674        list = (rtl ? list->prev : list->next))
8675     {
8676       tmp_column = list->data;
8677
8678       if (tmp_column == column)
8679         break;
8680
8681       if (tmp_column->visible)
8682         total_width += tmp_column->width;
8683     }
8684
8685   if (tmp_column != column)
8686     {
8687       g_warning (G_STRLOC": passed-in column isn't in the tree");
8688       return;
8689     }
8690
8691   if (x1)
8692     *x1 = total_width;
8693
8694   if (x2)
8695     {
8696       if (column->visible)
8697         *x2 = total_width + column->width;
8698       else
8699         *x2 = total_width; /* width of 0 */
8700     }
8701 }
8702 static void
8703 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8704                                 GtkRBTree   *tree,
8705                                 gint        *x1,
8706                                 gint        *x2)
8707 {
8708   gint x_offset = 0;
8709   GList *list;
8710   GtkTreeViewColumn *tmp_column = NULL;
8711   gint total_width;
8712   gboolean indent_expanders;
8713   gboolean rtl;
8714
8715   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8716
8717   total_width = 0;
8718   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8719        list;
8720        list = (rtl ? list->prev : list->next))
8721     {
8722       tmp_column = list->data;
8723
8724       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8725         {
8726           if (rtl)
8727             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8728           else
8729             x_offset = total_width;
8730           break;
8731         }
8732
8733       if (tmp_column->visible)
8734         total_width += tmp_column->width;
8735     }
8736
8737   gtk_widget_style_get (GTK_WIDGET (tree_view),
8738                         "indent-expanders", &indent_expanders,
8739                         NULL);
8740
8741   if (indent_expanders)
8742     {
8743       if (rtl)
8744         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8745       else
8746         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8747     }
8748
8749   *x1 = x_offset;
8750   
8751   if (tmp_column && tmp_column->visible)
8752     /* +1 because x2 isn't included in the range. */
8753     *x2 = *x1 + tree_view->priv->expander_size + 1;
8754   else
8755     *x2 = *x1;
8756 }
8757
8758 static void
8759 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8760                           GtkRBTree   *tree,
8761                           GtkTreeIter *iter,
8762                           gint         depth,
8763                           gboolean     recurse)
8764 {
8765   GtkRBNode *temp = NULL;
8766   GtkTreePath *path = NULL;
8767   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8768
8769   do
8770     {
8771       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8772       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8773
8774       if (tree_view->priv->fixed_height > 0)
8775         {
8776           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8777             {
8778               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8779               _gtk_rbtree_node_mark_valid (tree, temp);
8780             }
8781         }
8782
8783       if (is_list)
8784         continue;
8785
8786       if (recurse)
8787         {
8788           GtkTreeIter child;
8789
8790           if (!path)
8791             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8792           else
8793             gtk_tree_path_next (path);
8794
8795           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8796             {
8797               gboolean expand;
8798
8799               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8800
8801               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8802                   && !expand)
8803                 {
8804                   temp->children = _gtk_rbtree_new ();
8805                   temp->children->parent_tree = tree;
8806                   temp->children->parent_node = temp;
8807                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8808                 }
8809             }
8810         }
8811
8812       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8813         {
8814           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8815             temp->flags ^= GTK_RBNODE_IS_PARENT;
8816         }
8817     }
8818   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8819
8820   if (path)
8821     gtk_tree_path_free (path);
8822 }
8823
8824 /* Make sure the node is visible vertically */
8825 static void
8826 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8827                                   GtkRBTree   *tree,
8828                                   GtkRBNode   *node)
8829 {
8830   gint node_dy, height;
8831   GtkTreePath *path = NULL;
8832
8833   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8834     return;
8835
8836   /* just return if the node is visible, avoiding a costly expose */
8837   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8838   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8839   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8840       && node_dy >= tree_view->priv->vadjustment->value
8841       && node_dy + height <= (tree_view->priv->vadjustment->value
8842                               + tree_view->priv->vadjustment->page_size))
8843     return;
8844
8845   path = _gtk_tree_view_find_path (tree_view, tree, node);
8846   if (path)
8847     {
8848       /* We process updates because we want to clear old selected items when we scroll.
8849        * if this is removed, we get a "selection streak" at the bottom. */
8850       gtk_tree_view_bin_process_updates (tree_view);
8851
8852       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8853       gtk_tree_path_free (path);
8854     }
8855 }
8856
8857 static void
8858 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8859                                     GtkTreeViewColumn *column,
8860                                     gboolean           focus_to_cell)
8861 {
8862   GtkAllocation allocation;
8863   gint x, width;
8864
8865   if (column == NULL)
8866     return;
8867
8868   gtk_widget_get_allocation (column->button, &allocation);
8869   x = allocation.x;
8870   width = allocation.width;
8871
8872   if (width > tree_view->priv->hadjustment->page_size)
8873     {
8874       /* The column is larger than the horizontal page size.  If the
8875        * column has cells which can be focussed individually, then we make
8876        * sure the cell which gets focus is fully visible (if even the
8877        * focus cell is bigger than the page size, we make sure the
8878        * left-hand side of the cell is visible).
8879        *
8880        * If the column does not have those so-called special cells, we
8881        * make sure the left-hand side of the column is visible.
8882        */
8883
8884       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8885         {
8886           GtkTreePath *cursor_path;
8887           GdkRectangle background_area, cell_area, focus_area;
8888
8889           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8890
8891           gtk_tree_view_get_cell_area (tree_view,
8892                                        cursor_path, column, &cell_area);
8893           gtk_tree_view_get_background_area (tree_view,
8894                                              cursor_path, column,
8895                                              &background_area);
8896
8897           gtk_tree_path_free (cursor_path);
8898
8899           _gtk_tree_view_column_get_focus_area (column,
8900                                                 &background_area,
8901                                                 &cell_area,
8902                                                 &focus_area);
8903
8904           x = focus_area.x;
8905           width = focus_area.width;
8906
8907           if (width < tree_view->priv->hadjustment->page_size)
8908             {
8909               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8910                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8911                                           x + width - tree_view->priv->hadjustment->page_size);
8912               else if (tree_view->priv->hadjustment->value > x)
8913                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8914             }
8915         }
8916
8917       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8918     }
8919   else
8920     {
8921       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8922           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8923                                     x + width - tree_view->priv->hadjustment->page_size);
8924       else if (tree_view->priv->hadjustment->value > x)
8925         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8926   }
8927 }
8928
8929 /* This function could be more efficient.  I'll optimize it if profiling seems
8930  * to imply that it is important */
8931 GtkTreePath *
8932 _gtk_tree_view_find_path (GtkTreeView *tree_view,
8933                           GtkRBTree   *tree,
8934                           GtkRBNode   *node)
8935 {
8936   GtkTreePath *path;
8937   GtkRBTree *tmp_tree;
8938   GtkRBNode *tmp_node, *last;
8939   gint count;
8940
8941   path = gtk_tree_path_new ();
8942
8943   g_return_val_if_fail (node != NULL, path);
8944   g_return_val_if_fail (node != tree->nil, path);
8945
8946   count = 1 + node->left->count;
8947
8948   last = node;
8949   tmp_node = node->parent;
8950   tmp_tree = tree;
8951   while (tmp_tree)
8952     {
8953       while (tmp_node != tmp_tree->nil)
8954         {
8955           if (tmp_node->right == last)
8956             count += 1 + tmp_node->left->count;
8957           last = tmp_node;
8958           tmp_node = tmp_node->parent;
8959         }
8960       gtk_tree_path_prepend_index (path, count - 1);
8961       last = tmp_tree->parent_node;
8962       tmp_tree = tmp_tree->parent_tree;
8963       if (last)
8964         {
8965           count = 1 + last->left->count;
8966           tmp_node = last->parent;
8967         }
8968     }
8969   return path;
8970 }
8971
8972 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
8973  * invalid (ie. points to a node that's not in the tree), *tree and *node are
8974  * both set to NULL.
8975  */
8976 gboolean
8977 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
8978                           GtkTreePath  *path,
8979                           GtkRBTree   **tree,
8980                           GtkRBNode   **node)
8981 {
8982   GtkRBNode *tmpnode = NULL;
8983   GtkRBTree *tmptree = tree_view->priv->tree;
8984   gint *indices = gtk_tree_path_get_indices (path);
8985   gint depth = gtk_tree_path_get_depth (path);
8986   gint i = 0;
8987
8988   *node = NULL;
8989   *tree = NULL;
8990
8991   if (depth == 0 || tmptree == NULL)
8992     return FALSE;
8993   do
8994     {
8995       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8996       ++i;
8997       if (tmpnode == NULL)
8998         {
8999           *tree = NULL;
9000           *node = NULL;
9001           return FALSE;
9002         }
9003       if (i >= depth)
9004         {
9005           *tree = tmptree;
9006           *node = tmpnode;
9007           return FALSE;
9008         }
9009       *tree = tmptree;
9010       *node = tmpnode;
9011       tmptree = tmpnode->children;
9012       if (tmptree == NULL)
9013         return TRUE;
9014     }
9015   while (1);
9016 }
9017
9018 static gboolean
9019 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9020                                   GtkTreeViewColumn *column)
9021 {
9022   GList *list;
9023
9024   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9025     return FALSE;
9026
9027   if (tree_view->priv->expander_column != NULL)
9028     {
9029       if (tree_view->priv->expander_column == column)
9030         return TRUE;
9031       return FALSE;
9032     }
9033   else
9034     {
9035       for (list = tree_view->priv->columns;
9036            list;
9037            list = list->next)
9038         if (((GtkTreeViewColumn *)list->data)->visible)
9039           break;
9040       if (list && list->data == column)
9041         return TRUE;
9042     }
9043   return FALSE;
9044 }
9045
9046 static void
9047 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9048                                 guint           keyval,
9049                                 guint           modmask,
9050                                 gboolean        add_shifted_binding,
9051                                 GtkMovementStep step,
9052                                 gint            count)
9053 {
9054   
9055   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9056                                 "move-cursor", 2,
9057                                 G_TYPE_ENUM, step,
9058                                 G_TYPE_INT, count);
9059
9060   if (add_shifted_binding)
9061     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9062                                   "move-cursor", 2,
9063                                   G_TYPE_ENUM, step,
9064                                   G_TYPE_INT, count);
9065
9066   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9067    return;
9068
9069   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9070                                 "move-cursor", 2,
9071                                 G_TYPE_ENUM, step,
9072                                 G_TYPE_INT, count);
9073
9074   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9075                                 "move-cursor", 2,
9076                                 G_TYPE_ENUM, step,
9077                                 G_TYPE_INT, count);
9078 }
9079
9080 static gint
9081 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9082                                  GtkTreeIter  *iter,
9083                                  GtkRBTree    *tree,
9084                                  GtkRBNode    *node)
9085 {
9086   gint retval = FALSE;
9087   do
9088     {
9089       g_return_val_if_fail (node != NULL, FALSE);
9090
9091       if (node->children)
9092         {
9093           GtkTreeIter child;
9094           GtkRBTree *new_tree;
9095           GtkRBNode *new_node;
9096
9097           new_tree = node->children;
9098           new_node = new_tree->root;
9099
9100           while (new_node && new_node->left != new_tree->nil)
9101             new_node = new_node->left;
9102
9103           if (!gtk_tree_model_iter_children (model, &child, iter))
9104             return FALSE;
9105
9106           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9107         }
9108
9109       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9110         retval = TRUE;
9111       gtk_tree_model_unref_node (model, iter);
9112       node = _gtk_rbtree_next (tree, node);
9113     }
9114   while (gtk_tree_model_iter_next (model, iter));
9115
9116   return retval;
9117 }
9118
9119 static gint
9120 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9121                                               GtkRBTree   *tree)
9122 {
9123   GtkTreeIter iter;
9124   GtkTreePath *path;
9125   GtkRBNode *node;
9126   gint retval;
9127
9128   if (!tree)
9129     return FALSE;
9130
9131   node = tree->root;
9132   while (node && node->left != tree->nil)
9133     node = node->left;
9134
9135   g_return_val_if_fail (node != NULL, FALSE);
9136   path = _gtk_tree_view_find_path (tree_view, tree, node);
9137   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9138                            &iter, path);
9139   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9140   gtk_tree_path_free (path);
9141
9142   return retval;
9143 }
9144
9145 static void
9146 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9147                                     GtkTreeViewColumn *column)
9148 {
9149   GtkTreeViewColumn *left_column;
9150   GtkTreeViewColumn *cur_column = NULL;
9151   GtkTreeViewColumnReorder *reorder;
9152   gboolean rtl;
9153   GList *tmp_list;
9154   gint left;
9155
9156   /* We want to precalculate the motion list such that we know what column slots
9157    * are available.
9158    */
9159   left_column = NULL;
9160   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9161
9162   /* First, identify all possible drop spots */
9163   if (rtl)
9164     tmp_list = g_list_last (tree_view->priv->columns);
9165   else
9166     tmp_list = g_list_first (tree_view->priv->columns);
9167
9168   while (tmp_list)
9169     {
9170       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9171       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9172
9173       if (cur_column->visible == FALSE)
9174         continue;
9175
9176       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9177       if (left_column != column && cur_column != column &&
9178           tree_view->priv->column_drop_func &&
9179           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9180         {
9181           left_column = cur_column;
9182           continue;
9183         }
9184       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9185       reorder->left_column = left_column;
9186       left_column = reorder->right_column = cur_column;
9187
9188       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9189     }
9190
9191   /* Add the last one */
9192   if (tree_view->priv->column_drop_func == NULL ||
9193       ((left_column != column) &&
9194        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9195     {
9196       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9197       reorder->left_column = left_column;
9198       reorder->right_column = NULL;
9199       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9200     }
9201
9202   /* We quickly check to see if it even makes sense to reorder columns. */
9203   /* If there is nothing that can be moved, then we return */
9204
9205   if (tree_view->priv->column_drag_info == NULL)
9206     return;
9207
9208   /* We know there are always 2 slots possbile, as you can always return column. */
9209   /* If that's all there is, return */
9210   if (tree_view->priv->column_drag_info->next == NULL || 
9211       (tree_view->priv->column_drag_info->next->next == NULL &&
9212        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9213        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9214     {
9215       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9216         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9217       g_list_free (tree_view->priv->column_drag_info);
9218       tree_view->priv->column_drag_info = NULL;
9219       return;
9220     }
9221   /* We fill in the ranges for the columns, now that we've isolated them */
9222   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9223
9224   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9225     {
9226       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9227
9228       reorder->left_align = left;
9229       if (tmp_list->next != NULL)
9230         {
9231           GtkAllocation right_allocation, left_allocation;
9232
9233           g_assert (tmp_list->next->data);
9234
9235           gtk_widget_get_allocation (reorder->right_column->button, &right_allocation);
9236           gtk_widget_get_allocation (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button, &left_allocation);
9237           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9238         }
9239       else
9240         {
9241           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9242                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9243         }
9244     }
9245 }
9246
9247 void
9248 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9249                                   GtkTreeViewColumn *column,
9250                                   GdkDevice         *device)
9251 {
9252   GdkEvent *send_event;
9253   GtkAllocation allocation;
9254   GtkAllocation button_allocation;
9255   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9256   GdkDisplay *display = gdk_screen_get_display (screen);
9257
9258   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9259   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9260
9261   gtk_tree_view_set_column_drag_info (tree_view, column);
9262
9263   if (tree_view->priv->column_drag_info == NULL)
9264     return;
9265
9266   if (tree_view->priv->drag_window == NULL)
9267     {
9268       GdkWindowAttr attributes;
9269       guint attributes_mask;
9270
9271       gtk_widget_get_allocation (column->button, &button_allocation);
9272
9273       attributes.window_type = GDK_WINDOW_CHILD;
9274       attributes.wclass = GDK_INPUT_OUTPUT;
9275       attributes.x = button_allocation.x;
9276       attributes.y = 0;
9277       attributes.width = button_allocation.width;
9278       attributes.height = button_allocation.height;
9279       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9280       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9281       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9282
9283       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9284                                                      &attributes,
9285                                                      attributes_mask);
9286       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9287     }
9288
9289   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9290   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9291
9292   gtk_grab_remove (column->button);
9293
9294   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9295   send_event->crossing.send_event = TRUE;
9296   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9297   send_event->crossing.subwindow = NULL;
9298   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9299   send_event->crossing.time = GDK_CURRENT_TIME;
9300   gdk_event_set_device (send_event, device);
9301
9302   gtk_propagate_event (column->button, send_event);
9303   gdk_event_free (send_event);
9304
9305   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9306   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9307   send_event->button.send_event = TRUE;
9308   send_event->button.time = GDK_CURRENT_TIME;
9309   send_event->button.x = -1;
9310   send_event->button.y = -1;
9311   send_event->button.axes = NULL;
9312   send_event->button.state = 0;
9313   send_event->button.button = 1;
9314   send_event->button.x_root = 0;
9315   send_event->button.y_root = 0;
9316   gdk_event_set_device (send_event, device);
9317
9318   gtk_propagate_event (column->button, send_event);
9319   gdk_event_free (send_event);
9320
9321   /* Kids, don't try this at home */
9322   g_object_ref (column->button);
9323   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9324   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9325   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9326   g_object_unref (column->button);
9327
9328   gtk_widget_get_allocation (column->button, &button_allocation);
9329   tree_view->priv->drag_column_x = button_allocation.x;
9330   allocation = button_allocation;
9331   allocation.x = 0;
9332   gtk_widget_size_allocate (column->button, &allocation);
9333   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9334
9335   tree_view->priv->drag_column = column;
9336   gdk_window_show (tree_view->priv->drag_window);
9337
9338   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9339   while (gtk_events_pending ())
9340     gtk_main_iteration ();
9341
9342   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9343   gdk_pointer_grab (tree_view->priv->drag_window,
9344                     FALSE,
9345                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9346                     NULL, NULL, GDK_CURRENT_TIME);
9347   gdk_keyboard_grab (tree_view->priv->drag_window,
9348                      FALSE,
9349                      GDK_CURRENT_TIME);
9350 }
9351
9352 static void
9353 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9354                                 GtkRBTree          *tree,
9355                                 GtkRBNode          *node)
9356 {
9357   GtkAllocation allocation;
9358   GdkRectangle rect;
9359
9360   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9361     return;
9362
9363   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9364   rect.x = 0;
9365   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9366
9367   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9368   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9369
9370   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9371 }
9372
9373 void
9374 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9375                                 GtkRBTree          *tree,
9376                                 GtkRBNode          *node,
9377                                 const GdkRectangle *clip_rect)
9378 {
9379   GtkAllocation allocation;
9380   GdkRectangle rect;
9381
9382   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9383     return;
9384
9385   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9386   rect.x = 0;
9387   rect.width = MAX (tree_view->priv->width, allocation.width);
9388
9389   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9390   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9391
9392   if (clip_rect)
9393     {
9394       GdkRectangle new_rect;
9395
9396       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9397
9398       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9399     }
9400   else
9401     {
9402       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9403     }
9404 }
9405
9406 static void
9407 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9408                                GtkTreePath        *path,
9409                                const GdkRectangle *clip_rect)
9410 {
9411   GtkRBTree *tree = NULL;
9412   GtkRBNode *node = NULL;
9413
9414   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9415
9416   if (tree)
9417     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9418 }
9419
9420 /* x and y are the mouse position
9421  */
9422 static void
9423 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9424                           cairo_t     *cr,
9425                           GtkRBTree   *tree,
9426                           GtkRBNode   *node,
9427                           /* in bin_window coordinates */
9428                           gint         x,
9429                           gint         y)
9430 {
9431   GdkRectangle area;
9432   GtkStateType state;
9433   GtkWidget *widget;
9434   gint x_offset = 0;
9435   gint x2;
9436   gint vertical_separator;
9437   gint expander_size;
9438   GtkExpanderStyle expander_style;
9439
9440   widget = GTK_WIDGET (tree_view);
9441
9442   gtk_widget_style_get (widget,
9443                         "vertical-separator", &vertical_separator,
9444                         NULL);
9445   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9446
9447   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9448     return;
9449
9450   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9451
9452   area.x = x_offset;
9453   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9454   area.width = expander_size + 2;
9455   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9456
9457   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9458     {
9459       state = GTK_STATE_INSENSITIVE;
9460     }
9461   else if (node == tree_view->priv->button_pressed_node)
9462     {
9463       if (x >= area.x && x <= (area.x + area.width) &&
9464           y >= area.y && y <= (area.y + area.height))
9465         state = GTK_STATE_ACTIVE;
9466       else
9467         state = GTK_STATE_NORMAL;
9468     }
9469   else
9470     {
9471       if (node == tree_view->priv->prelight_node &&
9472           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9473         state = GTK_STATE_PRELIGHT;
9474       else
9475         state = GTK_STATE_NORMAL;
9476     }
9477
9478   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9479     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9480   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9481     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9482   else if (node->children != NULL)
9483     expander_style = GTK_EXPANDER_EXPANDED;
9484   else
9485     expander_style = GTK_EXPANDER_COLLAPSED;
9486
9487   gtk_paint_expander (gtk_widget_get_style (widget),
9488                       cr,
9489                       state,
9490                       widget,
9491                       "treeview",
9492                       area.x + area.width / 2,
9493                       area.y + area.height / 2,
9494                       expander_style);
9495 }
9496
9497 static void
9498 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9499
9500 {
9501   GtkTreePath *cursor_path;
9502
9503   if ((tree_view->priv->tree == NULL) ||
9504       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
9505     return;
9506
9507   cursor_path = NULL;
9508   if (tree_view->priv->cursor)
9509     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9510
9511   if (cursor_path == NULL)
9512     {
9513       /* Consult the selection before defaulting to the
9514        * first focusable element
9515        */
9516       GList *selected_rows;
9517       GtkTreeModel *model;
9518       GtkTreeSelection *selection;
9519
9520       selection = gtk_tree_view_get_selection (tree_view);
9521       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9522
9523       if (selected_rows)
9524         {
9525           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9526           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9527           g_list_free (selected_rows);
9528         }
9529       else
9530         {
9531           cursor_path = gtk_tree_path_new_first ();
9532           search_first_focusable_path (tree_view, &cursor_path,
9533                                        TRUE, NULL, NULL);
9534         }
9535
9536       gtk_tree_row_reference_free (tree_view->priv->cursor);
9537       tree_view->priv->cursor = NULL;
9538
9539       if (cursor_path)
9540         {
9541           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9542             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9543           else
9544             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9545         }
9546     }
9547
9548   if (cursor_path)
9549     {
9550       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9551
9552       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9553       gtk_tree_path_free (cursor_path);
9554
9555       if (tree_view->priv->focus_column == NULL)
9556         {
9557           GList *list;
9558           for (list = tree_view->priv->columns; list; list = list->next)
9559             {
9560               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9561                 {
9562                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9563                   break;
9564                 }
9565             }
9566         }
9567     }
9568 }
9569
9570 static void
9571 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9572                                    gint         count)
9573 {
9574   gint selection_count;
9575   GtkRBTree *cursor_tree = NULL;
9576   GtkRBNode *cursor_node = NULL;
9577   GtkRBTree *new_cursor_tree = NULL;
9578   GtkRBNode *new_cursor_node = NULL;
9579   GtkTreePath *cursor_path = NULL;
9580   gboolean grab_focus = TRUE;
9581   gboolean selectable;
9582
9583   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9584     return;
9585
9586   cursor_path = NULL;
9587   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9588     /* FIXME: we lost the cursor; should we get the first? */
9589     return;
9590
9591   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9592   _gtk_tree_view_find_node (tree_view, cursor_path,
9593                             &cursor_tree, &cursor_node);
9594
9595   if (cursor_tree == NULL)
9596     /* FIXME: we lost the cursor; should we get the first? */
9597     return;
9598
9599   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9600   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9601                                                       cursor_node,
9602                                                       cursor_path);
9603
9604   if (selection_count == 0
9605       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9606       && !tree_view->priv->ctrl_pressed
9607       && selectable)
9608     {
9609       /* Don't move the cursor, but just select the current node */
9610       new_cursor_tree = cursor_tree;
9611       new_cursor_node = cursor_node;
9612     }
9613   else
9614     {
9615       if (count == -1)
9616         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9617                                &new_cursor_tree, &new_cursor_node);
9618       else
9619         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9620                                &new_cursor_tree, &new_cursor_node);
9621     }
9622
9623   gtk_tree_path_free (cursor_path);
9624
9625   if (new_cursor_node)
9626     {
9627       cursor_path = _gtk_tree_view_find_path (tree_view,
9628                                               new_cursor_tree, new_cursor_node);
9629
9630       search_first_focusable_path (tree_view, &cursor_path,
9631                                    (count != -1),
9632                                    &new_cursor_tree,
9633                                    &new_cursor_node);
9634
9635       if (cursor_path)
9636         gtk_tree_path_free (cursor_path);
9637     }
9638
9639   /*
9640    * If the list has only one item and multi-selection is set then select
9641    * the row (if not yet selected).
9642    */
9643   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9644       new_cursor_node == NULL)
9645     {
9646       if (count == -1)
9647         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9648                                &new_cursor_tree, &new_cursor_node);
9649       else
9650         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9651                                &new_cursor_tree, &new_cursor_node);
9652
9653       if (new_cursor_node == NULL
9654           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9655         {
9656           new_cursor_node = cursor_node;
9657           new_cursor_tree = cursor_tree;
9658         }
9659       else
9660         {
9661           new_cursor_node = NULL;
9662         }
9663     }
9664
9665   if (new_cursor_node)
9666     {
9667       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9668       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9669       gtk_tree_path_free (cursor_path);
9670     }
9671   else
9672     {
9673       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9674
9675       if (!tree_view->priv->shift_pressed)
9676         {
9677           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9678                                           count < 0 ?
9679                                           GTK_DIR_UP : GTK_DIR_DOWN))
9680             {
9681               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9682
9683               if (toplevel)
9684                 gtk_widget_child_focus (toplevel,
9685                                         count < 0 ?
9686                                         GTK_DIR_TAB_BACKWARD :
9687                                         GTK_DIR_TAB_FORWARD);
9688
9689               grab_focus = FALSE;
9690             }
9691         }
9692       else
9693         {
9694           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9695         }
9696     }
9697
9698   if (grab_focus)
9699     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9700 }
9701
9702 static void
9703 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9704                                         gint         count)
9705 {
9706   GtkRBTree *cursor_tree = NULL;
9707   GtkRBNode *cursor_node = NULL;
9708   GtkTreePath *old_cursor_path = NULL;
9709   GtkTreePath *cursor_path = NULL;
9710   GtkRBTree *start_cursor_tree = NULL;
9711   GtkRBNode *start_cursor_node = NULL;
9712   gint y;
9713   gint window_y;
9714   gint vertical_separator;
9715
9716   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9717     return;
9718
9719   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9720     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9721   else
9722     /* This is sorta weird.  Focus in should give us a cursor */
9723     return;
9724
9725   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9726   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9727                             &cursor_tree, &cursor_node);
9728
9729   if (cursor_tree == NULL)
9730     {
9731       /* FIXME: we lost the cursor.  Should we try to get one? */
9732       gtk_tree_path_free (old_cursor_path);
9733       return;
9734     }
9735   g_return_if_fail (cursor_node != NULL);
9736
9737   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9738   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9739   y += tree_view->priv->cursor_offset;
9740   y += count * (int)tree_view->priv->vadjustment->page_increment;
9741   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9742
9743   if (y >= tree_view->priv->height)
9744     y = tree_view->priv->height - 1;
9745
9746   tree_view->priv->cursor_offset =
9747     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9748                              &cursor_tree, &cursor_node);
9749
9750   if (cursor_tree == NULL)
9751     {
9752       /* FIXME: we lost the cursor.  Should we try to get one? */
9753       gtk_tree_path_free (old_cursor_path);
9754       return;
9755     }
9756
9757   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9758     {
9759       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9760                              &cursor_tree, &cursor_node);
9761       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9762     }
9763
9764   y -= tree_view->priv->cursor_offset;
9765   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9766
9767   start_cursor_tree = cursor_tree;
9768   start_cursor_node = cursor_node;
9769
9770   if (! search_first_focusable_path (tree_view, &cursor_path,
9771                                      (count != -1),
9772                                      &cursor_tree, &cursor_node))
9773     {
9774       /* It looks like we reached the end of the view without finding
9775        * a focusable row.  We will step backwards to find the last
9776        * focusable row.
9777        */
9778       cursor_tree = start_cursor_tree;
9779       cursor_node = start_cursor_node;
9780       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9781
9782       search_first_focusable_path (tree_view, &cursor_path,
9783                                    (count == -1),
9784                                    &cursor_tree, &cursor_node);
9785     }
9786
9787   if (!cursor_path)
9788     goto cleanup;
9789
9790   /* update y */
9791   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9792
9793   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9794
9795   y -= window_y;
9796   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9797   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9798   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9799
9800   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9801     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9802
9803   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9804
9805 cleanup:
9806   gtk_tree_path_free (old_cursor_path);
9807   gtk_tree_path_free (cursor_path);
9808 }
9809
9810 static void
9811 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9812                                       gint         count)
9813 {
9814   GtkRBTree *cursor_tree = NULL;
9815   GtkRBNode *cursor_node = NULL;
9816   GtkTreePath *cursor_path = NULL;
9817   GtkTreeViewColumn *column;
9818   GtkTreeIter iter;
9819   GList *list;
9820   gboolean found_column = FALSE;
9821   gboolean rtl;
9822
9823   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9824
9825   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9826     return;
9827
9828   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9829     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9830   else
9831     return;
9832
9833   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9834   if (cursor_tree == NULL)
9835     return;
9836   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9837     {
9838       gtk_tree_path_free (cursor_path);
9839       return;
9840     }
9841   gtk_tree_path_free (cursor_path);
9842
9843   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9844   if (tree_view->priv->focus_column)
9845     {
9846       for (; list; list = (rtl ? list->prev : list->next))
9847         {
9848           if (list->data == tree_view->priv->focus_column)
9849             break;
9850         }
9851     }
9852
9853   while (list)
9854     {
9855       gboolean left, right;
9856
9857       column = list->data;
9858       if (column->visible == FALSE)
9859         goto loop_end;
9860
9861       gtk_tree_view_column_cell_set_cell_data (column,
9862                                                tree_view->priv->model,
9863                                                &iter,
9864                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9865                                                cursor_node->children?TRUE:FALSE);
9866
9867       if (rtl)
9868         {
9869           right = list->prev ? TRUE : FALSE;
9870           left = list->next ? TRUE : FALSE;
9871         }
9872       else
9873         {
9874           left = list->prev ? TRUE : FALSE;
9875           right = list->next ? TRUE : FALSE;
9876         }
9877
9878       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9879         {
9880           tree_view->priv->focus_column = column;
9881           found_column = TRUE;
9882           break;
9883         }
9884     loop_end:
9885       if (count == 1)
9886         list = rtl ? list->prev : list->next;
9887       else
9888         list = rtl ? list->next : list->prev;
9889     }
9890
9891   if (found_column)
9892     {
9893       if (!gtk_tree_view_has_special_cell (tree_view))
9894         _gtk_tree_view_queue_draw_node (tree_view,
9895                                         cursor_tree,
9896                                         cursor_node,
9897                                         NULL);
9898       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9899       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9900     }
9901   else
9902     {
9903       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9904     }
9905
9906   gtk_tree_view_clamp_column_visible (tree_view,
9907                                       tree_view->priv->focus_column, TRUE);
9908 }
9909
9910 static void
9911 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9912                                      gint         count)
9913 {
9914   GtkRBTree *cursor_tree;
9915   GtkRBNode *cursor_node;
9916   GtkTreePath *path;
9917   GtkTreePath *old_path;
9918
9919   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9920     return;
9921
9922   g_return_if_fail (tree_view->priv->tree != NULL);
9923
9924   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9925
9926   cursor_tree = tree_view->priv->tree;
9927   cursor_node = cursor_tree->root;
9928
9929   if (count == -1)
9930     {
9931       while (cursor_node && cursor_node->left != cursor_tree->nil)
9932         cursor_node = cursor_node->left;
9933
9934       /* Now go forward to find the first focusable row. */
9935       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9936       search_first_focusable_path (tree_view, &path,
9937                                    TRUE, &cursor_tree, &cursor_node);
9938     }
9939   else
9940     {
9941       do
9942         {
9943           while (cursor_node && cursor_node->right != cursor_tree->nil)
9944             cursor_node = cursor_node->right;
9945           if (cursor_node->children == NULL)
9946             break;
9947
9948           cursor_tree = cursor_node->children;
9949           cursor_node = cursor_tree->root;
9950         }
9951       while (1);
9952
9953       /* Now go backwards to find last focusable row. */
9954       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9955       search_first_focusable_path (tree_view, &path,
9956                                    FALSE, &cursor_tree, &cursor_node);
9957     }
9958
9959   if (!path)
9960     goto cleanup;
9961
9962   if (gtk_tree_path_compare (old_path, path))
9963     {
9964       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
9965       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9966     }
9967   else
9968     {
9969       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9970     }
9971
9972 cleanup:
9973   gtk_tree_path_free (old_path);
9974   gtk_tree_path_free (path);
9975 }
9976
9977 static gboolean
9978 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
9979 {
9980   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9981     return FALSE;
9982
9983   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
9984     return FALSE;
9985
9986   gtk_tree_selection_select_all (tree_view->priv->selection);
9987
9988   return TRUE;
9989 }
9990
9991 static gboolean
9992 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
9993 {
9994   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9995     return FALSE;
9996
9997   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
9998     return FALSE;
9999
10000   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10001
10002   return TRUE;
10003 }
10004
10005 static gboolean
10006 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10007                                       gboolean     start_editing)
10008 {
10009   GtkRBTree *new_tree = NULL;
10010   GtkRBNode *new_node = NULL;
10011   GtkRBTree *cursor_tree = NULL;
10012   GtkRBNode *cursor_node = NULL;
10013   GtkTreePath *cursor_path = NULL;
10014   GtkTreeSelectMode mode = 0;
10015
10016   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10017     return FALSE;
10018
10019   if (tree_view->priv->cursor)
10020     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10021
10022   if (cursor_path == NULL)
10023     return FALSE;
10024
10025   _gtk_tree_view_find_node (tree_view, cursor_path,
10026                             &cursor_tree, &cursor_node);
10027
10028   if (cursor_tree == NULL)
10029     {
10030       gtk_tree_path_free (cursor_path);
10031       return FALSE;
10032     }
10033
10034   if (!tree_view->priv->shift_pressed && start_editing &&
10035       tree_view->priv->focus_column)
10036     {
10037       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10038         {
10039           gtk_tree_path_free (cursor_path);
10040           return TRUE;
10041         }
10042     }
10043
10044   if (tree_view->priv->ctrl_pressed)
10045     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10046   if (tree_view->priv->shift_pressed)
10047     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10048
10049   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10050                                             cursor_node,
10051                                             cursor_tree,
10052                                             cursor_path,
10053                                             mode,
10054                                             FALSE);
10055
10056   /* We bail out if the original (tree, node) don't exist anymore after
10057    * handling the selection-changed callback.  We do return TRUE because
10058    * the key press has been handled at this point.
10059    */
10060   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10061
10062   if (cursor_tree != new_tree || cursor_node != new_node)
10063     return FALSE;
10064
10065   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10066
10067   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10068   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10069
10070   if (!tree_view->priv->shift_pressed)
10071     gtk_tree_view_row_activated (tree_view, cursor_path,
10072                                  tree_view->priv->focus_column);
10073     
10074   gtk_tree_path_free (cursor_path);
10075
10076   return TRUE;
10077 }
10078
10079 static gboolean
10080 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10081 {
10082   GtkRBTree *new_tree = NULL;
10083   GtkRBNode *new_node = NULL;
10084   GtkRBTree *cursor_tree = NULL;
10085   GtkRBNode *cursor_node = NULL;
10086   GtkTreePath *cursor_path = NULL;
10087
10088   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10089     return FALSE;
10090
10091   cursor_path = NULL;
10092   if (tree_view->priv->cursor)
10093     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10094
10095   if (cursor_path == NULL)
10096     return FALSE;
10097
10098   _gtk_tree_view_find_node (tree_view, cursor_path,
10099                             &cursor_tree, &cursor_node);
10100   if (cursor_tree == NULL)
10101     {
10102       gtk_tree_path_free (cursor_path);
10103       return FALSE;
10104     }
10105
10106   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10107                                             cursor_node,
10108                                             cursor_tree,
10109                                             cursor_path,
10110                                             GTK_TREE_SELECT_MODE_TOGGLE,
10111                                             FALSE);
10112
10113   /* We bail out if the original (tree, node) don't exist anymore after
10114    * handling the selection-changed callback.  We do return TRUE because
10115    * the key press has been handled at this point.
10116    */
10117   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10118
10119   if (cursor_tree != new_tree || cursor_node != new_node)
10120     return FALSE;
10121
10122   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10123
10124   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10125   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10126   gtk_tree_path_free (cursor_path);
10127
10128   return TRUE;
10129 }
10130
10131 static gboolean
10132 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10133                                                gboolean     logical,
10134                                                gboolean     expand,
10135                                                gboolean     open_all)
10136 {
10137   GtkTreePath *cursor_path = NULL;
10138   GtkRBTree *tree;
10139   GtkRBNode *node;
10140
10141   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10142     return FALSE;
10143
10144   cursor_path = NULL;
10145   if (tree_view->priv->cursor)
10146     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10147
10148   if (cursor_path == NULL)
10149     return FALSE;
10150
10151   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10152     return FALSE;
10153
10154   /* Don't handle the event if we aren't an expander */
10155   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10156     return FALSE;
10157
10158   if (!logical
10159       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10160     expand = !expand;
10161
10162   if (expand)
10163     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10164   else
10165     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10166
10167   gtk_tree_path_free (cursor_path);
10168
10169   return TRUE;
10170 }
10171
10172 static gboolean
10173 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10174 {
10175   GtkRBTree *cursor_tree = NULL;
10176   GtkRBNode *cursor_node = NULL;
10177   GtkTreePath *cursor_path = NULL;
10178   GdkModifierType state;
10179
10180   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10181     goto out;
10182
10183   cursor_path = NULL;
10184   if (tree_view->priv->cursor)
10185     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10186
10187   if (cursor_path == NULL)
10188     goto out;
10189
10190   _gtk_tree_view_find_node (tree_view, cursor_path,
10191                             &cursor_tree, &cursor_node);
10192   if (cursor_tree == NULL)
10193     {
10194       gtk_tree_path_free (cursor_path);
10195       goto out;
10196     }
10197
10198   if (cursor_tree->parent_node)
10199     {
10200       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10201       cursor_node = cursor_tree->parent_node;
10202       cursor_tree = cursor_tree->parent_tree;
10203
10204       gtk_tree_path_up (cursor_path);
10205
10206       if (gtk_get_current_event_state (&state))
10207         {
10208           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10209             tree_view->priv->ctrl_pressed = TRUE;
10210         }
10211
10212       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10213       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10214
10215       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10216       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10217       gtk_tree_path_free (cursor_path);
10218
10219       tree_view->priv->ctrl_pressed = FALSE;
10220
10221       return TRUE;
10222     }
10223
10224  out:
10225
10226   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10227   return FALSE;
10228 }
10229
10230 static gboolean
10231 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10232 {
10233   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10234   tree_view->priv->typeselect_flush_timeout = 0;
10235
10236   return FALSE;
10237 }
10238
10239 /* Cut and paste from gtkwindow.c */
10240 static void
10241 send_focus_change (GtkWidget *widget,
10242                    GdkDevice *device,
10243                    gboolean   in)
10244 {
10245   GdkDeviceManager *device_manager;
10246   GList *devices, *d;
10247
10248   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10249   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10250   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10251   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10252
10253   for (d = devices; d; d = d->next)
10254     {
10255       GdkDevice *dev = d->data;
10256       GdkEvent *fevent;
10257       GdkWindow *window;
10258
10259       if (dev->source != GDK_SOURCE_KEYBOARD)
10260         continue;
10261
10262       window = gtk_widget_get_window (widget);
10263
10264       /* Skip non-master keyboards that haven't
10265        * selected for events from this window
10266        */
10267       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10268           !gdk_window_get_device_events (window, dev))
10269         continue;
10270
10271       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10272
10273       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10274       fevent->focus_change.window = g_object_ref (window);
10275       fevent->focus_change.in = in;
10276       gdk_event_set_device (fevent, device);
10277
10278       gtk_widget_send_focus_change (widget, fevent);
10279
10280       gdk_event_free (fevent);
10281     }
10282 }
10283
10284 static void
10285 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10286 {
10287   GtkWidget *frame, *vbox, *toplevel;
10288   GdkScreen *screen;
10289
10290   if (tree_view->priv->search_custom_entry_set)
10291     return;
10292
10293   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10294   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10295
10296    if (tree_view->priv->search_window != NULL)
10297      {
10298        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10299          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10300                                       GTK_WINDOW (tree_view->priv->search_window));
10301        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10302          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10303                                          GTK_WINDOW (tree_view->priv->search_window));
10304
10305        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10306
10307        return;
10308      }
10309    
10310   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10311   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10312
10313   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10314     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10315                                  GTK_WINDOW (tree_view->priv->search_window));
10316
10317   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10318                             GDK_WINDOW_TYPE_HINT_UTILITY);
10319   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10320   g_signal_connect (tree_view->priv->search_window, "delete-event",
10321                     G_CALLBACK (gtk_tree_view_search_delete_event),
10322                     tree_view);
10323   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10324                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10325                     tree_view);
10326   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10327                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10328                     tree_view);
10329   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10330                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10331                     tree_view);
10332
10333   frame = gtk_frame_new (NULL);
10334   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10335   gtk_widget_show (frame);
10336   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10337
10338   vbox = gtk_vbox_new (FALSE, 0);
10339   gtk_widget_show (vbox);
10340   gtk_container_add (GTK_CONTAINER (frame), vbox);
10341   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10342
10343   /* add entry */
10344   tree_view->priv->search_entry = gtk_entry_new ();
10345   gtk_widget_show (tree_view->priv->search_entry);
10346   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10347                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10348                     tree_view);
10349   g_signal_connect (tree_view->priv->search_entry,
10350                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10351                     tree_view);
10352   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10353                     "preedit-changed",
10354                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10355                     tree_view);
10356   gtk_container_add (GTK_CONTAINER (vbox),
10357                      tree_view->priv->search_entry);
10358
10359   gtk_widget_realize (tree_view->priv->search_entry);
10360 }
10361
10362 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10363  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10364  */
10365 static gboolean
10366 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10367                                              GdkDevice   *device,
10368                                              gboolean     keybinding)
10369 {
10370   /* We only start interactive search if we have focus or the columns
10371    * have focus.  If one of our children have focus, we don't want to
10372    * start the search.
10373    */
10374   GList *list;
10375   gboolean found_focus = FALSE;
10376   GtkWidgetClass *entry_parent_class;
10377   
10378   if (!tree_view->priv->enable_search && !keybinding)
10379     return FALSE;
10380
10381   if (tree_view->priv->search_custom_entry_set)
10382     return FALSE;
10383
10384   if (tree_view->priv->search_window != NULL &&
10385       gtk_widget_get_visible (tree_view->priv->search_window))
10386     return TRUE;
10387
10388   for (list = tree_view->priv->columns; list; list = list->next)
10389     {
10390       GtkTreeViewColumn *column;
10391
10392       column = list->data;
10393       if (! column->visible)
10394         continue;
10395
10396       if (gtk_widget_has_focus (column->button))
10397         {
10398           found_focus = TRUE;
10399           break;
10400         }
10401     }
10402   
10403   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10404     found_focus = TRUE;
10405
10406   if (!found_focus)
10407     return FALSE;
10408
10409   if (tree_view->priv->search_column < 0)
10410     return FALSE;
10411
10412   gtk_tree_view_ensure_interactive_directory (tree_view);
10413
10414   if (keybinding)
10415     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10416
10417   /* done, show it */
10418   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10419   gtk_widget_show (tree_view->priv->search_window);
10420   if (tree_view->priv->search_entry_changed_id == 0)
10421     {
10422       tree_view->priv->search_entry_changed_id =
10423         g_signal_connect (tree_view->priv->search_entry, "changed",
10424                           G_CALLBACK (gtk_tree_view_search_init),
10425                           tree_view);
10426     }
10427
10428   tree_view->priv->typeselect_flush_timeout =
10429     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10430                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10431                    tree_view);
10432
10433   /* Grab focus will select all the text.  We don't want that to happen, so we
10434    * call the parent instance and bypass the selection change.  This is probably
10435    * really non-kosher. */
10436   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10437   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10438
10439   /* send focus-in event */
10440   send_focus_change (tree_view->priv->search_entry, device, TRUE);
10441
10442   /* search first matching iter */
10443   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10444
10445   return TRUE;
10446 }
10447
10448 static gboolean
10449 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10450 {
10451   return gtk_tree_view_real_start_interactive_search (tree_view,
10452                                                       gtk_get_current_event_device (),
10453                                                       TRUE);
10454 }
10455
10456 /* this function returns the new width of the column being resized given
10457  * the column and x position of the cursor; the x cursor position is passed
10458  * in as a pointer and automagicly corrected if it's beyond min/max limits
10459  */
10460 static gint
10461 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10462                                 gint       i,
10463                                 gint      *x)
10464 {
10465   GtkAllocation allocation;
10466   GtkTreeViewColumn *column;
10467   GtkRequisition button_req;
10468   gint width;
10469   gboolean rtl;
10470
10471   /* first translate the x position from widget->window
10472    * to clist->clist_window
10473    */
10474   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10475   column = g_list_nth (tree_view->priv->columns, i)->data;
10476   gtk_widget_get_allocation (column->button, &allocation);
10477   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
10478
10479   /* Clamp down the value */
10480   if (column->min_width == -1)
10481     {
10482       gtk_widget_get_preferred_size (column->button, &button_req, NULL);
10483       width = MAX (button_req.width, width);
10484     }
10485   else
10486     width = MAX (column->min_width,
10487                  width);
10488   if (column->max_width != -1)
10489     width = MIN (width, column->max_width);
10490
10491   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
10492
10493   return width;
10494 }
10495
10496
10497 /* FIXME this adjust_allocation is a big cut-and-paste from
10498  * GtkCList, needs to be some "official" way to do this
10499  * factored out.
10500  */
10501 typedef struct
10502 {
10503   GdkWindow *window;
10504   int dx;
10505   int dy;
10506 } ScrollData;
10507
10508 /* The window to which widget->window is relative */
10509 #define ALLOCATION_WINDOW(widget)               \
10510    (!gtk_widget_get_has_window (widget) ?                   \
10511     gtk_widget_get_window (widget) :                        \
10512     gdk_window_get_parent (gtk_widget_get_window (widget)))
10513
10514 static void
10515 adjust_allocation_recurse (GtkWidget *widget,
10516                            gpointer   data)
10517 {
10518   GtkAllocation allocation;
10519   ScrollData *scroll_data = data;
10520
10521   /* Need to really size allocate instead of just poking
10522    * into widget->allocation if the widget is not realized.
10523    * FIXME someone figure out why this was.
10524    */
10525   gtk_widget_get_allocation (widget, &allocation);
10526   if (!gtk_widget_get_realized (widget))
10527     {
10528       if (gtk_widget_get_visible (widget))
10529         {
10530           GdkRectangle tmp_rectangle = allocation;
10531           tmp_rectangle.x += scroll_data->dx;
10532           tmp_rectangle.y += scroll_data->dy;
10533           
10534           gtk_widget_size_allocate (widget, &tmp_rectangle);
10535         }
10536     }
10537   else
10538     {
10539       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10540         {
10541           allocation.x += scroll_data->dx;
10542           allocation.y += scroll_data->dy;
10543           gtk_widget_set_allocation (widget, &allocation);
10544
10545           if (GTK_IS_CONTAINER (widget))
10546             gtk_container_forall (GTK_CONTAINER (widget),
10547                                   adjust_allocation_recurse,
10548                                   data);
10549         }
10550     }
10551 }
10552
10553 static void
10554 adjust_allocation (GtkWidget *widget,
10555                    int        dx,
10556                    int        dy)
10557 {
10558   ScrollData scroll_data;
10559
10560   if (gtk_widget_get_realized (widget))
10561     scroll_data.window = ALLOCATION_WINDOW (widget);
10562   else
10563     scroll_data.window = NULL;
10564     
10565   scroll_data.dx = dx;
10566   scroll_data.dy = dy;
10567   
10568   adjust_allocation_recurse (widget, &scroll_data);
10569 }
10570
10571 /* Callbacks */
10572 static void
10573 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10574                                   GtkTreeView   *tree_view)
10575 {
10576   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10577     {
10578       gint dy;
10579         
10580       gdk_window_move (tree_view->priv->bin_window,
10581                        - tree_view->priv->hadjustment->value,
10582                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10583       gdk_window_move (tree_view->priv->header_window,
10584                        - tree_view->priv->hadjustment->value,
10585                        0);
10586       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10587       if (dy)
10588         {
10589           update_prelight (tree_view,
10590                            tree_view->priv->event_last_x,
10591                            tree_view->priv->event_last_y - dy);
10592
10593           if (tree_view->priv->edited_column &&
10594               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       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10626       gtk_tree_view_bin_process_updates (tree_view);
10627     }
10628 }
10629
10630 \f
10631
10632 /* Public methods
10633  */
10634
10635 /**
10636  * gtk_tree_view_new:
10637  *
10638  * Creates a new #GtkTreeView widget.
10639  *
10640  * Return value: A newly created #GtkTreeView widget.
10641  **/
10642 GtkWidget *
10643 gtk_tree_view_new (void)
10644 {
10645   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10646 }
10647
10648 /**
10649  * gtk_tree_view_new_with_model:
10650  * @model: the model.
10651  *
10652  * Creates a new #GtkTreeView widget with the model initialized to @model.
10653  *
10654  * Return value: A newly created #GtkTreeView widget.
10655  **/
10656 GtkWidget *
10657 gtk_tree_view_new_with_model (GtkTreeModel *model)
10658 {
10659   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10660 }
10661
10662 /* Public Accessors
10663  */
10664
10665 /**
10666  * gtk_tree_view_get_model:
10667  * @tree_view: a #GtkTreeView
10668  *
10669  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10670  * model is unset.
10671  *
10672  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
10673  **/
10674 GtkTreeModel *
10675 gtk_tree_view_get_model (GtkTreeView *tree_view)
10676 {
10677   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10678
10679   return tree_view->priv->model;
10680 }
10681
10682 /**
10683  * gtk_tree_view_set_model:
10684  * @tree_view: A #GtkTreeNode.
10685  * @model: (allow-none): The model.
10686  *
10687  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10688  * set, it will remove it before setting the new model.  If @model is %NULL,
10689  * then it will unset the old model.
10690  **/
10691 void
10692 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10693                          GtkTreeModel *model)
10694 {
10695   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10696   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10697
10698   if (model == tree_view->priv->model)
10699     return;
10700
10701   if (tree_view->priv->scroll_to_path)
10702     {
10703       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10704       tree_view->priv->scroll_to_path = NULL;
10705     }
10706
10707   if (tree_view->priv->model)
10708     {
10709       GList *tmplist = tree_view->priv->columns;
10710
10711       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10712       gtk_tree_view_stop_editing (tree_view, TRUE);
10713
10714       remove_expand_collapse_timeout (tree_view);
10715
10716       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10717                                             gtk_tree_view_row_changed,
10718                                             tree_view);
10719       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10720                                             gtk_tree_view_row_inserted,
10721                                             tree_view);
10722       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10723                                             gtk_tree_view_row_has_child_toggled,
10724                                             tree_view);
10725       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10726                                             gtk_tree_view_row_deleted,
10727                                             tree_view);
10728       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10729                                             gtk_tree_view_rows_reordered,
10730                                             tree_view);
10731
10732       for (; tmplist; tmplist = tmplist->next)
10733         _gtk_tree_view_column_unset_model (tmplist->data,
10734                                            tree_view->priv->model);
10735
10736       if (tree_view->priv->tree)
10737         gtk_tree_view_free_rbtree (tree_view);
10738
10739       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10740       tree_view->priv->drag_dest_row = NULL;
10741       gtk_tree_row_reference_free (tree_view->priv->cursor);
10742       tree_view->priv->cursor = NULL;
10743       gtk_tree_row_reference_free (tree_view->priv->anchor);
10744       tree_view->priv->anchor = NULL;
10745       gtk_tree_row_reference_free (tree_view->priv->top_row);
10746       tree_view->priv->top_row = NULL;
10747       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10748       tree_view->priv->scroll_to_path = NULL;
10749
10750       tree_view->priv->scroll_to_column = NULL;
10751
10752       g_object_unref (tree_view->priv->model);
10753
10754       tree_view->priv->search_column = -1;
10755       tree_view->priv->fixed_height_check = 0;
10756       tree_view->priv->fixed_height = -1;
10757       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10758       tree_view->priv->last_button_x = -1;
10759       tree_view->priv->last_button_y = -1;
10760     }
10761
10762   tree_view->priv->model = model;
10763
10764   if (tree_view->priv->model)
10765     {
10766       gint i;
10767       GtkTreePath *path;
10768       GtkTreeIter iter;
10769       GtkTreeModelFlags flags;
10770
10771       if (tree_view->priv->search_column == -1)
10772         {
10773           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10774             {
10775               GType type = gtk_tree_model_get_column_type (model, i);
10776
10777               if (g_value_type_transformable (type, G_TYPE_STRING))
10778                 {
10779                   tree_view->priv->search_column = i;
10780                   break;
10781                 }
10782             }
10783         }
10784
10785       g_object_ref (tree_view->priv->model);
10786       g_signal_connect (tree_view->priv->model,
10787                         "row-changed",
10788                         G_CALLBACK (gtk_tree_view_row_changed),
10789                         tree_view);
10790       g_signal_connect (tree_view->priv->model,
10791                         "row-inserted",
10792                         G_CALLBACK (gtk_tree_view_row_inserted),
10793                         tree_view);
10794       g_signal_connect (tree_view->priv->model,
10795                         "row-has-child-toggled",
10796                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10797                         tree_view);
10798       g_signal_connect (tree_view->priv->model,
10799                         "row-deleted",
10800                         G_CALLBACK (gtk_tree_view_row_deleted),
10801                         tree_view);
10802       g_signal_connect (tree_view->priv->model,
10803                         "rows-reordered",
10804                         G_CALLBACK (gtk_tree_view_rows_reordered),
10805                         tree_view);
10806
10807       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10808       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10809         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10810       else
10811         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10812
10813       path = gtk_tree_path_new_first ();
10814       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10815         {
10816           tree_view->priv->tree = _gtk_rbtree_new ();
10817           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10818         }
10819       gtk_tree_path_free (path);
10820
10821       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10822       install_presize_handler (tree_view);
10823     }
10824
10825   g_object_notify (G_OBJECT (tree_view), "model");
10826
10827   if (tree_view->priv->selection)
10828   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10829
10830   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10831     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10832 }
10833
10834 /**
10835  * gtk_tree_view_get_selection:
10836  * @tree_view: A #GtkTreeView.
10837  *
10838  * Gets the #GtkTreeSelection associated with @tree_view.
10839  *
10840  * Return value: (transfer none): A #GtkTreeSelection object.
10841  **/
10842 GtkTreeSelection *
10843 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10844 {
10845   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10846
10847   return tree_view->priv->selection;
10848 }
10849
10850 /**
10851  * gtk_tree_view_get_hadjustment:
10852  * @tree_view: A #GtkTreeView
10853  *
10854  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10855  *
10856  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
10857  *     if none is currently being used.
10858  *
10859  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
10860  **/
10861 GtkAdjustment *
10862 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10863 {
10864   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10865
10866   return tree_view->priv->hadjustment;
10867 }
10868
10869 /**
10870  * gtk_tree_view_set_hadjustment:
10871  * @tree_view: A #GtkTreeView
10872  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10873  *
10874  * Sets the #GtkAdjustment for the current horizontal aspect.
10875  *
10876  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
10877  **/
10878 void
10879 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10880                                GtkAdjustment *adjustment)
10881 {
10882   GtkTreeViewPrivate *priv = tree_view->priv;
10883
10884   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10885   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
10886
10887   if (adjustment && priv->hadjustment == adjustment)
10888     return;
10889
10890   if (priv->hadjustment != NULL)
10891     {
10892       g_signal_handlers_disconnect_by_func (priv->hadjustment,
10893                                             gtk_tree_view_adjustment_changed,
10894                                             tree_view);
10895       g_object_unref (priv->hadjustment);
10896     }
10897
10898   if (adjustment == NULL)
10899     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
10900                                      0.0, 0.0, 0.0);
10901
10902   g_signal_connect (adjustment, "value-changed",
10903                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
10904   priv->hadjustment = g_object_ref_sink (adjustment);
10905   /* FIXME: Adjustment should probably be populated here with fresh values, but
10906    * internal details are too complicated for me to decipher right now.
10907    */
10908   gtk_tree_view_adjustment_changed (NULL, tree_view);
10909
10910   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10911 }
10912
10913 /**
10914  * gtk_tree_view_get_vadjustment:
10915  * @tree_view: A #GtkTreeView
10916  *
10917  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10918  *
10919  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
10920  *     if none is currently being used.
10921  *
10922  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
10923  **/
10924 GtkAdjustment *
10925 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10926 {
10927   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10928
10929   return tree_view->priv->vadjustment;
10930 }
10931
10932 /**
10933  * gtk_tree_view_set_vadjustment:
10934  * @tree_view: A #GtkTreeView
10935  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10936  *
10937  * Sets the #GtkAdjustment for the current vertical aspect.
10938  *
10939  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
10940  **/
10941 void
10942 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10943                                GtkAdjustment *adjustment)
10944 {
10945   GtkTreeViewPrivate *priv = tree_view->priv;
10946
10947   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10948   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
10949
10950   if (adjustment && priv->vadjustment == adjustment)
10951     return;
10952
10953   if (priv->vadjustment != NULL)
10954     {
10955       g_signal_handlers_disconnect_by_func (priv->vadjustment,
10956                                             gtk_tree_view_adjustment_changed,
10957                                             tree_view);
10958       g_object_unref (priv->vadjustment);
10959     }
10960
10961   if (adjustment == NULL)
10962     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
10963                                      0.0, 0.0, 0.0);
10964
10965   g_signal_connect (adjustment, "value-changed",
10966                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
10967   priv->vadjustment = g_object_ref_sink (adjustment);
10968   /* FIXME: Adjustment should probably be populated here with fresh values, but
10969    * internal details are too complicated for me to decipher right now.
10970    */
10971   gtk_tree_view_adjustment_changed (NULL, tree_view);
10972   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10973 }
10974
10975 /* Column and header operations */
10976
10977 /**
10978  * gtk_tree_view_get_headers_visible:
10979  * @tree_view: A #GtkTreeView.
10980  *
10981  * Returns %TRUE if the headers on the @tree_view are visible.
10982  *
10983  * Return value: Whether the headers are visible or not.
10984  **/
10985 gboolean
10986 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10987 {
10988   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10989
10990   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10991 }
10992
10993 /**
10994  * gtk_tree_view_set_headers_visible:
10995  * @tree_view: A #GtkTreeView.
10996  * @headers_visible: %TRUE if the headers are visible
10997  *
10998  * Sets the visibility state of the headers.
10999  **/
11000 void
11001 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11002                                    gboolean     headers_visible)
11003 {
11004   gint x, y;
11005   GList *list;
11006   GtkTreeViewColumn *column;
11007   GtkAllocation allocation;
11008
11009   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11010
11011   headers_visible = !! headers_visible;
11012
11013   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
11014     return;
11015
11016   if (headers_visible)
11017     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11018   else
11019     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11020
11021   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11022     {
11023       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11024       if (headers_visible)
11025         {
11026           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11027           gdk_window_move_resize (tree_view->priv->bin_window,
11028                                   x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view),
11029                                   tree_view->priv->width, allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
11030
11031           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11032             gtk_tree_view_map_buttons (tree_view);
11033         }
11034       else
11035         {
11036           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11037
11038           for (list = tree_view->priv->columns; list; list = list->next)
11039             {
11040               column = list->data;
11041               gtk_widget_unmap (column->button);
11042             }
11043           gdk_window_hide (tree_view->priv->header_window);
11044         }
11045     }
11046
11047   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11048   tree_view->priv->vadjustment->page_size = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11049   tree_view->priv->vadjustment->page_increment = (allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11050   tree_view->priv->vadjustment->lower = 0;
11051   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11052   gtk_adjustment_changed (tree_view->priv->vadjustment);
11053
11054   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11055
11056   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11057 }
11058
11059 /**
11060  * gtk_tree_view_columns_autosize:
11061  * @tree_view: A #GtkTreeView.
11062  *
11063  * Resizes all columns to their optimal width. Only works after the
11064  * treeview has been realized.
11065  **/
11066 void
11067 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11068 {
11069   gboolean dirty = FALSE;
11070   GList *list;
11071   GtkTreeViewColumn *column;
11072
11073   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11074
11075   for (list = tree_view->priv->columns; list; list = list->next)
11076     {
11077       column = list->data;
11078       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11079         continue;
11080       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11081       dirty = TRUE;
11082     }
11083
11084   if (dirty)
11085     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11086 }
11087
11088 /**
11089  * gtk_tree_view_set_headers_clickable:
11090  * @tree_view: A #GtkTreeView.
11091  * @setting: %TRUE if the columns are clickable.
11092  *
11093  * Allow the column title buttons to be clicked.
11094  **/
11095 void
11096 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11097                                      gboolean   setting)
11098 {
11099   GList *list;
11100
11101   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11102
11103   for (list = tree_view->priv->columns; list; list = list->next)
11104     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11105
11106   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11107 }
11108
11109
11110 /**
11111  * gtk_tree_view_get_headers_clickable:
11112  * @tree_view: A #GtkTreeView.
11113  *
11114  * Returns whether all header columns are clickable.
11115  *
11116  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11117  *
11118  * Since: 2.10
11119  **/
11120 gboolean 
11121 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11122 {
11123   GList *list;
11124   
11125   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11126
11127   for (list = tree_view->priv->columns; list; list = list->next)
11128     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11129       return FALSE;
11130
11131   return TRUE;
11132 }
11133
11134 /**
11135  * gtk_tree_view_set_rules_hint
11136  * @tree_view: a #GtkTreeView
11137  * @setting: %TRUE if the tree requires reading across rows
11138  *
11139  * This function tells GTK+ that the user interface for your
11140  * application requires users to read across tree rows and associate
11141  * cells with one another. By default, GTK+ will then render the tree
11142  * with alternating row colors. Do <emphasis>not</emphasis> use it
11143  * just because you prefer the appearance of the ruled tree; that's a
11144  * question for the theme. Some themes will draw tree rows in
11145  * alternating colors even when rules are turned off, and users who
11146  * prefer that appearance all the time can choose those themes. You
11147  * should call this function only as a <emphasis>semantic</emphasis>
11148  * hint to the theme engine that your tree makes alternating colors
11149  * useful from a functional standpoint (since it has lots of columns,
11150  * generally).
11151  *
11152  **/
11153 void
11154 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11155                               gboolean      setting)
11156 {
11157   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11158
11159   setting = setting != FALSE;
11160
11161   if (tree_view->priv->has_rules != setting)
11162     {
11163       tree_view->priv->has_rules = setting;
11164       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11165     }
11166
11167   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11168 }
11169
11170 /**
11171  * gtk_tree_view_get_rules_hint
11172  * @tree_view: a #GtkTreeView
11173  *
11174  * Gets the setting set by gtk_tree_view_set_rules_hint().
11175  *
11176  * Return value: %TRUE if rules are useful for the user of this tree
11177  **/
11178 gboolean
11179 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11180 {
11181   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11182
11183   return tree_view->priv->has_rules;
11184 }
11185
11186 /* Public Column functions
11187  */
11188
11189 /**
11190  * gtk_tree_view_append_column:
11191  * @tree_view: A #GtkTreeView.
11192  * @column: The #GtkTreeViewColumn to add.
11193  *
11194  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11195  * mode enabled, then @column must have its "sizing" property set to be
11196  * GTK_TREE_VIEW_COLUMN_FIXED.
11197  *
11198  * Return value: The number of columns in @tree_view after appending.
11199  **/
11200 gint
11201 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11202                              GtkTreeViewColumn *column)
11203 {
11204   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11205   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11206   g_return_val_if_fail (column->tree_view == NULL, -1);
11207
11208   return gtk_tree_view_insert_column (tree_view, column, -1);
11209 }
11210
11211
11212 /**
11213  * gtk_tree_view_remove_column:
11214  * @tree_view: A #GtkTreeView.
11215  * @column: The #GtkTreeViewColumn to remove.
11216  *
11217  * Removes @column from @tree_view.
11218  *
11219  * Return value: The number of columns in @tree_view after removing.
11220  **/
11221 gint
11222 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11223                              GtkTreeViewColumn *column)
11224 {
11225   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11226   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11227   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11228
11229   if (tree_view->priv->focus_column == column)
11230     tree_view->priv->focus_column = NULL;
11231
11232   if (tree_view->priv->edited_column == column)
11233     {
11234       gtk_tree_view_stop_editing (tree_view, TRUE);
11235
11236       /* no need to, but just to be sure ... */
11237       tree_view->priv->edited_column = NULL;
11238     }
11239
11240   if (tree_view->priv->expander_column == column)
11241     tree_view->priv->expander_column = NULL;
11242
11243   g_signal_handlers_disconnect_by_func (column,
11244                                         G_CALLBACK (column_sizing_notify),
11245                                         tree_view);
11246
11247   _gtk_tree_view_column_unset_tree_view (column);
11248
11249   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11250   tree_view->priv->n_columns--;
11251
11252   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11253     {
11254       GList *list;
11255
11256       _gtk_tree_view_column_unrealize_button (column);
11257       for (list = tree_view->priv->columns; list; list = list->next)
11258         {
11259           GtkTreeViewColumn *tmp_column;
11260
11261           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11262           if (tmp_column->visible)
11263             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11264         }
11265
11266       if (tree_view->priv->n_columns == 0 &&
11267           gtk_tree_view_get_headers_visible (tree_view))
11268         gdk_window_hide (tree_view->priv->header_window);
11269
11270       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11271     }
11272
11273   g_object_unref (column);
11274   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11275
11276   return tree_view->priv->n_columns;
11277 }
11278
11279 /**
11280  * gtk_tree_view_insert_column:
11281  * @tree_view: A #GtkTreeView.
11282  * @column: The #GtkTreeViewColumn to be inserted.
11283  * @position: The position to insert @column in.
11284  *
11285  * This inserts the @column into the @tree_view at @position.  If @position is
11286  * -1, then the column is inserted at the end. If @tree_view has
11287  * "fixed_height" mode enabled, then @column must have its "sizing" property
11288  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11289  *
11290  * Return value: The number of columns in @tree_view after insertion.
11291  **/
11292 gint
11293 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11294                              GtkTreeViewColumn *column,
11295                              gint               position)
11296 {
11297   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11298   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11299   g_return_val_if_fail (column->tree_view == NULL, -1);
11300
11301   if (tree_view->priv->fixed_height_mode)
11302     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11303                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11304
11305   g_object_ref_sink (column);
11306
11307   if (tree_view->priv->n_columns == 0 &&
11308       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11309       gtk_tree_view_get_headers_visible (tree_view))
11310     {
11311       gdk_window_show (tree_view->priv->header_window);
11312     }
11313
11314   g_signal_connect (column, "notify::sizing",
11315                     G_CALLBACK (column_sizing_notify), tree_view);
11316
11317   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11318                                             column, position);
11319   tree_view->priv->n_columns++;
11320
11321   _gtk_tree_view_column_set_tree_view (column, tree_view);
11322
11323   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11324     {
11325       GList *list;
11326
11327       _gtk_tree_view_column_realize_button (column);
11328
11329       for (list = tree_view->priv->columns; list; list = list->next)
11330         {
11331           column = GTK_TREE_VIEW_COLUMN (list->data);
11332           if (column->visible)
11333             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11334         }
11335       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11336     }
11337
11338   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11339
11340   return tree_view->priv->n_columns;
11341 }
11342
11343 /**
11344  * gtk_tree_view_insert_column_with_attributes:
11345  * @tree_view: A #GtkTreeView
11346  * @position: The position to insert the new column in.
11347  * @title: The title to set the header to.
11348  * @cell: The #GtkCellRenderer.
11349  * @Varargs: A %NULL-terminated list of attributes.
11350  *
11351  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11352  * @position.  If @position is -1, then the newly created column is inserted at
11353  * the end.  The column is initialized with the attributes given. If @tree_view
11354  * has "fixed_height" mode enabled, then the new column will have its sizing
11355  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11356  *
11357  * Return value: The number of columns in @tree_view after insertion.
11358  **/
11359 gint
11360 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11361                                              gint             position,
11362                                              const gchar     *title,
11363                                              GtkCellRenderer *cell,
11364                                              ...)
11365 {
11366   GtkTreeViewColumn *column;
11367   gchar *attribute;
11368   va_list args;
11369   gint column_id;
11370
11371   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11372
11373   column = gtk_tree_view_column_new ();
11374   if (tree_view->priv->fixed_height_mode)
11375     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11376
11377   gtk_tree_view_column_set_title (column, title);
11378   gtk_tree_view_column_pack_start (column, cell, TRUE);
11379
11380   va_start (args, cell);
11381
11382   attribute = va_arg (args, gchar *);
11383
11384   while (attribute != NULL)
11385     {
11386       column_id = va_arg (args, gint);
11387       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11388       attribute = va_arg (args, gchar *);
11389     }
11390
11391   va_end (args);
11392
11393   gtk_tree_view_insert_column (tree_view, column, position);
11394
11395   return tree_view->priv->n_columns;
11396 }
11397
11398 /**
11399  * gtk_tree_view_insert_column_with_data_func:
11400  * @tree_view: a #GtkTreeView
11401  * @position: Position to insert, -1 for append
11402  * @title: column title
11403  * @cell: cell renderer for column
11404  * @func: function to set attributes of cell renderer
11405  * @data: data for @func
11406  * @dnotify: destroy notifier for @data
11407  *
11408  * Convenience function that inserts a new column into the #GtkTreeView
11409  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11410  * attributes (normally using data from the model). See also
11411  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11412  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11413  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11414  *
11415  * Return value: number of columns in the tree view post-insert
11416  **/
11417 gint
11418 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11419                                              gint                       position,
11420                                              const gchar               *title,
11421                                              GtkCellRenderer           *cell,
11422                                              GtkTreeCellDataFunc        func,
11423                                              gpointer                   data,
11424                                              GDestroyNotify             dnotify)
11425 {
11426   GtkTreeViewColumn *column;
11427
11428   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11429
11430   column = gtk_tree_view_column_new ();
11431   if (tree_view->priv->fixed_height_mode)
11432     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11433
11434   gtk_tree_view_column_set_title (column, title);
11435   gtk_tree_view_column_pack_start (column, cell, TRUE);
11436   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11437
11438   gtk_tree_view_insert_column (tree_view, column, position);
11439
11440   return tree_view->priv->n_columns;
11441 }
11442
11443 /**
11444  * gtk_tree_view_get_column:
11445  * @tree_view: A #GtkTreeView.
11446  * @n: The position of the column, counting from 0.
11447  *
11448  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11449  *
11450  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
11451  *     position is outside the range of columns.
11452  **/
11453 GtkTreeViewColumn *
11454 gtk_tree_view_get_column (GtkTreeView *tree_view,
11455                           gint         n)
11456 {
11457   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11458
11459   if (n < 0 || n >= tree_view->priv->n_columns)
11460     return NULL;
11461
11462   if (tree_view->priv->columns == NULL)
11463     return NULL;
11464
11465   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11466 }
11467
11468 /**
11469  * gtk_tree_view_get_columns:
11470  * @tree_view: A #GtkTreeView
11471  *
11472  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11473  * The returned list must be freed with g_list_free ().
11474  *
11475  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11476  **/
11477 GList *
11478 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11479 {
11480   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11481
11482   return g_list_copy (tree_view->priv->columns);
11483 }
11484
11485 /**
11486  * gtk_tree_view_move_column_after:
11487  * @tree_view: A #GtkTreeView
11488  * @column: The #GtkTreeViewColumn to be moved.
11489  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11490  *
11491  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11492  * @column is placed in the first position.
11493  **/
11494 void
11495 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11496                                  GtkTreeViewColumn *column,
11497                                  GtkTreeViewColumn *base_column)
11498 {
11499   GList *column_list_el, *base_el = NULL;
11500
11501   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11502
11503   column_list_el = g_list_find (tree_view->priv->columns, column);
11504   g_return_if_fail (column_list_el != NULL);
11505
11506   if (base_column)
11507     {
11508       base_el = g_list_find (tree_view->priv->columns, base_column);
11509       g_return_if_fail (base_el != NULL);
11510     }
11511
11512   if (column_list_el->prev == base_el)
11513     return;
11514
11515   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11516   if (base_el == NULL)
11517     {
11518       column_list_el->prev = NULL;
11519       column_list_el->next = tree_view->priv->columns;
11520       if (column_list_el->next)
11521         column_list_el->next->prev = column_list_el;
11522       tree_view->priv->columns = column_list_el;
11523     }
11524   else
11525     {
11526       column_list_el->prev = base_el;
11527       column_list_el->next = base_el->next;
11528       if (column_list_el->next)
11529         column_list_el->next->prev = column_list_el;
11530       base_el->next = column_list_el;
11531     }
11532
11533   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11534     {
11535       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11536       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11537     }
11538
11539   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11540 }
11541
11542 /**
11543  * gtk_tree_view_set_expander_column:
11544  * @tree_view: A #GtkTreeView
11545  * @column: %NULL, or the column to draw the expander arrow at.
11546  *
11547  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11548  * If @column is %NULL, then the expander arrow is always at the first 
11549  * visible column.
11550  *
11551  * If you do not want expander arrow to appear in your tree, set the 
11552  * expander column to a hidden column.
11553  **/
11554 void
11555 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11556                                    GtkTreeViewColumn *column)
11557 {
11558   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11559   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11560
11561   if (tree_view->priv->expander_column != column)
11562     {
11563       GList *list;
11564
11565       if (column)
11566         {
11567           /* Confirm that column is in tree_view */
11568           for (list = tree_view->priv->columns; list; list = list->next)
11569             if (list->data == column)
11570               break;
11571           g_return_if_fail (list != NULL);
11572         }
11573
11574       tree_view->priv->expander_column = column;
11575       g_object_notify (G_OBJECT (tree_view), "expander-column");
11576     }
11577 }
11578
11579 /**
11580  * gtk_tree_view_get_expander_column:
11581  * @tree_view: A #GtkTreeView
11582  *
11583  * Returns the column that is the current expander column.
11584  * This column has the expander arrow drawn next to it.
11585  *
11586  * Return value: (transfer none): The expander column.
11587  **/
11588 GtkTreeViewColumn *
11589 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11590 {
11591   GList *list;
11592
11593   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11594
11595   for (list = tree_view->priv->columns; list; list = list->next)
11596     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11597       return (GtkTreeViewColumn *) list->data;
11598   return NULL;
11599 }
11600
11601
11602 /**
11603  * gtk_tree_view_set_column_drag_function:
11604  * @tree_view: A #GtkTreeView.
11605  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
11606  * @user_data: (allow-none): User data to be passed to @func, or %NULL
11607  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
11608  *
11609  * Sets a user function for determining where a column may be dropped when
11610  * dragged.  This function is called on every column pair in turn at the
11611  * beginning of a column drag to determine where a drop can take place.  The
11612  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11613  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11614  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11615  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11616  * @tree_view reverts to the default behavior of allowing all columns to be
11617  * dropped everywhere.
11618  **/
11619 void
11620 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11621                                         GtkTreeViewColumnDropFunc  func,
11622                                         gpointer                   user_data,
11623                                         GDestroyNotify             destroy)
11624 {
11625   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11626
11627   if (tree_view->priv->column_drop_func_data_destroy)
11628     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11629
11630   tree_view->priv->column_drop_func = func;
11631   tree_view->priv->column_drop_func_data = user_data;
11632   tree_view->priv->column_drop_func_data_destroy = destroy;
11633 }
11634
11635 /**
11636  * gtk_tree_view_scroll_to_point:
11637  * @tree_view: a #GtkTreeView
11638  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11639  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11640  *
11641  * Scrolls the tree view such that the top-left corner of the visible
11642  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11643  * in tree coordinates.  The @tree_view must be realized before
11644  * this function is called.  If it isn't, you probably want to be
11645  * using gtk_tree_view_scroll_to_cell().
11646  *
11647  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11648  **/
11649 void
11650 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11651                                gint         tree_x,
11652                                gint         tree_y)
11653 {
11654   GtkAdjustment *hadj;
11655   GtkAdjustment *vadj;
11656
11657   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11658   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
11659
11660   hadj = tree_view->priv->hadjustment;
11661   vadj = tree_view->priv->vadjustment;
11662
11663   if (tree_x != -1)
11664     gtk_adjustment_set_value (hadj, tree_x);
11665   if (tree_y != -1)
11666     gtk_adjustment_set_value (vadj, tree_y);
11667 }
11668
11669 /**
11670  * gtk_tree_view_scroll_to_cell:
11671  * @tree_view: A #GtkTreeView.
11672  * @path: (allow-none): The path of the row to move to, or %NULL.
11673  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11674  * @use_align: whether to use alignment arguments, or %FALSE.
11675  * @row_align: The vertical alignment of the row specified by @path.
11676  * @col_align: The horizontal alignment of the column specified by @column.
11677  *
11678  * Moves the alignments of @tree_view to the position specified by @column and
11679  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11680  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11681  * or @path need to be non-%NULL.  @row_align determines where the row is
11682  * placed, and @col_align determines where @column is placed.  Both are expected
11683  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11684  * right/bottom alignment, 0.5 means center.
11685  *
11686  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11687  * tree does the minimum amount of work to scroll the cell onto the screen.
11688  * This means that the cell will be scrolled to the edge closest to its current
11689  * position.  If the cell is currently visible on the screen, nothing is done.
11690  *
11691  * This function only works if the model is set, and @path is a valid row on the
11692  * model.  If the model changes before the @tree_view is realized, the centered
11693  * path will be modified to reflect this change.
11694  **/
11695 void
11696 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11697                               GtkTreePath       *path,
11698                               GtkTreeViewColumn *column,
11699                               gboolean           use_align,
11700                               gfloat             row_align,
11701                               gfloat             col_align)
11702 {
11703   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11704   g_return_if_fail (tree_view->priv->model != NULL);
11705   g_return_if_fail (tree_view->priv->tree != NULL);
11706   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11707   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11708   g_return_if_fail (path != NULL || column != NULL);
11709
11710 #if 0
11711   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11712            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11713 #endif
11714   row_align = CLAMP (row_align, 0.0, 1.0);
11715   col_align = CLAMP (col_align, 0.0, 1.0);
11716
11717
11718   /* Note: Despite the benefits that come from having one code path for the
11719    * scrolling code, we short-circuit validate_visible_area's immplementation as
11720    * it is much slower than just going to the point.
11721    */
11722   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
11723       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
11724       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
11725       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11726     {
11727       if (tree_view->priv->scroll_to_path)
11728         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11729
11730       tree_view->priv->scroll_to_path = NULL;
11731       tree_view->priv->scroll_to_column = NULL;
11732
11733       if (path)
11734         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11735       if (column)
11736         tree_view->priv->scroll_to_column = column;
11737       tree_view->priv->scroll_to_use_align = use_align;
11738       tree_view->priv->scroll_to_row_align = row_align;
11739       tree_view->priv->scroll_to_col_align = col_align;
11740
11741       install_presize_handler (tree_view);
11742     }
11743   else
11744     {
11745       GdkRectangle cell_rect;
11746       GdkRectangle vis_rect;
11747       gint dest_x, dest_y;
11748
11749       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11750       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11751
11752       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11753
11754       dest_x = vis_rect.x;
11755       dest_y = vis_rect.y;
11756
11757       if (column)
11758         {
11759           if (use_align)
11760             {
11761               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11762             }
11763           else
11764             {
11765               if (cell_rect.x < vis_rect.x)
11766                 dest_x = cell_rect.x;
11767               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11768                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11769             }
11770         }
11771
11772       if (path)
11773         {
11774           if (use_align)
11775             {
11776               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11777               dest_y = MAX (dest_y, 0);
11778             }
11779           else
11780             {
11781               if (cell_rect.y < vis_rect.y)
11782                 dest_y = cell_rect.y;
11783               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11784                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11785             }
11786         }
11787
11788       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11789     }
11790 }
11791
11792 /**
11793  * gtk_tree_view_row_activated:
11794  * @tree_view: A #GtkTreeView
11795  * @path: The #GtkTreePath to be activated.
11796  * @column: The #GtkTreeViewColumn to be activated.
11797  *
11798  * Activates the cell determined by @path and @column.
11799  **/
11800 void
11801 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11802                              GtkTreePath       *path,
11803                              GtkTreeViewColumn *column)
11804 {
11805   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11806
11807   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11808 }
11809
11810
11811 static void
11812 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11813                                           GtkRBNode *node,
11814                                           gpointer   data)
11815 {
11816   GtkTreeView *tree_view = data;
11817
11818   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11819       node->children)
11820     {
11821       GtkTreePath *path;
11822       GtkTreeIter iter;
11823
11824       path = _gtk_tree_view_find_path (tree_view, tree, node);
11825       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11826
11827       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11828
11829       gtk_tree_path_free (path);
11830     }
11831
11832   if (node->children)
11833     _gtk_rbtree_traverse (node->children,
11834                           node->children->root,
11835                           G_PRE_ORDER,
11836                           gtk_tree_view_expand_all_emission_helper,
11837                           tree_view);
11838 }
11839
11840 /**
11841  * gtk_tree_view_expand_all:
11842  * @tree_view: A #GtkTreeView.
11843  *
11844  * Recursively expands all nodes in the @tree_view.
11845  **/
11846 void
11847 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11848 {
11849   GtkTreePath *path;
11850   GtkRBTree *tree;
11851   GtkRBNode *node;
11852
11853   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11854
11855   if (tree_view->priv->tree == NULL)
11856     return;
11857
11858   path = gtk_tree_path_new_first ();
11859   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11860
11861   while (node)
11862     {
11863       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11864       node = _gtk_rbtree_next (tree, node);
11865       gtk_tree_path_next (path);
11866   }
11867
11868   gtk_tree_path_free (path);
11869 }
11870
11871 /* Timeout to animate the expander during expands and collapses */
11872 static gboolean
11873 expand_collapse_timeout (gpointer data)
11874 {
11875   return do_expand_collapse (data);
11876 }
11877
11878 static void
11879 add_expand_collapse_timeout (GtkTreeView *tree_view,
11880                              GtkRBTree   *tree,
11881                              GtkRBNode   *node,
11882                              gboolean     expand)
11883 {
11884   if (tree_view->priv->expand_collapse_timeout != 0)
11885     return;
11886
11887   tree_view->priv->expand_collapse_timeout =
11888       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11889   tree_view->priv->expanded_collapsed_tree = tree;
11890   tree_view->priv->expanded_collapsed_node = node;
11891
11892   if (expand)
11893     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11894   else
11895     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11896 }
11897
11898 static void
11899 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11900 {
11901   if (tree_view->priv->expand_collapse_timeout)
11902     {
11903       g_source_remove (tree_view->priv->expand_collapse_timeout);
11904       tree_view->priv->expand_collapse_timeout = 0;
11905     }
11906
11907   if (tree_view->priv->expanded_collapsed_node != NULL)
11908     {
11909       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11910       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11911
11912       tree_view->priv->expanded_collapsed_node = NULL;
11913     }
11914 }
11915
11916 static void
11917 cancel_arrow_animation (GtkTreeView *tree_view)
11918 {
11919   if (tree_view->priv->expand_collapse_timeout)
11920     {
11921       while (do_expand_collapse (tree_view));
11922
11923       remove_expand_collapse_timeout (tree_view);
11924     }
11925 }
11926
11927 static gboolean
11928 do_expand_collapse (GtkTreeView *tree_view)
11929 {
11930   GtkRBNode *node;
11931   GtkRBTree *tree;
11932   gboolean expanding;
11933   gboolean redraw;
11934
11935   redraw = FALSE;
11936   expanding = TRUE;
11937
11938   node = tree_view->priv->expanded_collapsed_node;
11939   tree = tree_view->priv->expanded_collapsed_tree;
11940
11941   if (node->children == NULL)
11942     expanding = FALSE;
11943
11944   if (expanding)
11945     {
11946       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11947         {
11948           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11949           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11950
11951           redraw = TRUE;
11952
11953         }
11954       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11955         {
11956           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11957
11958           redraw = TRUE;
11959         }
11960     }
11961   else
11962     {
11963       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11964         {
11965           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11966           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11967
11968           redraw = TRUE;
11969         }
11970       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11971         {
11972           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11973
11974           redraw = TRUE;
11975
11976         }
11977     }
11978
11979   if (redraw)
11980     {
11981       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
11982
11983       return TRUE;
11984     }
11985
11986   return FALSE;
11987 }
11988
11989 /**
11990  * gtk_tree_view_collapse_all:
11991  * @tree_view: A #GtkTreeView.
11992  *
11993  * Recursively collapses all visible, expanded nodes in @tree_view.
11994  **/
11995 void
11996 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11997 {
11998   GtkRBTree *tree;
11999   GtkRBNode *node;
12000   GtkTreePath *path;
12001   gint *indices;
12002
12003   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12004
12005   if (tree_view->priv->tree == NULL)
12006     return;
12007
12008   path = gtk_tree_path_new ();
12009   gtk_tree_path_down (path);
12010   indices = gtk_tree_path_get_indices (path);
12011
12012   tree = tree_view->priv->tree;
12013   node = tree->root;
12014   while (node && node->left != tree->nil)
12015     node = node->left;
12016
12017   while (node)
12018     {
12019       if (node->children)
12020         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12021       indices[0]++;
12022       node = _gtk_rbtree_next (tree, node);
12023     }
12024
12025   gtk_tree_path_free (path);
12026 }
12027
12028 /**
12029  * gtk_tree_view_expand_to_path:
12030  * @tree_view: A #GtkTreeView.
12031  * @path: path to a row.
12032  *
12033  * Expands the row at @path. This will also expand all parent rows of
12034  * @path as necessary.
12035  *
12036  * Since: 2.2
12037  **/
12038 void
12039 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12040                               GtkTreePath *path)
12041 {
12042   gint i, depth;
12043   gint *indices;
12044   GtkTreePath *tmp;
12045
12046   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12047   g_return_if_fail (path != NULL);
12048
12049   depth = gtk_tree_path_get_depth (path);
12050   indices = gtk_tree_path_get_indices (path);
12051
12052   tmp = gtk_tree_path_new ();
12053   g_return_if_fail (tmp != NULL);
12054
12055   for (i = 0; i < depth; i++)
12056     {
12057       gtk_tree_path_append_index (tmp, indices[i]);
12058       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12059     }
12060
12061   gtk_tree_path_free (tmp);
12062 }
12063
12064 /* FIXME the bool return values for expand_row and collapse_row are
12065  * not analagous; they should be TRUE if the row had children and
12066  * was not already in the requested state.
12067  */
12068
12069
12070 static gboolean
12071 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12072                                GtkTreePath *path,
12073                                GtkRBTree   *tree,
12074                                GtkRBNode   *node,
12075                                gboolean     open_all,
12076                                gboolean     animate)
12077 {
12078   GtkTreeIter iter;
12079   GtkTreeIter temp;
12080   gboolean expand;
12081
12082   if (animate)
12083     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12084                   "gtk-enable-animations", &animate,
12085                   NULL);
12086
12087   remove_auto_expand_timeout (tree_view);
12088
12089   if (node->children && !open_all)
12090     return FALSE;
12091
12092   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12093     return FALSE;
12094
12095   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12096   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12097     return FALSE;
12098
12099
12100    if (node->children && open_all)
12101     {
12102       gboolean retval = FALSE;
12103       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12104
12105       gtk_tree_path_append_index (tmp_path, 0);
12106       tree = node->children;
12107       node = tree->root;
12108       while (node->left != tree->nil)
12109         node = node->left;
12110       /* try to expand the children */
12111       do
12112         {
12113          gboolean t;
12114          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12115                                             TRUE, animate);
12116          if (t)
12117            retval = TRUE;
12118
12119          gtk_tree_path_next (tmp_path);
12120          node = _gtk_rbtree_next (tree, node);
12121        }
12122       while (node != NULL);
12123
12124       gtk_tree_path_free (tmp_path);
12125
12126       return retval;
12127     }
12128
12129   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12130
12131   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12132     return FALSE;
12133
12134   if (expand)
12135     return FALSE;
12136
12137   node->children = _gtk_rbtree_new ();
12138   node->children->parent_tree = tree;
12139   node->children->parent_node = node;
12140
12141   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12142
12143   gtk_tree_view_build_tree (tree_view,
12144                             node->children,
12145                             &temp,
12146                             gtk_tree_path_get_depth (path) + 1,
12147                             open_all);
12148
12149   remove_expand_collapse_timeout (tree_view);
12150
12151   if (animate)
12152     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12153
12154   install_presize_handler (tree_view);
12155
12156   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12157   if (open_all && node->children)
12158     {
12159       _gtk_rbtree_traverse (node->children,
12160                             node->children->root,
12161                             G_PRE_ORDER,
12162                             gtk_tree_view_expand_all_emission_helper,
12163                             tree_view);
12164     }
12165   return TRUE;
12166 }
12167
12168
12169 /**
12170  * gtk_tree_view_expand_row:
12171  * @tree_view: a #GtkTreeView
12172  * @path: path to a row
12173  * @open_all: whether to recursively expand, or just expand immediate children
12174  *
12175  * Opens the row so its children are visible.
12176  *
12177  * Return value: %TRUE if the row existed and had children
12178  **/
12179 gboolean
12180 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12181                           GtkTreePath *path,
12182                           gboolean     open_all)
12183 {
12184   GtkRBTree *tree;
12185   GtkRBNode *node;
12186
12187   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12188   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12189   g_return_val_if_fail (path != NULL, FALSE);
12190
12191   if (_gtk_tree_view_find_node (tree_view,
12192                                 path,
12193                                 &tree,
12194                                 &node))
12195     return FALSE;
12196
12197   if (tree != NULL)
12198     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12199   else
12200     return FALSE;
12201 }
12202
12203 static gboolean
12204 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12205                                  GtkTreePath *path,
12206                                  GtkRBTree   *tree,
12207                                  GtkRBNode   *node,
12208                                  gboolean     animate)
12209 {
12210   GtkTreeIter iter;
12211   GtkTreeIter children;
12212   gboolean collapse;
12213   gint x, y;
12214   GList *list;
12215   GdkWindow *child, *parent;
12216
12217   if (animate)
12218     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12219                   "gtk-enable-animations", &animate,
12220                   NULL);
12221
12222   remove_auto_expand_timeout (tree_view);
12223
12224   if (node->children == NULL)
12225     return FALSE;
12226
12227   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12228
12229   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12230
12231   if (collapse)
12232     return FALSE;
12233
12234   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12235    * a chance to prelight the correct node below */
12236
12237   if (tree_view->priv->prelight_tree)
12238     {
12239       GtkRBTree *parent_tree;
12240       GtkRBNode *parent_node;
12241
12242       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12243       parent_node = tree_view->priv->prelight_tree->parent_node;
12244       while (parent_tree)
12245         {
12246           if (parent_tree == tree && parent_node == node)
12247             {
12248               ensure_unprelighted (tree_view);
12249               break;
12250             }
12251           parent_node = parent_tree->parent_node;
12252           parent_tree = parent_tree->parent_tree;
12253         }
12254     }
12255
12256   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12257
12258   for (list = tree_view->priv->columns; list; list = list->next)
12259     {
12260       GtkTreeViewColumn *column = list->data;
12261
12262       if (column->visible == FALSE)
12263         continue;
12264       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12265         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12266     }
12267
12268   if (tree_view->priv->destroy_count_func)
12269     {
12270       GtkTreePath *child_path;
12271       gint child_count = 0;
12272       child_path = gtk_tree_path_copy (path);
12273       gtk_tree_path_down (child_path);
12274       if (node->children)
12275         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12276       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12277       gtk_tree_path_free (child_path);
12278     }
12279
12280   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12281     {
12282       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12283
12284       if (gtk_tree_path_is_ancestor (path, cursor_path))
12285         {
12286           gtk_tree_row_reference_free (tree_view->priv->cursor);
12287           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12288                                                                       tree_view->priv->model,
12289                                                                       path);
12290         }
12291       gtk_tree_path_free (cursor_path);
12292     }
12293
12294   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12295     {
12296       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12297       if (gtk_tree_path_is_ancestor (path, anchor_path))
12298         {
12299           gtk_tree_row_reference_free (tree_view->priv->anchor);
12300           tree_view->priv->anchor = NULL;
12301         }
12302       gtk_tree_path_free (anchor_path);
12303     }
12304
12305   /* Stop a pending double click */
12306   tree_view->priv->last_button_x = -1;
12307   tree_view->priv->last_button_y = -1;
12308
12309   remove_expand_collapse_timeout (tree_view);
12310
12311   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12312     {
12313       _gtk_rbtree_remove (node->children);
12314       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12315     }
12316   else
12317     _gtk_rbtree_remove (node->children);
12318   
12319   if (animate)
12320     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12321   
12322   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12323     {
12324       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12325     }
12326
12327   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12328
12329   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12330     {
12331       /* now that we've collapsed all rows, we want to try to set the prelight
12332        * again. To do this, we fake a motion event and send it to ourselves. */
12333
12334       child = tree_view->priv->bin_window;
12335       parent = gdk_window_get_parent (child);
12336
12337       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12338         {
12339           GdkEventMotion event;
12340           gint child_x, child_y;
12341
12342           gdk_window_get_position (child, &child_x, &child_y);
12343
12344           event.window = tree_view->priv->bin_window;
12345           event.x = x - child_x;
12346           event.y = y - child_y;
12347
12348           /* despite the fact this isn't a real event, I'm almost positive it will
12349            * never trigger a drag event.  maybe_drag is the only function that uses
12350            * more than just event.x and event.y. */
12351           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12352         }
12353     }
12354
12355   return TRUE;
12356 }
12357
12358 /**
12359  * gtk_tree_view_collapse_row:
12360  * @tree_view: a #GtkTreeView
12361  * @path: path to a row in the @tree_view
12362  *
12363  * Collapses a row (hides its child rows, if they exist).
12364  *
12365  * Return value: %TRUE if the row was collapsed.
12366  **/
12367 gboolean
12368 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12369                             GtkTreePath *path)
12370 {
12371   GtkRBTree *tree;
12372   GtkRBNode *node;
12373
12374   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12375   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12376   g_return_val_if_fail (path != NULL, FALSE);
12377
12378   if (_gtk_tree_view_find_node (tree_view,
12379                                 path,
12380                                 &tree,
12381                                 &node))
12382     return FALSE;
12383
12384   if (tree == NULL || node->children == NULL)
12385     return FALSE;
12386
12387   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12388 }
12389
12390 static void
12391 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12392                                         GtkRBTree              *tree,
12393                                         GtkTreePath            *path,
12394                                         GtkTreeViewMappingFunc  func,
12395                                         gpointer                user_data)
12396 {
12397   GtkRBNode *node;
12398
12399   if (tree == NULL || tree->root == NULL)
12400     return;
12401
12402   node = tree->root;
12403
12404   while (node && node->left != tree->nil)
12405     node = node->left;
12406
12407   while (node)
12408     {
12409       if (node->children)
12410         {
12411           (* func) (tree_view, path, user_data);
12412           gtk_tree_path_down (path);
12413           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12414           gtk_tree_path_up (path);
12415         }
12416       gtk_tree_path_next (path);
12417       node = _gtk_rbtree_next (tree, node);
12418     }
12419 }
12420
12421 /**
12422  * gtk_tree_view_map_expanded_rows:
12423  * @tree_view: A #GtkTreeView
12424  * @func: (scope call): A function to be called
12425  * @data: User data to be passed to the function.
12426  *
12427  * Calls @func on all expanded rows.
12428  **/
12429 void
12430 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12431                                  GtkTreeViewMappingFunc  func,
12432                                  gpointer                user_data)
12433 {
12434   GtkTreePath *path;
12435
12436   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12437   g_return_if_fail (func != NULL);
12438
12439   path = gtk_tree_path_new_first ();
12440
12441   gtk_tree_view_map_expanded_rows_helper (tree_view,
12442                                           tree_view->priv->tree,
12443                                           path, func, user_data);
12444
12445   gtk_tree_path_free (path);
12446 }
12447
12448 /**
12449  * gtk_tree_view_row_expanded:
12450  * @tree_view: A #GtkTreeView.
12451  * @path: A #GtkTreePath to test expansion state.
12452  *
12453  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12454  *
12455  * Return value: %TRUE if #path is expanded.
12456  **/
12457 gboolean
12458 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12459                             GtkTreePath *path)
12460 {
12461   GtkRBTree *tree;
12462   GtkRBNode *node;
12463
12464   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12465   g_return_val_if_fail (path != NULL, FALSE);
12466
12467   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12468
12469   if (node == NULL)
12470     return FALSE;
12471
12472   return (node->children != NULL);
12473 }
12474
12475 /**
12476  * gtk_tree_view_get_reorderable:
12477  * @tree_view: a #GtkTreeView
12478  *
12479  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12480  * gtk_tree_view_set_reorderable().
12481  *
12482  * Return value: %TRUE if the tree can be reordered.
12483  **/
12484 gboolean
12485 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12486 {
12487   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12488
12489   return tree_view->priv->reorderable;
12490 }
12491
12492 /**
12493  * gtk_tree_view_set_reorderable:
12494  * @tree_view: A #GtkTreeView.
12495  * @reorderable: %TRUE, if the tree can be reordered.
12496  *
12497  * This function is a convenience function to allow you to reorder
12498  * models that support the #GtkDragSourceIface and the
12499  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12500  * these.  If @reorderable is %TRUE, then the user can reorder the
12501  * model by dragging and dropping rows. The developer can listen to
12502  * these changes by connecting to the model's row_inserted and
12503  * row_deleted signals. The reordering is implemented by setting up
12504  * the tree view as a drag source and destination. Therefore, drag and
12505  * drop can not be used in a reorderable view for any other purpose.
12506  *
12507  * This function does not give you any degree of control over the order -- any
12508  * reordering is allowed.  If more control is needed, you should probably
12509  * handle drag and drop manually.
12510  **/
12511 void
12512 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12513                                gboolean     reorderable)
12514 {
12515   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12516
12517   reorderable = reorderable != FALSE;
12518
12519   if (tree_view->priv->reorderable == reorderable)
12520     return;
12521
12522   if (reorderable)
12523     {
12524       const GtkTargetEntry row_targets[] = {
12525         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12526       };
12527
12528       gtk_tree_view_enable_model_drag_source (tree_view,
12529                                               GDK_BUTTON1_MASK,
12530                                               row_targets,
12531                                               G_N_ELEMENTS (row_targets),
12532                                               GDK_ACTION_MOVE);
12533       gtk_tree_view_enable_model_drag_dest (tree_view,
12534                                             row_targets,
12535                                             G_N_ELEMENTS (row_targets),
12536                                             GDK_ACTION_MOVE);
12537     }
12538   else
12539     {
12540       gtk_tree_view_unset_rows_drag_source (tree_view);
12541       gtk_tree_view_unset_rows_drag_dest (tree_view);
12542     }
12543
12544   tree_view->priv->reorderable = reorderable;
12545
12546   g_object_notify (G_OBJECT (tree_view), "reorderable");
12547 }
12548
12549 static void
12550 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12551                                GtkTreePath     *path,
12552                                gboolean         clear_and_select,
12553                                gboolean         clamp_node)
12554 {
12555   GtkRBTree *tree = NULL;
12556   GtkRBNode *node = NULL;
12557
12558   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12559     {
12560       GtkTreePath *cursor_path;
12561       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12562       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12563       gtk_tree_path_free (cursor_path);
12564     }
12565
12566   gtk_tree_row_reference_free (tree_view->priv->cursor);
12567   tree_view->priv->cursor = NULL;
12568
12569   /* One cannot set the cursor on a separator.   Also, if
12570    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12571    * before finding the tree and node belonging to path.  The
12572    * path maps to a non-existing path and we will silently bail out.
12573    * We unset tree and node to avoid further processing.
12574    */
12575   if (!row_is_separator (tree_view, NULL, path)
12576       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12577     {
12578       tree_view->priv->cursor =
12579           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12580                                             tree_view->priv->model,
12581                                             path);
12582     }
12583   else
12584     {
12585       tree = NULL;
12586       node = NULL;
12587     }
12588
12589   if (tree != NULL)
12590     {
12591       GtkRBTree *new_tree = NULL;
12592       GtkRBNode *new_node = NULL;
12593
12594       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12595         {
12596           GtkTreeSelectMode mode = 0;
12597
12598           if (tree_view->priv->ctrl_pressed)
12599             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12600           if (tree_view->priv->shift_pressed)
12601             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12602
12603           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12604                                                     node, tree, path, mode,
12605                                                     FALSE);
12606         }
12607
12608       /* We have to re-find tree and node here again, somebody might have
12609        * cleared the node or the whole tree in the GtkTreeSelection::changed
12610        * callback. If the nodes differ we bail out here.
12611        */
12612       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12613
12614       if (tree != new_tree || node != new_node)
12615         return;
12616
12617       if (clamp_node)
12618         {
12619           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12620           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12621         }
12622     }
12623
12624   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12625 }
12626
12627 /**
12628  * gtk_tree_view_get_cursor:
12629  * @tree_view: A #GtkTreeView
12630  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
12631  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
12632  *
12633  * Fills in @path and @focus_column with the current path and focus column.  If
12634  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12635  * currently has focus, then *@focus_column will be %NULL.
12636  *
12637  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12638  * you are done with it.
12639  **/
12640 void
12641 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12642                           GtkTreePath       **path,
12643                           GtkTreeViewColumn **focus_column)
12644 {
12645   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12646
12647   if (path)
12648     {
12649       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12650         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12651       else
12652         *path = NULL;
12653     }
12654
12655   if (focus_column)
12656     {
12657       *focus_column = tree_view->priv->focus_column;
12658     }
12659 }
12660
12661 /**
12662  * gtk_tree_view_set_cursor:
12663  * @tree_view: A #GtkTreeView
12664  * @path: A #GtkTreePath
12665  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12666  * @start_editing: %TRUE if the specified cell should start being edited.
12667  *
12668  * Sets the current keyboard focus to be at @path, and selects it.  This is
12669  * useful when you want to focus the user's attention on a particular row.  If
12670  * @focus_column is not %NULL, then focus is given to the column specified by 
12671  * it. Additionally, if @focus_column is specified, and @start_editing is 
12672  * %TRUE, then editing should be started in the specified cell.  
12673  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12674  * in order to give keyboard focus to the widget.  Please note that editing 
12675  * can only happen when the widget is realized.
12676  *
12677  * If @path is invalid for @model, the current cursor (if any) will be unset
12678  * and the function will return without failing.
12679  **/
12680 void
12681 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12682                           GtkTreePath       *path,
12683                           GtkTreeViewColumn *focus_column,
12684                           gboolean           start_editing)
12685 {
12686   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12687                                     NULL, start_editing);
12688 }
12689
12690 /**
12691  * gtk_tree_view_set_cursor_on_cell:
12692  * @tree_view: A #GtkTreeView
12693  * @path: A #GtkTreePath
12694  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12695  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12696  * @start_editing: %TRUE if the specified cell should start being edited.
12697  *
12698  * Sets the current keyboard focus to be at @path, and selects it.  This is
12699  * useful when you want to focus the user's attention on a particular row.  If
12700  * @focus_column is not %NULL, then focus is given to the column specified by
12701  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12702  * contains 2 or more editable or activatable cells, then focus is given to
12703  * the cell specified by @focus_cell. Additionally, if @focus_column is
12704  * specified, and @start_editing is %TRUE, then editing should be started in
12705  * the specified cell.  This function is often followed by
12706  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12707  * widget.  Please note that editing can only happen when the widget is
12708  * realized.
12709  *
12710  * If @path is invalid for @model, the current cursor (if any) will be unset
12711  * and the function will return without failing.
12712  *
12713  * Since: 2.2
12714  **/
12715 void
12716 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12717                                   GtkTreePath       *path,
12718                                   GtkTreeViewColumn *focus_column,
12719                                   GtkCellRenderer   *focus_cell,
12720                                   gboolean           start_editing)
12721 {
12722   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12723   g_return_if_fail (path != NULL);
12724   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12725
12726   if (!tree_view->priv->model)
12727     return;
12728
12729   if (focus_cell)
12730     {
12731       g_return_if_fail (focus_column);
12732       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12733     }
12734
12735   /* cancel the current editing, if it exists */
12736   if (tree_view->priv->edited_column &&
12737       tree_view->priv->edited_column->editable_widget)
12738     gtk_tree_view_stop_editing (tree_view, TRUE);
12739
12740   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12741
12742   if (focus_column && focus_column->visible)
12743     {
12744       GList *list;
12745       gboolean column_in_tree = FALSE;
12746
12747       for (list = tree_view->priv->columns; list; list = list->next)
12748         if (list->data == focus_column)
12749           {
12750             column_in_tree = TRUE;
12751             break;
12752           }
12753       g_return_if_fail (column_in_tree);
12754       tree_view->priv->focus_column = focus_column;
12755       if (focus_cell)
12756         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12757       if (start_editing)
12758         gtk_tree_view_start_editing (tree_view, path);
12759     }
12760 }
12761
12762 /**
12763  * gtk_tree_view_get_bin_window:
12764  * @tree_view: A #GtkTreeView
12765  *
12766  * Returns the window that @tree_view renders to.
12767  * This is used primarily to compare to <literal>event->window</literal>
12768  * to confirm that the event on @tree_view is on the right window.
12769  *
12770  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
12771  *     hasn't been realized yet
12772  **/
12773 GdkWindow *
12774 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12775 {
12776   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12777
12778   return tree_view->priv->bin_window;
12779 }
12780
12781 /**
12782  * gtk_tree_view_get_path_at_pos:
12783  * @tree_view: A #GtkTreeView.
12784  * @x: The x position to be identified (relative to bin_window).
12785  * @y: The y position to be identified (relative to bin_window).
12786  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12787  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12788  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
12789  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12790  *
12791  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12792  * (please see gtk_tree_view_get_bin_window()).
12793  * That is, @x and @y are relative to an events coordinates. @x and @y must
12794  * come from an event on the @tree_view only where <literal>event->window ==
12795  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12796  * things like popup menus. If @path is non-%NULL, then it will be filled
12797  * with the #GtkTreePath at that point.  This path should be freed with
12798  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12799  * with the column at that point.  @cell_x and @cell_y return the coordinates
12800  * relative to the cell background (i.e. the @background_area passed to
12801  * gtk_cell_renderer_render()).  This function is only meaningful if
12802  * @tree_view is realized.  Therefore this function will always return %FALSE
12803  * if @tree_view is not realized or does not have a model.
12804  *
12805  * For converting widget coordinates (eg. the ones you get from
12806  * GtkWidget::query-tooltip), please see
12807  * gtk_tree_view_convert_widget_to_bin_window_coords().
12808  *
12809  * Return value: %TRUE if a row exists at that coordinate.
12810  **/
12811 gboolean
12812 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12813                                gint                x,
12814                                gint                y,
12815                                GtkTreePath       **path,
12816                                GtkTreeViewColumn **column,
12817                                gint               *cell_x,
12818                                gint               *cell_y)
12819 {
12820   GtkRBTree *tree;
12821   GtkRBNode *node;
12822   gint y_offset;
12823
12824   g_return_val_if_fail (tree_view != NULL, FALSE);
12825
12826   if (path)
12827     *path = NULL;
12828   if (column)
12829     *column = NULL;
12830
12831   if (tree_view->priv->bin_window == NULL)
12832     return FALSE;
12833
12834   if (tree_view->priv->tree == NULL)
12835     return FALSE;
12836
12837   if (x > tree_view->priv->hadjustment->upper)
12838     return FALSE;
12839
12840   if (x < 0 || y < 0)
12841     return FALSE;
12842
12843   if (column || cell_x)
12844     {
12845       GtkTreeViewColumn *tmp_column;
12846       GtkTreeViewColumn *last_column = NULL;
12847       GList *list;
12848       gint remaining_x = x;
12849       gboolean found = FALSE;
12850       gboolean rtl;
12851
12852       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12853       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12854            list;
12855            list = (rtl ? list->prev : list->next))
12856         {
12857           tmp_column = list->data;
12858
12859           if (tmp_column->visible == FALSE)
12860             continue;
12861
12862           last_column = tmp_column;
12863           if (remaining_x <= tmp_column->width)
12864             {
12865               found = TRUE;
12866
12867               if (column)
12868                 *column = tmp_column;
12869
12870               if (cell_x)
12871                 *cell_x = remaining_x;
12872
12873               break;
12874             }
12875           remaining_x -= tmp_column->width;
12876         }
12877
12878       /* If found is FALSE and there is a last_column, then it the remainder
12879        * space is in that area
12880        */
12881       if (!found)
12882         {
12883           if (last_column)
12884             {
12885               if (column)
12886                 *column = last_column;
12887               
12888               if (cell_x)
12889                 *cell_x = last_column->width + remaining_x;
12890             }
12891           else
12892             {
12893               return FALSE;
12894             }
12895         }
12896     }
12897
12898   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12899                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12900                                       &tree, &node);
12901
12902   if (tree == NULL)
12903     return FALSE;
12904
12905   if (cell_y)
12906     *cell_y = y_offset;
12907
12908   if (path)
12909     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12910
12911   return TRUE;
12912 }
12913
12914
12915 /**
12916  * gtk_tree_view_get_cell_area:
12917  * @tree_view: a #GtkTreeView
12918  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12919  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12920  * @rect: rectangle to fill with cell rect
12921  *
12922  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12923  * row specified by @path and the column specified by @column.  If @path is
12924  * %NULL, or points to a path not currently displayed, the @y and @height fields
12925  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12926  * fields will be filled with 0.  The sum of all cell rects does not cover the
12927  * entire tree; there are extra pixels in between rows, for example. The
12928  * returned rectangle is equivalent to the @cell_area passed to
12929  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12930  * realized.
12931  **/
12932 void
12933 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12934                              GtkTreePath        *path,
12935                              GtkTreeViewColumn  *column,
12936                              GdkRectangle       *rect)
12937 {
12938   GtkAllocation allocation;
12939   GtkRBTree *tree = NULL;
12940   GtkRBNode *node = NULL;
12941   gint vertical_separator;
12942   gint horizontal_separator;
12943
12944   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12945   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12946   g_return_if_fail (rect != NULL);
12947   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12948   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12949
12950   gtk_widget_style_get (GTK_WIDGET (tree_view),
12951                         "vertical-separator", &vertical_separator,
12952                         "horizontal-separator", &horizontal_separator,
12953                         NULL);
12954
12955   rect->x = 0;
12956   rect->y = 0;
12957   rect->width = 0;
12958   rect->height = 0;
12959
12960   if (column)
12961     {
12962       gtk_widget_get_allocation (column->button, &allocation);
12963       rect->x = allocation.x + horizontal_separator/2;
12964       rect->width = allocation.width - horizontal_separator;
12965     }
12966
12967   if (path)
12968     {
12969       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12970
12971       /* Get vertical coords */
12972       if ((!ret && tree == NULL) || ret)
12973         return;
12974
12975       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12976       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12977
12978       if (column &&
12979           gtk_tree_view_is_expander_column (tree_view, column))
12980         {
12981           gint depth = gtk_tree_path_get_depth (path);
12982           gboolean rtl;
12983
12984           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12985
12986           if (!rtl)
12987             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12988           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12989
12990           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12991             {
12992               if (!rtl)
12993                 rect->x += depth * tree_view->priv->expander_size;
12994               rect->width -= depth * tree_view->priv->expander_size;
12995             }
12996
12997           rect->width = MAX (rect->width, 0);
12998         }
12999     }
13000 }
13001
13002 /**
13003  * gtk_tree_view_get_background_area:
13004  * @tree_view: a #GtkTreeView
13005  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13006  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13007  * @rect: rectangle to fill with cell background rect
13008  *
13009  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13010  * row specified by @path and the column specified by @column.  If @path is
13011  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13012  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13013  * fields will be filled with 0.  The returned rectangle is equivalent to the
13014  * @background_area passed to gtk_cell_renderer_render().  These background
13015  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13016  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13017  * itself, excluding surrounding borders and the tree expander area.
13018  *
13019  **/
13020 void
13021 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13022                                    GtkTreePath        *path,
13023                                    GtkTreeViewColumn  *column,
13024                                    GdkRectangle       *rect)
13025 {
13026   GtkRBTree *tree = NULL;
13027   GtkRBNode *node = NULL;
13028
13029   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13030   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13031   g_return_if_fail (rect != NULL);
13032
13033   rect->x = 0;
13034   rect->y = 0;
13035   rect->width = 0;
13036   rect->height = 0;
13037
13038   if (path)
13039     {
13040       /* Get vertical coords */
13041
13042       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13043           tree == NULL)
13044         return;
13045
13046       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13047
13048       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13049     }
13050
13051   if (column)
13052     {
13053       gint x2 = 0;
13054
13055       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13056       rect->width = x2 - rect->x;
13057     }
13058 }
13059
13060 /**
13061  * gtk_tree_view_get_visible_rect:
13062  * @tree_view: a #GtkTreeView
13063  * @visible_rect: rectangle to fill
13064  *
13065  * Fills @visible_rect with the currently-visible region of the
13066  * buffer, in tree coordinates. Convert to bin_window coordinates with
13067  * gtk_tree_view_convert_tree_to_bin_window_coords().
13068  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13069  * scrollable area of the tree.
13070  **/
13071 void
13072 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13073                                 GdkRectangle *visible_rect)
13074 {
13075   GtkAllocation allocation;
13076   GtkWidget *widget;
13077
13078   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13079
13080   widget = GTK_WIDGET (tree_view);
13081
13082   if (visible_rect)
13083     {
13084       gtk_widget_get_allocation (widget, &allocation);
13085       visible_rect->x = tree_view->priv->hadjustment->value;
13086       visible_rect->y = tree_view->priv->vadjustment->value;
13087       visible_rect->width = allocation.width;
13088       visible_rect->height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13089     }
13090 }
13091
13092 /**
13093  * gtk_tree_view_convert_widget_to_tree_coords:
13094  * @tree_view: a #GtkTreeView
13095  * @wx: X coordinate relative to the widget
13096  * @wy: Y coordinate relative to the widget
13097  * @tx: return location for tree X coordinate
13098  * @ty: return location for tree Y coordinate
13099  *
13100  * Converts widget coordinates to coordinates for the
13101  * tree (the full scrollable area of the tree).
13102  *
13103  * Since: 2.12
13104  **/
13105 void
13106 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13107                                              gint         wx,
13108                                              gint         wy,
13109                                              gint        *tx,
13110                                              gint        *ty)
13111 {
13112   gint x, y;
13113
13114   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13115
13116   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13117                                                      wx, wy,
13118                                                      &x, &y);
13119   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13120                                                    x, y,
13121                                                    tx, ty);
13122 }
13123
13124 /**
13125  * gtk_tree_view_convert_tree_to_widget_coords:
13126  * @tree_view: a #GtkTreeView
13127  * @tx: X coordinate relative to the tree
13128  * @ty: Y coordinate relative to the tree
13129  * @wx: return location for widget X coordinate
13130  * @wy: return location for widget Y coordinate
13131  *
13132  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13133  * to widget coordinates.
13134  *
13135  * Since: 2.12
13136  **/
13137 void
13138 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13139                                              gint         tx,
13140                                              gint         ty,
13141                                              gint        *wx,
13142                                              gint        *wy)
13143 {
13144   gint x, y;
13145
13146   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13147
13148   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13149                                                    tx, ty,
13150                                                    &x, &y);
13151   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13152                                                      x, y,
13153                                                      wx, wy);
13154 }
13155
13156 /**
13157  * gtk_tree_view_convert_widget_to_bin_window_coords:
13158  * @tree_view: a #GtkTreeView
13159  * @wx: X coordinate relative to the widget
13160  * @wy: Y coordinate relative to the widget
13161  * @bx: return location for bin_window X coordinate
13162  * @by: return location for bin_window Y coordinate
13163  *
13164  * Converts widget coordinates to coordinates for the bin_window
13165  * (see gtk_tree_view_get_bin_window()).
13166  *
13167  * Since: 2.12
13168  **/
13169 void
13170 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13171                                                    gint         wx,
13172                                                    gint         wy,
13173                                                    gint        *bx,
13174                                                    gint        *by)
13175 {
13176   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13177
13178   if (bx)
13179     *bx = wx + tree_view->priv->hadjustment->value;
13180   if (by)
13181     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13182 }
13183
13184 /**
13185  * gtk_tree_view_convert_bin_window_to_widget_coords:
13186  * @tree_view: a #GtkTreeView
13187  * @bx: bin_window X coordinate
13188  * @by: bin_window Y coordinate
13189  * @wx: return location for widget X coordinate
13190  * @wy: return location for widget Y coordinate
13191  *
13192  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13193  * to widget relative coordinates.
13194  *
13195  * Since: 2.12
13196  **/
13197 void
13198 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13199                                                    gint         bx,
13200                                                    gint         by,
13201                                                    gint        *wx,
13202                                                    gint        *wy)
13203 {
13204   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13205
13206   if (wx)
13207     *wx = bx - tree_view->priv->hadjustment->value;
13208   if (wy)
13209     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13210 }
13211
13212 /**
13213  * gtk_tree_view_convert_tree_to_bin_window_coords:
13214  * @tree_view: a #GtkTreeView
13215  * @tx: tree X coordinate
13216  * @ty: tree Y coordinate
13217  * @bx: return location for X coordinate relative to bin_window
13218  * @by: return location for Y coordinate relative to bin_window
13219  *
13220  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13221  * to bin_window coordinates.
13222  *
13223  * Since: 2.12
13224  **/
13225 void
13226 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13227                                                  gint         tx,
13228                                                  gint         ty,
13229                                                  gint        *bx,
13230                                                  gint        *by)
13231 {
13232   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13233
13234   if (bx)
13235     *bx = tx;
13236   if (by)
13237     *by = ty - tree_view->priv->dy;
13238 }
13239
13240 /**
13241  * gtk_tree_view_convert_bin_window_to_tree_coords:
13242  * @tree_view: a #GtkTreeView
13243  * @bx: X coordinate relative to bin_window
13244  * @by: Y coordinate relative to bin_window
13245  * @tx: return location for tree X coordinate
13246  * @ty: return location for tree Y coordinate
13247  *
13248  * Converts bin_window coordinates to coordinates for the
13249  * tree (the full scrollable area of the tree).
13250  *
13251  * Since: 2.12
13252  **/
13253 void
13254 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13255                                                  gint         bx,
13256                                                  gint         by,
13257                                                  gint        *tx,
13258                                                  gint        *ty)
13259 {
13260   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13261
13262   if (tx)
13263     *tx = bx;
13264   if (ty)
13265     *ty = by + tree_view->priv->dy;
13266 }
13267
13268
13269
13270 /**
13271  * gtk_tree_view_get_visible_range:
13272  * @tree_view: A #GtkTreeView
13273  * @start_path: (allow-none): Return location for start of region, or %NULL.
13274  * @end_path: (allow-none): Return location for end of region, or %NULL.
13275  *
13276  * Sets @start_path and @end_path to be the first and last visible path.
13277  * Note that there may be invisible paths in between.
13278  *
13279  * The paths should be freed with gtk_tree_path_free() after use.
13280  *
13281  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13282  *
13283  * Since: 2.8
13284  **/
13285 gboolean
13286 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13287                                  GtkTreePath **start_path,
13288                                  GtkTreePath **end_path)
13289 {
13290   GtkRBTree *tree;
13291   GtkRBNode *node;
13292   gboolean retval;
13293   
13294   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13295
13296   if (!tree_view->priv->tree)
13297     return FALSE;
13298
13299   retval = TRUE;
13300
13301   if (start_path)
13302     {
13303       _gtk_rbtree_find_offset (tree_view->priv->tree,
13304                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13305                                &tree, &node);
13306       if (node)
13307         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13308       else
13309         retval = FALSE;
13310     }
13311
13312   if (end_path)
13313     {
13314       gint y;
13315
13316       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13317         y = tree_view->priv->height - 1;
13318       else
13319         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13320
13321       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13322       if (node)
13323         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13324       else
13325         retval = FALSE;
13326     }
13327
13328   return retval;
13329 }
13330
13331 static void
13332 unset_reorderable (GtkTreeView *tree_view)
13333 {
13334   if (tree_view->priv->reorderable)
13335     {
13336       tree_view->priv->reorderable = FALSE;
13337       g_object_notify (G_OBJECT (tree_view), "reorderable");
13338     }
13339 }
13340
13341 /**
13342  * gtk_tree_view_enable_model_drag_source:
13343  * @tree_view: a #GtkTreeView
13344  * @start_button_mask: Mask of allowed buttons to start drag
13345  * @targets: the table of targets that the drag will support
13346  * @n_targets: the number of items in @targets
13347  * @actions: the bitmask of possible actions for a drag from this
13348  *    widget
13349  *
13350  * Turns @tree_view into a drag source for automatic DND. Calling this
13351  * method sets #GtkTreeView:reorderable to %FALSE.
13352  **/
13353 void
13354 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13355                                         GdkModifierType           start_button_mask,
13356                                         const GtkTargetEntry     *targets,
13357                                         gint                      n_targets,
13358                                         GdkDragAction             actions)
13359 {
13360   TreeViewDragInfo *di;
13361
13362   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13363
13364   gtk_drag_source_set (GTK_WIDGET (tree_view),
13365                        0,
13366                        targets,
13367                        n_targets,
13368                        actions);
13369
13370   di = ensure_info (tree_view);
13371
13372   di->start_button_mask = start_button_mask;
13373   di->source_actions = actions;
13374   di->source_set = TRUE;
13375
13376   unset_reorderable (tree_view);
13377 }
13378
13379 /**
13380  * gtk_tree_view_enable_model_drag_dest:
13381  * @tree_view: a #GtkTreeView
13382  * @targets: the table of targets that the drag will support
13383  * @n_targets: the number of items in @targets
13384  * @actions: the bitmask of possible actions for a drag from this
13385  *    widget
13386  * 
13387  * Turns @tree_view into a drop destination for automatic DND. Calling
13388  * this method sets #GtkTreeView:reorderable to %FALSE.
13389  **/
13390 void
13391 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13392                                       const GtkTargetEntry     *targets,
13393                                       gint                      n_targets,
13394                                       GdkDragAction             actions)
13395 {
13396   TreeViewDragInfo *di;
13397
13398   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13399
13400   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13401                      0,
13402                      targets,
13403                      n_targets,
13404                      actions);
13405
13406   di = ensure_info (tree_view);
13407   di->dest_set = TRUE;
13408
13409   unset_reorderable (tree_view);
13410 }
13411
13412 /**
13413  * gtk_tree_view_unset_rows_drag_source:
13414  * @tree_view: a #GtkTreeView
13415  *
13416  * Undoes the effect of
13417  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13418  * #GtkTreeView:reorderable to %FALSE.
13419  **/
13420 void
13421 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13422 {
13423   TreeViewDragInfo *di;
13424
13425   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13426
13427   di = get_info (tree_view);
13428
13429   if (di)
13430     {
13431       if (di->source_set)
13432         {
13433           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13434           di->source_set = FALSE;
13435         }
13436
13437       if (!di->dest_set && !di->source_set)
13438         remove_info (tree_view);
13439     }
13440   
13441   unset_reorderable (tree_view);
13442 }
13443
13444 /**
13445  * gtk_tree_view_unset_rows_drag_dest:
13446  * @tree_view: a #GtkTreeView
13447  *
13448  * Undoes the effect of
13449  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13450  * #GtkTreeView:reorderable to %FALSE.
13451  **/
13452 void
13453 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13454 {
13455   TreeViewDragInfo *di;
13456
13457   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13458
13459   di = get_info (tree_view);
13460
13461   if (di)
13462     {
13463       if (di->dest_set)
13464         {
13465           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13466           di->dest_set = FALSE;
13467         }
13468
13469       if (!di->dest_set && !di->source_set)
13470         remove_info (tree_view);
13471     }
13472
13473   unset_reorderable (tree_view);
13474 }
13475
13476 /**
13477  * gtk_tree_view_set_drag_dest_row:
13478  * @tree_view: a #GtkTreeView
13479  * @path: (allow-none): The path of the row to highlight, or %NULL.
13480  * @pos: Specifies whether to drop before, after or into the row
13481  * 
13482  * Sets the row that is highlighted for feedback.
13483  **/
13484 void
13485 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13486                                  GtkTreePath            *path,
13487                                  GtkTreeViewDropPosition pos)
13488 {
13489   GtkTreePath *current_dest;
13490
13491   /* Note; this function is exported to allow a custom DND
13492    * implementation, so it can't touch TreeViewDragInfo
13493    */
13494
13495   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13496
13497   current_dest = NULL;
13498
13499   if (tree_view->priv->drag_dest_row)
13500     {
13501       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13502       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13503     }
13504
13505   /* special case a drop on an empty model */
13506   tree_view->priv->empty_view_drop = 0;
13507
13508   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13509       && gtk_tree_path_get_depth (path) == 1
13510       && gtk_tree_path_get_indices (path)[0] == 0)
13511     {
13512       gint n_children;
13513
13514       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13515                                                    NULL);
13516
13517       if (!n_children)
13518         tree_view->priv->empty_view_drop = 1;
13519     }
13520
13521   tree_view->priv->drag_dest_pos = pos;
13522
13523   if (path)
13524     {
13525       tree_view->priv->drag_dest_row =
13526         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13527       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13528     }
13529   else
13530     tree_view->priv->drag_dest_row = NULL;
13531
13532   if (current_dest)
13533     {
13534       GtkRBTree *tree, *new_tree;
13535       GtkRBNode *node, *new_node;
13536
13537       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13538       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13539
13540       if (tree && node)
13541         {
13542           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13543           if (new_tree && new_node)
13544             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13545
13546           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13547           if (new_tree && new_node)
13548             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13549         }
13550       gtk_tree_path_free (current_dest);
13551     }
13552 }
13553
13554 /**
13555  * gtk_tree_view_get_drag_dest_row:
13556  * @tree_view: a #GtkTreeView
13557  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13558  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13559  * 
13560  * Gets information about the row that is highlighted for feedback.
13561  **/
13562 void
13563 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13564                                  GtkTreePath             **path,
13565                                  GtkTreeViewDropPosition  *pos)
13566 {
13567   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13568
13569   if (path)
13570     {
13571       if (tree_view->priv->drag_dest_row)
13572         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13573       else
13574         {
13575           if (tree_view->priv->empty_view_drop)
13576             *path = gtk_tree_path_new_from_indices (0, -1);
13577           else
13578             *path = NULL;
13579         }
13580     }
13581
13582   if (pos)
13583     *pos = tree_view->priv->drag_dest_pos;
13584 }
13585
13586 /**
13587  * gtk_tree_view_get_dest_row_at_pos:
13588  * @tree_view: a #GtkTreeView
13589  * @drag_x: the position to determine the destination row for
13590  * @drag_y: the position to determine the destination row for
13591  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13592  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13593  * 
13594  * Determines the destination row for a given position.  @drag_x and
13595  * @drag_y are expected to be in widget coordinates.  This function is only
13596  * meaningful if @tree_view is realized.  Therefore this function will always
13597  * return %FALSE if @tree_view is not realized or does not have a model.
13598  * 
13599  * Return value: whether there is a row at the given position, %TRUE if this
13600  * is indeed the case.
13601  **/
13602 gboolean
13603 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13604                                    gint                     drag_x,
13605                                    gint                     drag_y,
13606                                    GtkTreePath            **path,
13607                                    GtkTreeViewDropPosition *pos)
13608 {
13609   gint cell_y;
13610   gint bin_x, bin_y;
13611   gdouble offset_into_row;
13612   gdouble third;
13613   GdkRectangle cell;
13614   GtkTreeViewColumn *column = NULL;
13615   GtkTreePath *tmp_path = NULL;
13616
13617   /* Note; this function is exported to allow a custom DND
13618    * implementation, so it can't touch TreeViewDragInfo
13619    */
13620
13621   g_return_val_if_fail (tree_view != NULL, FALSE);
13622   g_return_val_if_fail (drag_x >= 0, FALSE);
13623   g_return_val_if_fail (drag_y >= 0, FALSE);
13624
13625   if (path)
13626     *path = NULL;
13627
13628   if (tree_view->priv->bin_window == NULL)
13629     return FALSE;
13630
13631   if (tree_view->priv->tree == NULL)
13632     return FALSE;
13633
13634   /* If in the top third of a row, we drop before that row; if
13635    * in the bottom third, drop after that row; if in the middle,
13636    * and the row has children, drop into the row.
13637    */
13638   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13639                                                      &bin_x, &bin_y);
13640
13641   if (!gtk_tree_view_get_path_at_pos (tree_view,
13642                                       bin_x,
13643                                       bin_y,
13644                                       &tmp_path,
13645                                       &column,
13646                                       NULL,
13647                                       &cell_y))
13648     return FALSE;
13649
13650   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13651                                      &cell);
13652
13653   offset_into_row = cell_y;
13654
13655   if (path)
13656     *path = tmp_path;
13657   else
13658     gtk_tree_path_free (tmp_path);
13659
13660   tmp_path = NULL;
13661
13662   third = cell.height / 3.0;
13663
13664   if (pos)
13665     {
13666       if (offset_into_row < third)
13667         {
13668           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13669         }
13670       else if (offset_into_row < (cell.height / 2.0))
13671         {
13672           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13673         }
13674       else if (offset_into_row < third * 2.0)
13675         {
13676           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13677         }
13678       else
13679         {
13680           *pos = GTK_TREE_VIEW_DROP_AFTER;
13681         }
13682     }
13683
13684   return TRUE;
13685 }
13686
13687
13688
13689 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13690 /**
13691  * gtk_tree_view_create_row_drag_icon:
13692  * @tree_view: a #GtkTreeView
13693  * @path: a #GtkTreePath in @tree_view
13694  *
13695  * Creates a #cairo_surface_t representation of the row at @path.  
13696  * This image is used for a drag icon.
13697  *
13698  * Return value: (transfer full): a newly-allocated surface of the drag icon.
13699  **/
13700 cairo_surface_t *
13701 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13702                                     GtkTreePath  *path)
13703 {
13704   GtkTreeIter   iter;
13705   GtkRBTree    *tree;
13706   GtkRBNode    *node;
13707   GtkStyle *style;
13708   gint cell_offset;
13709   GList *list;
13710   GdkRectangle background_area;
13711   GtkWidget *widget;
13712   gint depth;
13713   /* start drawing inside the black outline */
13714   gint x = 1, y = 1;
13715   cairo_surface_t *surface;
13716   gint bin_window_width;
13717   gboolean is_separator = FALSE;
13718   gboolean rtl;
13719   cairo_t *cr;
13720
13721   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13722   g_return_val_if_fail (path != NULL, NULL);
13723
13724   widget = GTK_WIDGET (tree_view);
13725
13726   if (!gtk_widget_get_realized (widget))
13727     return NULL;
13728
13729   depth = gtk_tree_path_get_depth (path);
13730
13731   _gtk_tree_view_find_node (tree_view,
13732                             path,
13733                             &tree,
13734                             &node);
13735
13736   if (tree == NULL)
13737     return NULL;
13738
13739   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13740                                 &iter,
13741                                 path))
13742     return NULL;
13743
13744   style = gtk_widget_get_style (widget);
13745
13746   is_separator = row_is_separator (tree_view, &iter, NULL);
13747
13748   cell_offset = x;
13749
13750   background_area.y = y;
13751   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13752
13753   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
13754
13755   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
13756                                                CAIRO_CONTENT_COLOR,
13757                                                bin_window_width + 2,
13758                                                background_area.height + 2);
13759
13760   cr = cairo_create (surface);
13761   gdk_cairo_set_source_color (cr, &style->base [gtk_widget_get_state (widget)]);
13762   cairo_paint (cr);
13763
13764   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13765
13766   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13767       list;
13768       list = (rtl ? list->prev : list->next))
13769     {
13770       GtkTreeViewColumn *column = list->data;
13771       GdkRectangle cell_area;
13772       gint vertical_separator;
13773
13774       if (!column->visible)
13775         continue;
13776
13777       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13778                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13779                                                node->children?TRUE:FALSE);
13780
13781       background_area.x = cell_offset;
13782       background_area.width = column->width;
13783
13784       gtk_widget_style_get (widget,
13785                             "vertical-separator", &vertical_separator,
13786                             NULL);
13787
13788       cell_area = background_area;
13789
13790       cell_area.y += vertical_separator / 2;
13791       cell_area.height -= vertical_separator;
13792
13793       if (gtk_tree_view_is_expander_column (tree_view, column))
13794         {
13795           if (!rtl)
13796             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13797           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13798
13799           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13800             {
13801               if (!rtl)
13802                 cell_area.x += depth * tree_view->priv->expander_size;
13803               cell_area.width -= depth * tree_view->priv->expander_size;
13804             }
13805         }
13806
13807       if (gtk_tree_view_column_cell_is_visible (column))
13808         {
13809           if (is_separator)
13810             gtk_paint_hline (style,
13811                                    cr,
13812                                    GTK_STATE_NORMAL,
13813                                    widget,
13814                                    NULL,
13815                                    cell_area.x,
13816                                    cell_area.x + cell_area.width,
13817                                    cell_area.y + cell_area.height / 2);
13818           else
13819             _gtk_tree_view_column_cell_render (column,
13820                                                cr,
13821                                                &background_area,
13822                                                &cell_area,
13823                                                0);
13824         }
13825       cell_offset += column->width;
13826     }
13827
13828   cairo_set_source_rgb (cr, 0, 0, 0);
13829   cairo_rectangle (cr, 
13830                    0.5, 0.5, 
13831                    bin_window_width + 1,
13832                    background_area.height + 1);
13833   cairo_set_line_width (cr, 1.0);
13834   cairo_stroke (cr);
13835
13836   cairo_destroy (cr);
13837
13838   cairo_surface_set_device_offset (surface, 2, 2);
13839
13840   return surface;
13841 }
13842
13843
13844 /**
13845  * gtk_tree_view_set_destroy_count_func:
13846  * @tree_view: A #GtkTreeView
13847  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
13848  * @data: (allow-none): User data to be passed to @func, or %NULL
13849  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
13850  *
13851  * This function should almost never be used.  It is meant for private use by
13852  * ATK for determining the number of visible children that are removed when the
13853  * user collapses a row, or a row is deleted.
13854  **/
13855 void
13856 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13857                                       GtkTreeDestroyCountFunc  func,
13858                                       gpointer                 data,
13859                                       GDestroyNotify           destroy)
13860 {
13861   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13862
13863   if (tree_view->priv->destroy_count_destroy)
13864     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13865
13866   tree_view->priv->destroy_count_func = func;
13867   tree_view->priv->destroy_count_data = data;
13868   tree_view->priv->destroy_count_destroy = destroy;
13869 }
13870
13871
13872 /*
13873  * Interactive search
13874  */
13875
13876 /**
13877  * gtk_tree_view_set_enable_search:
13878  * @tree_view: A #GtkTreeView
13879  * @enable_search: %TRUE, if the user can search interactively
13880  *
13881  * If @enable_search is set, then the user can type in text to search through
13882  * the tree interactively (this is sometimes called "typeahead find").
13883  * 
13884  * Note that even if this is %FALSE, the user can still initiate a search 
13885  * using the "start-interactive-search" key binding.
13886  */
13887 void
13888 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13889                                  gboolean     enable_search)
13890 {
13891   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13892
13893   enable_search = !!enable_search;
13894   
13895   if (tree_view->priv->enable_search != enable_search)
13896     {
13897        tree_view->priv->enable_search = enable_search;
13898        g_object_notify (G_OBJECT (tree_view), "enable-search");
13899     }
13900 }
13901
13902 /**
13903  * gtk_tree_view_get_enable_search:
13904  * @tree_view: A #GtkTreeView
13905  *
13906  * Returns whether or not the tree allows to start interactive searching 
13907  * by typing in text.
13908  *
13909  * Return value: whether or not to let the user search interactively
13910  */
13911 gboolean
13912 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13913 {
13914   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13915
13916   return tree_view->priv->enable_search;
13917 }
13918
13919
13920 /**
13921  * gtk_tree_view_get_search_column:
13922  * @tree_view: A #GtkTreeView
13923  *
13924  * Gets the column searched on by the interactive search code.
13925  *
13926  * Return value: the column the interactive search code searches in.
13927  */
13928 gint
13929 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13930 {
13931   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13932
13933   return (tree_view->priv->search_column);
13934 }
13935
13936 /**
13937  * gtk_tree_view_set_search_column:
13938  * @tree_view: A #GtkTreeView
13939  * @column: the column of the model to search in, or -1 to disable searching
13940  *
13941  * Sets @column as the column where the interactive search code should
13942  * search in for the current model. 
13943  * 
13944  * If the search column is set, users can use the "start-interactive-search"
13945  * key binding to bring up search popup. The enable-search property controls
13946  * whether simply typing text will also start an interactive search.
13947  *
13948  * Note that @column refers to a column of the current model. The search 
13949  * column is reset to -1 when the model is changed.
13950  */
13951 void
13952 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13953                                  gint         column)
13954 {
13955   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13956   g_return_if_fail (column >= -1);
13957
13958   if (tree_view->priv->search_column == column)
13959     return;
13960
13961   tree_view->priv->search_column = column;
13962   g_object_notify (G_OBJECT (tree_view), "search-column");
13963 }
13964
13965 /**
13966  * gtk_tree_view_get_search_equal_func:
13967  * @tree_view: A #GtkTreeView
13968  *
13969  * Returns the compare function currently in use.
13970  *
13971  * Return value: the currently used compare function for the search code.
13972  */
13973
13974 GtkTreeViewSearchEqualFunc
13975 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
13976 {
13977   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13978
13979   return tree_view->priv->search_equal_func;
13980 }
13981
13982 /**
13983  * gtk_tree_view_set_search_equal_func:
13984  * @tree_view: A #GtkTreeView
13985  * @search_equal_func: the compare function to use during the search
13986  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
13987  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
13988  *
13989  * Sets the compare function for the interactive search capabilities; note
13990  * that somewhat like strcmp() returning 0 for equality
13991  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
13992  **/
13993 void
13994 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
13995                                      GtkTreeViewSearchEqualFunc  search_equal_func,
13996                                      gpointer                    search_user_data,
13997                                      GDestroyNotify              search_destroy)
13998 {
13999   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14000   g_return_if_fail (search_equal_func != NULL);
14001
14002   if (tree_view->priv->search_destroy)
14003     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14004
14005   tree_view->priv->search_equal_func = search_equal_func;
14006   tree_view->priv->search_user_data = search_user_data;
14007   tree_view->priv->search_destroy = search_destroy;
14008   if (tree_view->priv->search_equal_func == NULL)
14009     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14010 }
14011
14012 /**
14013  * gtk_tree_view_get_search_entry:
14014  * @tree_view: A #GtkTreeView
14015  *
14016  * Returns the #GtkEntry which is currently in use as interactive search
14017  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14018  * will be returned.
14019  *
14020  * Return value: (transfer none): the entry currently in use as search entry.
14021  *
14022  * Since: 2.10
14023  */
14024 GtkEntry *
14025 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14026 {
14027   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14028
14029   if (tree_view->priv->search_custom_entry_set)
14030     return GTK_ENTRY (tree_view->priv->search_entry);
14031
14032   return NULL;
14033 }
14034
14035 /**
14036  * gtk_tree_view_set_search_entry:
14037  * @tree_view: A #GtkTreeView
14038  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14039  *
14040  * Sets the entry which the interactive search code will use for this
14041  * @tree_view.  This is useful when you want to provide a search entry
14042  * in our interface at all time at a fixed position.  Passing %NULL for
14043  * @entry will make the interactive search code use the built-in popup
14044  * entry again.
14045  *
14046  * Since: 2.10
14047  */
14048 void
14049 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14050                                 GtkEntry    *entry)
14051 {
14052   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14053   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14054
14055   if (tree_view->priv->search_custom_entry_set)
14056     {
14057       if (tree_view->priv->search_entry_changed_id)
14058         {
14059           g_signal_handler_disconnect (tree_view->priv->search_entry,
14060                                        tree_view->priv->search_entry_changed_id);
14061           tree_view->priv->search_entry_changed_id = 0;
14062         }
14063       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14064                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14065                                             tree_view);
14066
14067       g_object_unref (tree_view->priv->search_entry);
14068     }
14069   else if (tree_view->priv->search_window)
14070     {
14071       gtk_widget_destroy (tree_view->priv->search_window);
14072
14073       tree_view->priv->search_window = NULL;
14074     }
14075
14076   if (entry)
14077     {
14078       tree_view->priv->search_entry = g_object_ref (entry);
14079       tree_view->priv->search_custom_entry_set = TRUE;
14080
14081       if (tree_view->priv->search_entry_changed_id == 0)
14082         {
14083           tree_view->priv->search_entry_changed_id =
14084             g_signal_connect (tree_view->priv->search_entry, "changed",
14085                               G_CALLBACK (gtk_tree_view_search_init),
14086                               tree_view);
14087         }
14088       
14089         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14090                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14091                           tree_view);
14092
14093         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14094     }
14095   else
14096     {
14097       tree_view->priv->search_entry = NULL;
14098       tree_view->priv->search_custom_entry_set = FALSE;
14099     }
14100 }
14101
14102 /**
14103  * gtk_tree_view_set_search_position_func:
14104  * @tree_view: A #GtkTreeView
14105  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14106  *    to use the default search position function
14107  * @data: (allow-none): user data to pass to @func, or %NULL
14108  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14109  *
14110  * Sets the function to use when positioning the search dialog.
14111  *
14112  * Since: 2.10
14113  **/
14114 void
14115 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14116                                         GtkTreeViewSearchPositionFunc  func,
14117                                         gpointer                       user_data,
14118                                         GDestroyNotify                 destroy)
14119 {
14120   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14121
14122   if (tree_view->priv->search_position_destroy)
14123     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14124
14125   tree_view->priv->search_position_func = func;
14126   tree_view->priv->search_position_user_data = user_data;
14127   tree_view->priv->search_position_destroy = destroy;
14128   if (tree_view->priv->search_position_func == NULL)
14129     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14130 }
14131
14132 /**
14133  * gtk_tree_view_get_search_position_func:
14134  * @tree_view: A #GtkTreeView
14135  *
14136  * Returns the positioning function currently in use.
14137  *
14138  * Return value: the currently used function for positioning the search dialog.
14139  *
14140  * Since: 2.10
14141  */
14142 GtkTreeViewSearchPositionFunc
14143 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14144 {
14145   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14146
14147   return tree_view->priv->search_position_func;
14148 }
14149
14150
14151 static void
14152 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14153                                   GtkTreeView *tree_view,
14154                                   GdkDevice   *device)
14155 {
14156   if (tree_view->priv->disable_popdown)
14157     return;
14158
14159   if (tree_view->priv->search_entry_changed_id)
14160     {
14161       g_signal_handler_disconnect (tree_view->priv->search_entry,
14162                                    tree_view->priv->search_entry_changed_id);
14163       tree_view->priv->search_entry_changed_id = 0;
14164     }
14165   if (tree_view->priv->typeselect_flush_timeout)
14166     {
14167       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14168       tree_view->priv->typeselect_flush_timeout = 0;
14169     }
14170         
14171   if (gtk_widget_get_visible (search_dialog))
14172     {
14173       /* send focus-in event */
14174       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14175       gtk_widget_hide (search_dialog);
14176       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14177       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14178     }
14179 }
14180
14181 static void
14182 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14183                                     GtkWidget   *search_dialog,
14184                                     gpointer     user_data)
14185 {
14186   gint x, y;
14187   gint tree_x, tree_y;
14188   gint tree_width, tree_height;
14189   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14190   GdkScreen *screen = gdk_window_get_screen (tree_window);
14191   GtkRequisition requisition;
14192   gint monitor_num;
14193   GdkRectangle monitor;
14194
14195   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14196   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14197
14198   gtk_widget_realize (search_dialog);
14199
14200   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14201   tree_width = gdk_window_get_width (tree_window);
14202   tree_height = gdk_window_get_height (tree_window);
14203   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14204
14205   if (tree_x + tree_width > gdk_screen_get_width (screen))
14206     x = gdk_screen_get_width (screen) - requisition.width;
14207   else if (tree_x + tree_width - requisition.width < 0)
14208     x = 0;
14209   else
14210     x = tree_x + tree_width - requisition.width;
14211
14212   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14213     y = gdk_screen_get_height (screen) - requisition.height;
14214   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14215     y = 0;
14216   else
14217     y = tree_y + tree_height;
14218
14219   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14220 }
14221
14222 static void
14223 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14224                                       GtkMenu  *menu,
14225                                       gpointer  data)
14226 {
14227   GtkTreeView *tree_view = (GtkTreeView *)data;
14228
14229   tree_view->priv->disable_popdown = 1;
14230   g_signal_connect (menu, "hide",
14231                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14232 }
14233
14234 /* Because we're visible but offscreen, we just set a flag in the preedit
14235  * callback.
14236  */
14237 static void
14238 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14239                                       GtkTreeView  *tree_view)
14240 {
14241   tree_view->priv->imcontext_changed = 1;
14242   if (tree_view->priv->typeselect_flush_timeout)
14243     {
14244       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14245       tree_view->priv->typeselect_flush_timeout =
14246         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14247                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14248                        tree_view);
14249     }
14250
14251 }
14252
14253 static void
14254 gtk_tree_view_search_activate (GtkEntry    *entry,
14255                                GtkTreeView *tree_view)
14256 {
14257   GtkTreePath *path;
14258   GtkRBNode *node;
14259   GtkRBTree *tree;
14260
14261   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14262                                     tree_view,
14263                                     gtk_get_current_event_device ());
14264
14265   /* If we have a row selected and it's the cursor row, we activate
14266    * the row XXX */
14267   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14268     {
14269       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14270       
14271       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14272       
14273       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14274         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14275       
14276       gtk_tree_path_free (path);
14277     }
14278 }
14279
14280 static gboolean
14281 gtk_tree_view_real_search_enable_popdown (gpointer data)
14282 {
14283   GtkTreeView *tree_view = (GtkTreeView *)data;
14284
14285   tree_view->priv->disable_popdown = 0;
14286
14287   return FALSE;
14288 }
14289
14290 static void
14291 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14292                                      gpointer   data)
14293 {
14294   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14295 }
14296
14297 static gboolean
14298 gtk_tree_view_search_delete_event (GtkWidget *widget,
14299                                    GdkEventAny *event,
14300                                    GtkTreeView *tree_view)
14301 {
14302   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14303
14304   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14305
14306   return TRUE;
14307 }
14308
14309 static gboolean
14310 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14311                                          GdkEventButton *event,
14312                                          GtkTreeView *tree_view)
14313 {
14314   GdkDevice *keyb_device;
14315
14316   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14317
14318   keyb_device = gdk_device_get_associated_device (event->device);
14319   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14320
14321   if (event->window == tree_view->priv->bin_window)
14322     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14323
14324   return TRUE;
14325 }
14326
14327 static gboolean
14328 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14329                                    GdkEventScroll *event,
14330                                    GtkTreeView *tree_view)
14331 {
14332   gboolean retval = FALSE;
14333
14334   if (event->direction == GDK_SCROLL_UP)
14335     {
14336       gtk_tree_view_search_move (widget, tree_view, TRUE);
14337       retval = TRUE;
14338     }
14339   else if (event->direction == GDK_SCROLL_DOWN)
14340     {
14341       gtk_tree_view_search_move (widget, tree_view, FALSE);
14342       retval = TRUE;
14343     }
14344
14345   /* renew the flush timeout */
14346   if (retval && tree_view->priv->typeselect_flush_timeout
14347       && !tree_view->priv->search_custom_entry_set)
14348     {
14349       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14350       tree_view->priv->typeselect_flush_timeout =
14351         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14352                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14353                        tree_view);
14354     }
14355
14356   return retval;
14357 }
14358
14359 static gboolean
14360 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14361                                       GdkEventKey *event,
14362                                       GtkTreeView *tree_view)
14363 {
14364   gboolean retval = FALSE;
14365
14366   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14367   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14368
14369   /* close window and cancel the search */
14370   if (!tree_view->priv->search_custom_entry_set
14371       && (event->keyval == GDK_KEY_Escape ||
14372           event->keyval == GDK_KEY_Tab ||
14373             event->keyval == GDK_KEY_KP_Tab ||
14374             event->keyval == GDK_KEY_ISO_Left_Tab))
14375     {
14376       gtk_tree_view_search_dialog_hide (widget, tree_view,
14377                                         gdk_event_get_device ((GdkEvent *) event));
14378       return TRUE;
14379     }
14380
14381   /* select previous matching iter */
14382   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
14383     {
14384       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14385         gtk_widget_error_bell (widget);
14386
14387       retval = TRUE;
14388     }
14389
14390   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14391       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14392     {
14393       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14394         gtk_widget_error_bell (widget);
14395
14396       retval = TRUE;
14397     }
14398
14399   /* select next matching iter */
14400   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
14401     {
14402       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14403         gtk_widget_error_bell (widget);
14404
14405       retval = TRUE;
14406     }
14407
14408   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14409       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
14410     {
14411       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14412         gtk_widget_error_bell (widget);
14413
14414       retval = TRUE;
14415     }
14416
14417   /* renew the flush timeout */
14418   if (retval && tree_view->priv->typeselect_flush_timeout
14419       && !tree_view->priv->search_custom_entry_set)
14420     {
14421       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14422       tree_view->priv->typeselect_flush_timeout =
14423         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14424                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14425                        tree_view);
14426     }
14427
14428   return retval;
14429 }
14430
14431 /*  this function returns FALSE if there is a search string but
14432  *  nothing was found, and TRUE otherwise.
14433  */
14434 static gboolean
14435 gtk_tree_view_search_move (GtkWidget   *window,
14436                            GtkTreeView *tree_view,
14437                            gboolean     up)
14438 {
14439   gboolean ret;
14440   gint len;
14441   gint count = 0;
14442   const gchar *text;
14443   GtkTreeIter iter;
14444   GtkTreeModel *model;
14445   GtkTreeSelection *selection;
14446
14447   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14448
14449   g_return_val_if_fail (text != NULL, FALSE);
14450
14451   len = strlen (text);
14452
14453   if (up && tree_view->priv->selected_iter == 1)
14454     return strlen (text) < 1;
14455
14456   len = strlen (text);
14457
14458   if (len < 1)
14459     return TRUE;
14460
14461   model = gtk_tree_view_get_model (tree_view);
14462   selection = gtk_tree_view_get_selection (tree_view);
14463
14464   /* search */
14465   gtk_tree_selection_unselect_all (selection);
14466   if (!gtk_tree_model_get_iter_first (model, &iter))
14467     return TRUE;
14468
14469   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14470                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14471
14472   if (ret)
14473     {
14474       /* found */
14475       tree_view->priv->selected_iter += up?(-1):(1);
14476       return TRUE;
14477     }
14478   else
14479     {
14480       /* return to old iter */
14481       count = 0;
14482       gtk_tree_model_get_iter_first (model, &iter);
14483       gtk_tree_view_search_iter (model, selection,
14484                                  &iter, text,
14485                                  &count, tree_view->priv->selected_iter);
14486       return FALSE;
14487     }
14488 }
14489
14490 static gboolean
14491 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14492                                  gint          column,
14493                                  const gchar  *key,
14494                                  GtkTreeIter  *iter,
14495                                  gpointer      search_data)
14496 {
14497   gboolean retval = TRUE;
14498   const gchar *str;
14499   gchar *normalized_string;
14500   gchar *normalized_key;
14501   gchar *case_normalized_string = NULL;
14502   gchar *case_normalized_key = NULL;
14503   GValue value = {0,};
14504   GValue transformed = {0,};
14505
14506   gtk_tree_model_get_value (model, iter, column, &value);
14507
14508   g_value_init (&transformed, G_TYPE_STRING);
14509
14510   if (!g_value_transform (&value, &transformed))
14511     {
14512       g_value_unset (&value);
14513       return TRUE;
14514     }
14515
14516   g_value_unset (&value);
14517
14518   str = g_value_get_string (&transformed);
14519   if (!str)
14520     {
14521       g_value_unset (&transformed);
14522       return TRUE;
14523     }
14524
14525   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14526   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14527
14528   if (normalized_string && normalized_key)
14529     {
14530       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14531       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14532
14533       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14534         retval = FALSE;
14535     }
14536
14537   g_value_unset (&transformed);
14538   g_free (normalized_key);
14539   g_free (normalized_string);
14540   g_free (case_normalized_key);
14541   g_free (case_normalized_string);
14542
14543   return retval;
14544 }
14545
14546 static gboolean
14547 gtk_tree_view_search_iter (GtkTreeModel     *model,
14548                            GtkTreeSelection *selection,
14549                            GtkTreeIter      *iter,
14550                            const gchar      *text,
14551                            gint             *count,
14552                            gint              n)
14553 {
14554   GtkRBTree *tree = NULL;
14555   GtkRBNode *node = NULL;
14556   GtkTreePath *path;
14557
14558   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14559
14560   path = gtk_tree_model_get_path (model, iter);
14561   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14562
14563   do
14564     {
14565       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14566         {
14567           (*count)++;
14568           if (*count == n)
14569             {
14570               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14571                                             TRUE, 0.5, 0.0);
14572               gtk_tree_selection_select_iter (selection, iter);
14573               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14574
14575               if (path)
14576                 gtk_tree_path_free (path);
14577
14578               return TRUE;
14579             }
14580         }
14581
14582       if (node->children)
14583         {
14584           gboolean has_child;
14585           GtkTreeIter tmp;
14586
14587           tree = node->children;
14588           node = tree->root;
14589
14590           while (node->left != tree->nil)
14591             node = node->left;
14592
14593           tmp = *iter;
14594           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14595           gtk_tree_path_down (path);
14596
14597           /* sanity check */
14598           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14599         }
14600       else
14601         {
14602           gboolean done = FALSE;
14603
14604           do
14605             {
14606               node = _gtk_rbtree_next (tree, node);
14607
14608               if (node)
14609                 {
14610                   gboolean has_next;
14611
14612                   has_next = gtk_tree_model_iter_next (model, iter);
14613
14614                   done = TRUE;
14615                   gtk_tree_path_next (path);
14616
14617                   /* sanity check */
14618                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14619                 }
14620               else
14621                 {
14622                   gboolean has_parent;
14623                   GtkTreeIter tmp_iter = *iter;
14624
14625                   node = tree->parent_node;
14626                   tree = tree->parent_tree;
14627
14628                   if (!tree)
14629                     {
14630                       if (path)
14631                         gtk_tree_path_free (path);
14632
14633                       /* we've run out of tree, done with this func */
14634                       return FALSE;
14635                     }
14636
14637                   has_parent = gtk_tree_model_iter_parent (model,
14638                                                            iter,
14639                                                            &tmp_iter);
14640                   gtk_tree_path_up (path);
14641
14642                   /* sanity check */
14643                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14644                 }
14645             }
14646           while (!done);
14647         }
14648     }
14649   while (1);
14650
14651   return FALSE;
14652 }
14653
14654 static void
14655 gtk_tree_view_search_init (GtkWidget   *entry,
14656                            GtkTreeView *tree_view)
14657 {
14658   gint ret;
14659   gint count = 0;
14660   const gchar *text;
14661   GtkTreeIter iter;
14662   GtkTreeModel *model;
14663   GtkTreeSelection *selection;
14664
14665   g_return_if_fail (GTK_IS_ENTRY (entry));
14666   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14667
14668   text = gtk_entry_get_text (GTK_ENTRY (entry));
14669
14670   model = gtk_tree_view_get_model (tree_view);
14671   selection = gtk_tree_view_get_selection (tree_view);
14672
14673   /* search */
14674   gtk_tree_selection_unselect_all (selection);
14675   if (tree_view->priv->typeselect_flush_timeout
14676       && !tree_view->priv->search_custom_entry_set)
14677     {
14678       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14679       tree_view->priv->typeselect_flush_timeout =
14680         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14681                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14682                        tree_view);
14683     }
14684
14685   if (*text == '\0')
14686     return;
14687
14688   if (!gtk_tree_model_get_iter_first (model, &iter))
14689     return;
14690
14691   ret = gtk_tree_view_search_iter (model, selection,
14692                                    &iter, text,
14693                                    &count, 1);
14694
14695   if (ret)
14696     tree_view->priv->selected_iter = 1;
14697 }
14698
14699 static void
14700 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14701                              GtkTreeView     *tree_view)
14702 {
14703   if (tree_view->priv->edited_column == NULL)
14704     return;
14705
14706   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14707   tree_view->priv->edited_column = NULL;
14708
14709   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
14710     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14711
14712   g_signal_handlers_disconnect_by_func (cell_editable,
14713                                         gtk_tree_view_remove_widget,
14714                                         tree_view);
14715
14716   gtk_container_remove (GTK_CONTAINER (tree_view),
14717                         GTK_WIDGET (cell_editable));  
14718
14719   /* FIXME should only redraw a single node */
14720   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14721 }
14722
14723 static gboolean
14724 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14725                              GtkTreePath *cursor_path)
14726 {
14727   GtkTreeIter iter;
14728   GdkRectangle background_area;
14729   GdkRectangle cell_area;
14730   GtkCellEditable *editable_widget = NULL;
14731   gchar *path_string;
14732   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14733   gint retval = FALSE;
14734   GtkRBTree *cursor_tree;
14735   GtkRBNode *cursor_node;
14736
14737   g_assert (tree_view->priv->focus_column);
14738
14739   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
14740     return FALSE;
14741
14742   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14743       cursor_node == NULL)
14744     return FALSE;
14745
14746   path_string = gtk_tree_path_to_string (cursor_path);
14747   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14748
14749   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14750
14751   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14752                                            tree_view->priv->model,
14753                                            &iter,
14754                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14755                                            cursor_node->children?TRUE:FALSE);
14756   gtk_tree_view_get_background_area (tree_view,
14757                                      cursor_path,
14758                                      tree_view->priv->focus_column,
14759                                      &background_area);
14760   gtk_tree_view_get_cell_area (tree_view,
14761                                cursor_path,
14762                                tree_view->priv->focus_column,
14763                                &cell_area);
14764
14765   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14766                                         &editable_widget,
14767                                         NULL,
14768                                         path_string,
14769                                         &background_area,
14770                                         &cell_area,
14771                                         flags))
14772     {
14773       retval = TRUE;
14774       if (editable_widget != NULL)
14775         {
14776           gint left, right;
14777           GdkRectangle area;
14778           GtkCellRenderer *cell;
14779
14780           area = cell_area;
14781           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14782
14783           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14784
14785           area.x += left;
14786           area.width -= right + left;
14787
14788           gtk_tree_view_real_start_editing (tree_view,
14789                                             tree_view->priv->focus_column,
14790                                             cursor_path,
14791                                             editable_widget,
14792                                             &area,
14793                                             NULL,
14794                                             flags);
14795         }
14796
14797     }
14798   g_free (path_string);
14799   return retval;
14800 }
14801
14802 static void
14803 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14804                                   GtkTreeViewColumn *column,
14805                                   GtkTreePath       *path,
14806                                   GtkCellEditable   *cell_editable,
14807                                   GdkRectangle      *cell_area,
14808                                   GdkEvent          *event,
14809                                   guint              flags)
14810 {
14811   gint pre_val = tree_view->priv->vadjustment->value;
14812   GtkRequisition requisition;
14813
14814   tree_view->priv->edited_column = column;
14815   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14816
14817   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14818   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14819
14820   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
14821                                  &requisition, NULL);
14822
14823   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14824
14825   if (requisition.height < cell_area->height)
14826     {
14827       gint diff = cell_area->height - requisition.height;
14828       gtk_tree_view_put (tree_view,
14829                          GTK_WIDGET (cell_editable),
14830                          cell_area->x, cell_area->y + diff/2,
14831                          cell_area->width, requisition.height);
14832     }
14833   else
14834     {
14835       gtk_tree_view_put (tree_view,
14836                          GTK_WIDGET (cell_editable),
14837                          cell_area->x, cell_area->y,
14838                          cell_area->width, cell_area->height);
14839     }
14840
14841   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14842                                    (GdkEvent *)event);
14843
14844   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14845   g_signal_connect (cell_editable, "remove-widget",
14846                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14847 }
14848
14849 static void
14850 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14851                             gboolean     cancel_editing)
14852 {
14853   GtkTreeViewColumn *column;
14854   GtkCellRenderer *cell;
14855
14856   if (tree_view->priv->edited_column == NULL)
14857     return;
14858
14859   /*
14860    * This is very evil. We need to do this, because
14861    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14862    * later on. If gtk_tree_view_row_changed notices
14863    * tree_view->priv->edited_column != NULL, it'll call
14864    * gtk_tree_view_stop_editing again. Bad things will happen then.
14865    *
14866    * Please read that again if you intend to modify anything here.
14867    */
14868
14869   column = tree_view->priv->edited_column;
14870   tree_view->priv->edited_column = NULL;
14871
14872   cell = _gtk_tree_view_column_get_edited_cell (column);
14873   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14874
14875   if (!cancel_editing)
14876     gtk_cell_editable_editing_done (column->editable_widget);
14877
14878   tree_view->priv->edited_column = column;
14879
14880   gtk_cell_editable_remove_widget (column->editable_widget);
14881 }
14882
14883
14884 /**
14885  * gtk_tree_view_set_hover_selection:
14886  * @tree_view: a #GtkTreeView
14887  * @hover: %TRUE to enable hover selection mode
14888  *
14889  * Enables of disables the hover selection mode of @tree_view.
14890  * Hover selection makes the selected row follow the pointer.
14891  * Currently, this works only for the selection modes 
14892  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14893  * 
14894  * Since: 2.6
14895  **/
14896 void     
14897 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14898                                    gboolean     hover)
14899 {
14900   hover = hover != FALSE;
14901
14902   if (hover != tree_view->priv->hover_selection)
14903     {
14904       tree_view->priv->hover_selection = hover;
14905
14906       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14907     }
14908 }
14909
14910 /**
14911  * gtk_tree_view_get_hover_selection:
14912  * @tree_view: a #GtkTreeView
14913  * 
14914  * Returns whether hover selection mode is turned on for @tree_view.
14915  * 
14916  * Return value: %TRUE if @tree_view is in hover selection mode
14917  *
14918  * Since: 2.6 
14919  **/
14920 gboolean 
14921 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14922 {
14923   return tree_view->priv->hover_selection;
14924 }
14925
14926 /**
14927  * gtk_tree_view_set_hover_expand:
14928  * @tree_view: a #GtkTreeView
14929  * @expand: %TRUE to enable hover selection mode
14930  *
14931  * Enables of disables the hover expansion mode of @tree_view.
14932  * Hover expansion makes rows expand or collapse if the pointer 
14933  * moves over them.
14934  * 
14935  * Since: 2.6
14936  **/
14937 void     
14938 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14939                                 gboolean     expand)
14940 {
14941   expand = expand != FALSE;
14942
14943   if (expand != tree_view->priv->hover_expand)
14944     {
14945       tree_view->priv->hover_expand = expand;
14946
14947       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14948     }
14949 }
14950
14951 /**
14952  * gtk_tree_view_get_hover_expand:
14953  * @tree_view: a #GtkTreeView
14954  * 
14955  * Returns whether hover expansion mode is turned on for @tree_view.
14956  * 
14957  * Return value: %TRUE if @tree_view is in hover expansion mode
14958  *
14959  * Since: 2.6 
14960  **/
14961 gboolean 
14962 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14963 {
14964   return tree_view->priv->hover_expand;
14965 }
14966
14967 /**
14968  * gtk_tree_view_set_rubber_banding:
14969  * @tree_view: a #GtkTreeView
14970  * @enable: %TRUE to enable rubber banding
14971  *
14972  * Enables or disables rubber banding in @tree_view.  If the selection mode
14973  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14974  * multiple rows by dragging the mouse.
14975  * 
14976  * Since: 2.10
14977  **/
14978 void
14979 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
14980                                   gboolean     enable)
14981 {
14982   enable = enable != FALSE;
14983
14984   if (enable != tree_view->priv->rubber_banding_enable)
14985     {
14986       tree_view->priv->rubber_banding_enable = enable;
14987
14988       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
14989     }
14990 }
14991
14992 /**
14993  * gtk_tree_view_get_rubber_banding:
14994  * @tree_view: a #GtkTreeView
14995  * 
14996  * Returns whether rubber banding is turned on for @tree_view.  If the
14997  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
14998  * user to select multiple rows by dragging the mouse.
14999  * 
15000  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15001  *
15002  * Since: 2.10
15003  **/
15004 gboolean
15005 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15006 {
15007   return tree_view->priv->rubber_banding_enable;
15008 }
15009
15010 /**
15011  * gtk_tree_view_is_rubber_banding_active:
15012  * @tree_view: a #GtkTreeView
15013  * 
15014  * Returns whether a rubber banding operation is currently being done
15015  * in @tree_view.
15016  *
15017  * Return value: %TRUE if a rubber banding operation is currently being
15018  * done in @tree_view.
15019  *
15020  * Since: 2.12
15021  **/
15022 gboolean
15023 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15024 {
15025   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15026
15027   if (tree_view->priv->rubber_banding_enable
15028       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15029     return TRUE;
15030
15031   return FALSE;
15032 }
15033
15034 /**
15035  * gtk_tree_view_get_row_separator_func:
15036  * @tree_view: a #GtkTreeView
15037  * 
15038  * Returns the current row separator function.
15039  * 
15040  * Return value: the current row separator function.
15041  *
15042  * Since: 2.6
15043  **/
15044 GtkTreeViewRowSeparatorFunc 
15045 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15046 {
15047   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15048
15049   return tree_view->priv->row_separator_func;
15050 }
15051
15052 /**
15053  * gtk_tree_view_set_row_separator_func:
15054  * @tree_view: a #GtkTreeView
15055  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15056  * @data: (allow-none): user data to pass to @func, or %NULL
15057  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15058  * 
15059  * Sets the row separator function, which is used to determine
15060  * whether a row should be drawn as a separator. If the row separator
15061  * function is %NULL, no separators are drawn. This is the default value.
15062  *
15063  * Since: 2.6
15064  **/
15065 void
15066 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15067                                       GtkTreeViewRowSeparatorFunc  func,
15068                                       gpointer                     data,
15069                                       GDestroyNotify               destroy)
15070 {
15071   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15072
15073   if (tree_view->priv->row_separator_destroy)
15074     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15075
15076   tree_view->priv->row_separator_func = func;
15077   tree_view->priv->row_separator_data = data;
15078   tree_view->priv->row_separator_destroy = destroy;
15079
15080   /* Have the tree recalculate heights */
15081   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15082   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15083 }
15084
15085   
15086 static void
15087 gtk_tree_view_grab_notify (GtkWidget *widget,
15088                            gboolean   was_grabbed)
15089 {
15090   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15091
15092   tree_view->priv->in_grab = !was_grabbed;
15093
15094   if (!was_grabbed)
15095     {
15096       tree_view->priv->pressed_button = -1;
15097
15098       if (tree_view->priv->rubber_band_status)
15099         gtk_tree_view_stop_rubber_band (tree_view);
15100     }
15101 }
15102
15103 static void
15104 gtk_tree_view_state_changed (GtkWidget      *widget,
15105                              GtkStateType    previous_state)
15106 {
15107   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15108
15109   if (gtk_widget_get_realized (widget))
15110     {
15111       gdk_window_set_background (tree_view->priv->bin_window,
15112                                  &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
15113     }
15114
15115   gtk_widget_queue_draw (widget);
15116 }
15117
15118 /**
15119  * gtk_tree_view_get_grid_lines:
15120  * @tree_view: a #GtkTreeView
15121  *
15122  * Returns which grid lines are enabled in @tree_view.
15123  *
15124  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15125  * are enabled.
15126  *
15127  * Since: 2.10
15128  */
15129 GtkTreeViewGridLines
15130 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15131 {
15132   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15133
15134   return tree_view->priv->grid_lines;
15135 }
15136
15137 /**
15138  * gtk_tree_view_set_grid_lines:
15139  * @tree_view: a #GtkTreeView
15140  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15141  * enable.
15142  *
15143  * Sets which grid lines to draw in @tree_view.
15144  *
15145  * Since: 2.10
15146  */
15147 void
15148 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15149                               GtkTreeViewGridLines   grid_lines)
15150 {
15151   GtkTreeViewPrivate *priv;
15152   GtkWidget *widget;
15153   GtkTreeViewGridLines old_grid_lines;
15154
15155   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15156
15157   priv = tree_view->priv;
15158   widget = GTK_WIDGET (tree_view);
15159
15160   old_grid_lines = priv->grid_lines;
15161   priv->grid_lines = grid_lines;
15162   
15163   if (gtk_widget_get_realized (widget))
15164     {
15165       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15166           priv->grid_line_width)
15167         {
15168           priv->grid_line_width = 0;
15169         }
15170       
15171       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15172           !priv->grid_line_width)
15173         {
15174           gint8 *dash_list;
15175
15176           gtk_widget_style_get (widget,
15177                                 "grid-line-width", &priv->grid_line_width,
15178                                 "grid-line-pattern", (gchar *)&dash_list,
15179                                 NULL);
15180       
15181           if (dash_list)
15182             {
15183               priv->grid_line_dashes[0] = dash_list[0];
15184               if (dash_list[0])
15185                 priv->grid_line_dashes[1] = dash_list[1];
15186               
15187               g_free (dash_list);
15188             }
15189           else
15190             {
15191               priv->grid_line_dashes[0] = 1;
15192               priv->grid_line_dashes[1] = 1;
15193             }
15194         }      
15195     }
15196
15197   if (old_grid_lines != grid_lines)
15198     {
15199       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15200       
15201       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15202     }
15203 }
15204
15205 /**
15206  * gtk_tree_view_get_enable_tree_lines:
15207  * @tree_view: a #GtkTreeView.
15208  *
15209  * Returns whether or not tree lines are drawn in @tree_view.
15210  *
15211  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15212  * otherwise.
15213  *
15214  * Since: 2.10
15215  */
15216 gboolean
15217 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15218 {
15219   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15220
15221   return tree_view->priv->tree_lines_enabled;
15222 }
15223
15224 /**
15225  * gtk_tree_view_set_enable_tree_lines:
15226  * @tree_view: a #GtkTreeView
15227  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15228  *
15229  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15230  * This does not have any visible effects for lists.
15231  *
15232  * Since: 2.10
15233  */
15234 void
15235 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15236                                      gboolean     enabled)
15237 {
15238   GtkTreeViewPrivate *priv;
15239   GtkWidget *widget;
15240   gboolean was_enabled;
15241
15242   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15243
15244   enabled = enabled != FALSE;
15245
15246   priv = tree_view->priv;
15247   widget = GTK_WIDGET (tree_view);
15248
15249   was_enabled = priv->tree_lines_enabled;
15250
15251   priv->tree_lines_enabled = enabled;
15252
15253   if (gtk_widget_get_realized (widget))
15254     {
15255       if (!enabled && priv->tree_line_width)
15256         {
15257           priv->tree_line_width = 0;
15258         }
15259       
15260       if (enabled && !priv->tree_line_width)
15261         {
15262           gint8 *dash_list;
15263           gtk_widget_style_get (widget,
15264                                 "tree-line-width", &priv->tree_line_width,
15265                                 "tree-line-pattern", (gchar *)&dash_list,
15266                                 NULL);
15267           
15268           if (dash_list)
15269             {
15270               priv->tree_line_dashes[0] = dash_list[0];
15271               if (dash_list[0])
15272                 priv->tree_line_dashes[1] = dash_list[1];
15273               
15274               g_free (dash_list);
15275             }
15276           else
15277             {
15278               priv->tree_line_dashes[0] = 1;
15279               priv->tree_line_dashes[1] = 1;
15280             }
15281         }
15282     }
15283
15284   if (was_enabled != enabled)
15285     {
15286       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15287
15288       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15289     }
15290 }
15291
15292
15293 /**
15294  * gtk_tree_view_set_show_expanders:
15295  * @tree_view: a #GtkTreeView
15296  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15297  *
15298  * Sets whether to draw and enable expanders and indent child rows in
15299  * @tree_view.  When disabled there will be no expanders visible in trees
15300  * and there will be no way to expand and collapse rows by default.  Also
15301  * note that hiding the expanders will disable the default indentation.  You
15302  * can set a custom indentation in this case using
15303  * gtk_tree_view_set_level_indentation().
15304  * This does not have any visible effects for lists.
15305  *
15306  * Since: 2.12
15307  */
15308 void
15309 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15310                                   gboolean     enabled)
15311 {
15312   gboolean was_enabled;
15313
15314   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15315
15316   enabled = enabled != FALSE;
15317   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15318
15319   if (enabled)
15320     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15321   else
15322     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15323
15324   if (enabled != was_enabled)
15325     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15326 }
15327
15328 /**
15329  * gtk_tree_view_get_show_expanders:
15330  * @tree_view: a #GtkTreeView.
15331  *
15332  * Returns whether or not expanders are drawn in @tree_view.
15333  *
15334  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15335  * otherwise.
15336  *
15337  * Since: 2.12
15338  */
15339 gboolean
15340 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15341 {
15342   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15343
15344   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15345 }
15346
15347 /**
15348  * gtk_tree_view_set_level_indentation:
15349  * @tree_view: a #GtkTreeView
15350  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15351  *
15352  * Sets the amount of extra indentation for child levels to use in @tree_view
15353  * in addition to the default indentation.  The value should be specified in
15354  * pixels, a value of 0 disables this feature and in this case only the default
15355  * indentation will be used.
15356  * This does not have any visible effects for lists.
15357  *
15358  * Since: 2.12
15359  */
15360 void
15361 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15362                                      gint         indentation)
15363 {
15364   tree_view->priv->level_indentation = indentation;
15365
15366   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15367 }
15368
15369 /**
15370  * gtk_tree_view_get_level_indentation:
15371  * @tree_view: a #GtkTreeView.
15372  *
15373  * Returns the amount, in pixels, of extra indentation for child levels
15374  * in @tree_view.
15375  *
15376  * Return value: the amount of extra indentation for child levels in
15377  * @tree_view.  A return value of 0 means that this feature is disabled.
15378  *
15379  * Since: 2.12
15380  */
15381 gint
15382 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15383 {
15384   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15385
15386   return tree_view->priv->level_indentation;
15387 }
15388
15389 /**
15390  * gtk_tree_view_set_tooltip_row:
15391  * @tree_view: a #GtkTreeView
15392  * @tooltip: a #GtkTooltip
15393  * @path: a #GtkTreePath
15394  *
15395  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15396  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15397  * See also gtk_tooltip_set_tip_area().
15398  *
15399  * Since: 2.12
15400  */
15401 void
15402 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15403                                GtkTooltip  *tooltip,
15404                                GtkTreePath *path)
15405 {
15406   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15407   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15408
15409   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15410 }
15411
15412 /**
15413  * gtk_tree_view_set_tooltip_cell:
15414  * @tree_view: a #GtkTreeView
15415  * @tooltip: a #GtkTooltip
15416  * @path: (allow-none): a #GtkTreePath or %NULL
15417  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
15418  * @cell: (allow-none): a #GtkCellRenderer or %NULL
15419  *
15420  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15421  * in common.  For example if @path is %NULL and @column is set, the tip
15422  * area will be set to the full area covered by @column.  See also
15423  * gtk_tooltip_set_tip_area().
15424  *
15425  * Note that if @path is not specified and @cell is set and part of a column
15426  * containing the expander, the tooltip might not show and hide at the correct
15427  * position.  In such cases @path must be set to the current node under the
15428  * mouse cursor for this function to operate correctly.
15429  *
15430  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15431  *
15432  * Since: 2.12
15433  */
15434 void
15435 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15436                                 GtkTooltip        *tooltip,
15437                                 GtkTreePath       *path,
15438                                 GtkTreeViewColumn *column,
15439                                 GtkCellRenderer   *cell)
15440 {
15441   GtkAllocation allocation;
15442   GdkRectangle rect;
15443
15444   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15445   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15446   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15447   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15448
15449   /* Determine x values. */
15450   if (column && cell)
15451     {
15452       GdkRectangle tmp;
15453       gint start, width;
15454
15455       /* We always pass in path here, whether it is NULL or not.
15456        * For cells in expander columns path must be specified so that
15457        * we can correctly account for the indentation.  This also means
15458        * that the tooltip is constrained vertically by the "Determine y
15459        * values" code below; this is not a real problem since cells actually
15460        * don't stretch vertically in constrast to columns.
15461        */
15462       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15463       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15464
15465       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15466                                                          tmp.x + start, 0,
15467                                                          &rect.x, NULL);
15468       rect.width = width;
15469     }
15470   else if (column)
15471     {
15472       GdkRectangle tmp;
15473
15474       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15475       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15476                                                          tmp.x, 0,
15477                                                          &rect.x, NULL);
15478       rect.width = tmp.width;
15479     }
15480   else
15481     {
15482       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
15483       rect.x = 0;
15484       rect.width = allocation.width;
15485     }
15486
15487   /* Determine y values. */
15488   if (path)
15489     {
15490       GdkRectangle tmp;
15491
15492       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15493       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15494                                                          0, tmp.y,
15495                                                          NULL, &rect.y);
15496       rect.height = tmp.height;
15497     }
15498   else
15499     {
15500       rect.y = 0;
15501       rect.height = tree_view->priv->vadjustment->page_size;
15502     }
15503
15504   gtk_tooltip_set_tip_area (tooltip, &rect);
15505 }
15506
15507 /**
15508  * gtk_tree_view_get_tooltip_context:
15509  * @tree_view: a #GtkTreeView
15510  * @x: the x coordinate (relative to widget coordinates)
15511  * @y: the y coordinate (relative to widget coordinates)
15512  * @keyboard_tip: whether this is a keyboard tooltip or not
15513  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
15514  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
15515  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
15516  *
15517  * This function is supposed to be used in a #GtkWidget::query-tooltip
15518  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15519  * which are received in the signal handler, should be passed to this
15520  * function without modification.
15521  *
15522  * The return value indicates whether there is a tree view row at the given
15523  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15524  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15525  * @model, @path and @iter which have been provided will be set to point to
15526  * that row and the corresponding model.  @x and @y will always be converted
15527  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15528  *
15529  * Return value: whether or not the given tooltip context points to a row.
15530  *
15531  * Since: 2.12
15532  */
15533 gboolean
15534 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15535                                    gint          *x,
15536                                    gint          *y,
15537                                    gboolean       keyboard_tip,
15538                                    GtkTreeModel **model,
15539                                    GtkTreePath  **path,
15540                                    GtkTreeIter   *iter)
15541 {
15542   GtkTreePath *tmppath = NULL;
15543
15544   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15545   g_return_val_if_fail (x != NULL, FALSE);
15546   g_return_val_if_fail (y != NULL, FALSE);
15547
15548   if (keyboard_tip)
15549     {
15550       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15551
15552       if (!tmppath)
15553         return FALSE;
15554     }
15555   else
15556     {
15557       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15558                                                          x, y);
15559
15560       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15561                                           &tmppath, NULL, NULL, NULL))
15562         return FALSE;
15563     }
15564
15565   if (model)
15566     *model = gtk_tree_view_get_model (tree_view);
15567
15568   if (iter)
15569     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15570                              iter, tmppath);
15571
15572   if (path)
15573     *path = tmppath;
15574   else
15575     gtk_tree_path_free (tmppath);
15576
15577   return TRUE;
15578 }
15579
15580 static gboolean
15581 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15582                                     gint        x,
15583                                     gint        y,
15584                                     gboolean    keyboard_tip,
15585                                     GtkTooltip *tooltip,
15586                                     gpointer    data)
15587 {
15588   GValue value = { 0, };
15589   GValue transformed = { 0, };
15590   GtkTreeIter iter;
15591   GtkTreePath *path;
15592   GtkTreeModel *model;
15593   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15594
15595   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15596                                           &x, &y,
15597                                           keyboard_tip,
15598                                           &model, &path, &iter))
15599     return FALSE;
15600
15601   gtk_tree_model_get_value (model, &iter,
15602                             tree_view->priv->tooltip_column, &value);
15603
15604   g_value_init (&transformed, G_TYPE_STRING);
15605
15606   if (!g_value_transform (&value, &transformed))
15607     {
15608       g_value_unset (&value);
15609       gtk_tree_path_free (path);
15610
15611       return FALSE;
15612     }
15613
15614   g_value_unset (&value);
15615
15616   if (!g_value_get_string (&transformed))
15617     {
15618       g_value_unset (&transformed);
15619       gtk_tree_path_free (path);
15620
15621       return FALSE;
15622     }
15623
15624   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15625   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15626
15627   gtk_tree_path_free (path);
15628   g_value_unset (&transformed);
15629
15630   return TRUE;
15631 }
15632
15633 /**
15634  * gtk_tree_view_set_tooltip_column:
15635  * @tree_view: a #GtkTreeView
15636  * @column: an integer, which is a valid column number for @tree_view's model
15637  *
15638  * If you only plan to have simple (text-only) tooltips on full rows, you
15639  * can use this function to have #GtkTreeView handle these automatically
15640  * for you. @column should be set to the column in @tree_view's model
15641  * containing the tooltip texts, or -1 to disable this feature.
15642  *
15643  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15644  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15645  *
15646  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15647  * so &amp;, &lt;, etc have to be escaped in the text.
15648  *
15649  * Since: 2.12
15650  */
15651 void
15652 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15653                                   gint         column)
15654 {
15655   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15656
15657   if (column == tree_view->priv->tooltip_column)
15658     return;
15659
15660   if (column == -1)
15661     {
15662       g_signal_handlers_disconnect_by_func (tree_view,
15663                                             gtk_tree_view_set_tooltip_query_cb,
15664                                             NULL);
15665       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15666     }
15667   else
15668     {
15669       if (tree_view->priv->tooltip_column == -1)
15670         {
15671           g_signal_connect (tree_view, "query-tooltip",
15672                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15673           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15674         }
15675     }
15676
15677   tree_view->priv->tooltip_column = column;
15678   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15679 }
15680
15681 /**
15682  * gtk_tree_view_get_tooltip_column:
15683  * @tree_view: a #GtkTreeView
15684  *
15685  * Returns the column of @tree_view's model which is being used for
15686  * displaying tooltips on @tree_view's rows.
15687  *
15688  * Return value: the index of the tooltip column that is currently being
15689  * used, or -1 if this is disabled.
15690  *
15691  * Since: 2.12
15692  */
15693 gint
15694 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15695 {
15696   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15697
15698   return tree_view->priv->tooltip_column;
15699 }