]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Use accessor functions to acces GtkContainer
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include "config.h"
22 #include <string.h>
23 #include <gdk/gdkkeysyms.h>
24
25 #include "gtktreeview.h"
26 #include "gtkrbtree.h"
27 #include "gtktreednd.h"
28 #include "gtktreeprivate.h"
29 #include "gtkcellrenderer.h"
30 #include "gtkmain.h"
31 #include "gtkmarshalers.h"
32 #include "gtkbuildable.h"
33 #include "gtkbutton.h"
34 #include "gtkalignment.h"
35 #include "gtklabel.h"
36 #include "gtkhbox.h"
37 #include "gtkvbox.h"
38 #include "gtkarrow.h"
39 #include "gtkintl.h"
40 #include "gtkbindings.h"
41 #include "gtkcontainer.h"
42 #include "gtkentry.h"
43 #include "gtkframe.h"
44 #include "gtktreemodelsort.h"
45 #include "gtktooltip.h"
46 #include "gtkprivate.h"
47
48 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
49 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
50 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
51 #define SCROLL_EDGE_SIZE 15
52 #define EXPANDER_EXTRA_PADDING 4
53 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
54 #define AUTO_EXPAND_TIMEOUT 500
55
56 /* The "background" areas of all rows/cells add up to cover the entire tree.
57  * The background includes all inter-row and inter-cell spacing.
58  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
59  * i.e. just the cells, no spacing.
60  */
61
62 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
63 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
64
65 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
66  * vice versa.
67  */
68 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
69 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
70
71 /* This is in bin_window coordinates */
72 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
73 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
74
75 #define ROW_HEIGHT(tree_view,height) \
76   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
77
78
79 typedef struct _GtkTreeViewChild GtkTreeViewChild;
80 struct _GtkTreeViewChild
81 {
82   GtkWidget *widget;
83   gint x;
84   gint y;
85   gint width;
86   gint height;
87 };
88
89
90 typedef struct _TreeViewDragInfo TreeViewDragInfo;
91 struct _TreeViewDragInfo
92 {
93   GdkModifierType start_button_mask;
94   GtkTargetList *_unused_source_target_list;
95   GdkDragAction source_actions;
96
97   GtkTargetList *_unused_dest_target_list;
98
99   guint source_set : 1;
100   guint dest_set : 1;
101 };
102
103
104 /* Signals */
105 enum
106 {
107   ROW_ACTIVATED,
108   TEST_EXPAND_ROW,
109   TEST_COLLAPSE_ROW,
110   ROW_EXPANDED,
111   ROW_COLLAPSED,
112   COLUMNS_CHANGED,
113   CURSOR_CHANGED,
114   MOVE_CURSOR,
115   SELECT_ALL,
116   UNSELECT_ALL,
117   SELECT_CURSOR_ROW,
118   TOGGLE_CURSOR_ROW,
119   EXPAND_COLLAPSE_CURSOR_ROW,
120   SELECT_CURSOR_PARENT,
121   START_INTERACTIVE_SEARCH,
122   LAST_SIGNAL
123 };
124
125 /* Properties */
126 enum {
127   PROP_0,
128   PROP_MODEL,
129   PROP_HADJUSTMENT,
130   PROP_VADJUSTMENT,
131   PROP_HEADERS_VISIBLE,
132   PROP_HEADERS_CLICKABLE,
133   PROP_EXPANDER_COLUMN,
134   PROP_REORDERABLE,
135   PROP_RULES_HINT,
136   PROP_ENABLE_SEARCH,
137   PROP_SEARCH_COLUMN,
138   PROP_FIXED_HEIGHT_MODE,
139   PROP_HOVER_SELECTION,
140   PROP_HOVER_EXPAND,
141   PROP_SHOW_EXPANDERS,
142   PROP_LEVEL_INDENTATION,
143   PROP_RUBBER_BANDING,
144   PROP_ENABLE_GRID_LINES,
145   PROP_ENABLE_TREE_LINES,
146   PROP_TOOLTIP_COLUMN
147 };
148
149 /* object signals */
150 static void     gtk_tree_view_finalize             (GObject          *object);
151 static void     gtk_tree_view_set_property         (GObject         *object,
152                                                     guint            prop_id,
153                                                     const GValue    *value,
154                                                     GParamSpec      *pspec);
155 static void     gtk_tree_view_get_property         (GObject         *object,
156                                                     guint            prop_id,
157                                                     GValue          *value,
158                                                     GParamSpec      *pspec);
159
160 /* gtkobject signals */
161 static void     gtk_tree_view_destroy              (GtkObject        *object);
162
163 /* gtkwidget signals */
164 static void     gtk_tree_view_realize              (GtkWidget        *widget);
165 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
166 static void     gtk_tree_view_map                  (GtkWidget        *widget);
167 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
168                                                     GtkRequisition   *requisition);
169 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
170                                                     GtkAllocation    *allocation);
171 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
172                                                     GdkEventExpose   *event);
173 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
174                                                     GdkEventKey      *event);
175 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
176                                                     GdkEventKey      *event);
177 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
178                                                     GdkEventMotion   *event);
179 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
180                                                     GdkEventCrossing *event);
181 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
182                                                     GdkEventCrossing *event);
183 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
184                                                     GdkEventButton   *event);
185 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
186                                                     GdkEventButton   *event);
187 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
188                                                     GdkEventGrabBroken *event);
189 #if 0
190 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
191                                                     GdkEventConfigure *event);
192 #endif
193
194 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
195                                                     GtkWidget        *child);
196 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
197                                                     GdkEventFocus    *event);
198 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
199                                                     GtkDirectionType  direction);
200 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
201 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
202                                                     GtkStyle         *previous_style);
203 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
204                                                     gboolean          was_grabbed);
205 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
206                                                     GtkStateType      previous_state);
207
208 /* container signals */
209 static void     gtk_tree_view_remove               (GtkContainer     *container,
210                                                     GtkWidget        *widget);
211 static void     gtk_tree_view_forall               (GtkContainer     *container,
212                                                     gboolean          include_internals,
213                                                     GtkCallback       callback,
214                                                     gpointer          callback_data);
215
216 /* Source side drag signals */
217 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
218                                             GdkDragContext   *context);
219 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
220                                             GdkDragContext   *context);
221 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
222                                             GdkDragContext   *context,
223                                             GtkSelectionData *selection_data,
224                                             guint             info,
225                                             guint             time);
226 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
227                                             GdkDragContext   *context);
228
229 /* Target side drag signals */
230 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
231                                                   GdkDragContext   *context,
232                                                   guint             time);
233 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
234                                                   GdkDragContext   *context,
235                                                   gint              x,
236                                                   gint              y,
237                                                   guint             time);
238 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
239                                                   GdkDragContext   *context,
240                                                   gint              x,
241                                                   gint              y,
242                                                   guint             time);
243 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
244                                                   GdkDragContext   *context,
245                                                   gint              x,
246                                                   gint              y,
247                                                   GtkSelectionData *selection_data,
248                                                   guint             info,
249                                                   guint             time);
250
251 /* tree_model signals */
252 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
253                                                            GtkAdjustment   *hadj,
254                                                            GtkAdjustment   *vadj);
255 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
256                                                            GtkMovementStep  step,
257                                                            gint             count);
258 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
259 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
260 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
261                                                            gboolean         start_editing);
262 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
263 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
264                                                                gboolean         logical,
265                                                                gboolean         expand,
266                                                                gboolean         open_all);
267 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
268 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
269                                                            GtkTreePath     *path,
270                                                            GtkTreeIter     *iter,
271                                                            gpointer         data);
272 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
273                                                            GtkTreePath     *path,
274                                                            GtkTreeIter     *iter,
275                                                            gpointer         data);
276 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
277                                                            GtkTreePath     *path,
278                                                            GtkTreeIter     *iter,
279                                                            gpointer         data);
280 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
281                                                            GtkTreePath     *path,
282                                                            gpointer         data);
283 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
284                                                            GtkTreePath     *parent,
285                                                            GtkTreeIter     *iter,
286                                                            gint            *new_order,
287                                                            gpointer         data);
288
289 /* Incremental reflow */
290 static gboolean validate_row             (GtkTreeView *tree_view,
291                                           GtkRBTree   *tree,
292                                           GtkRBNode   *node,
293                                           GtkTreeIter *iter,
294                                           GtkTreePath *path);
295 static void     validate_visible_area    (GtkTreeView *tree_view);
296 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
297 static gboolean do_validate_rows         (GtkTreeView *tree_view,
298                                           gboolean     size_request);
299 static gboolean validate_rows            (GtkTreeView *tree_view);
300 static gboolean presize_handler_callback (gpointer     data);
301 static void     install_presize_handler  (GtkTreeView *tree_view);
302 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
303 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
304                                              GtkTreePath *path,
305                                              gint         offset);
306 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
307 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
308 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
309
310 /* Internal functions */
311 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
312                                                               GtkTreeViewColumn  *column);
313 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
314                                                               guint               keyval,
315                                                               guint               modmask,
316                                                               gboolean            add_shifted_binding,
317                                                               GtkMovementStep     step,
318                                                               gint                count);
319 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
320                                                               GtkRBTree          *tree);
321 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
322                                                               GtkTreePath        *path,
323                                                               const GdkRectangle *clip_rect);
324 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
325                                                               GtkRBTree          *tree,
326                                                               GtkRBNode          *node,
327                                                               const GdkRectangle *clip_rect);
328 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
329                                                               GtkRBTree          *tree,
330                                                               GtkRBNode          *node,
331                                                               gint                x,
332                                                               gint                y);
333 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
334                                                               GtkRBTree          *tree,
335                                                               gint               *x1,
336                                                               gint               *x2);
337 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
338                                                               gint                i,
339                                                               gint               *x);
340 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
341                                                               GtkTreeView        *tree_view);
342 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
343                                                               GtkRBTree          *tree,
344                                                               GtkTreeIter        *iter,
345                                                               gint                depth,
346                                                               gboolean            recurse);
347 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
348                                                               GtkRBTree          *tree,
349                                                               GtkRBNode          *node);
350 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
351                                                               GtkTreeViewColumn  *column,
352                                                               gboolean            focus_to_cell);
353 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
354                                                               GdkEventMotion     *event);
355 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
356 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
357                                                               gint                count);
358 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
359                                                               gint                count);
360 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
361                                                               gint                count);
362 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
363                                                               gint                count);
364 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
365                                                               GtkTreePath        *path,
366                                                               GtkRBTree          *tree,
367                                                               GtkRBNode          *node,
368                                                               gboolean            animate);
369 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
370                                                               GtkTreePath        *path,
371                                                               GtkRBTree          *tree,
372                                                               GtkRBNode          *node,
373                                                               gboolean            open_all,
374                                                               gboolean            animate);
375 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
376                                                               GtkTreePath        *path,
377                                                               gboolean            clear_and_select,
378                                                               gboolean            clamp_node);
379 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
380 static void     column_sizing_notify                         (GObject            *object,
381                                                               GParamSpec         *pspec,
382                                                               gpointer            data);
383 static gboolean expand_collapse_timeout                      (gpointer            data);
384 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
385                                                               GtkRBTree          *tree,
386                                                               GtkRBNode          *node,
387                                                               gboolean            expand);
388 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
389 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
390 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
391 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
392 static void     update_prelight                              (GtkTreeView        *tree_view,
393                                                               int                 x,
394                                                               int                 y);
395
396 /* interactive search */
397 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
398 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
399                                                          GtkTreeView      *tree_view,
400                                                          GdkDevice        *device);
401 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
402                                                          GtkWidget        *search_dialog,
403                                                          gpointer          user_data);
404 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
405                                                          GtkMenu          *menu,
406                                                          gpointer          data);
407 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
408                                                          GtkTreeView      *tree_view);
409 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
410                                                          GtkTreeView      *tree_view);
411 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
412 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
413                                                          gpointer          data);
414 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
415                                                          GdkEventAny      *event,
416                                                          GtkTreeView      *tree_view);
417 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
418                                                          GdkEventButton   *event,
419                                                          GtkTreeView      *tree_view);
420 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
421                                                          GdkEventScroll   *event,
422                                                          GtkTreeView      *tree_view);
423 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
424                                                          GdkEventKey      *event,
425                                                          GtkTreeView      *tree_view);
426 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
427                                                          GtkTreeView      *tree_view,
428                                                          gboolean          up);
429 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
430                                                          gint              column,
431                                                          const gchar      *key,
432                                                          GtkTreeIter      *iter,
433                                                          gpointer          search_data);
434 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
435                                                          GtkTreeSelection *selection,
436                                                          GtkTreeIter      *iter,
437                                                          const gchar      *text,
438                                                          gint             *count,
439                                                          gint              n);
440 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
441                                                          GtkTreeView      *tree_view);
442 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
443                                                          GtkWidget        *child_widget,
444                                                          gint              x,
445                                                          gint              y,
446                                                          gint              width,
447                                                          gint              height);
448 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
449                                                          GtkTreePath      *cursor_path);
450 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
451                                               GtkTreeViewColumn *column,
452                                               GtkTreePath       *path,
453                                               GtkCellEditable   *cell_editable,
454                                               GdkRectangle      *cell_area,
455                                               GdkEvent          *event,
456                                               guint              flags);
457 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
458                                                          gboolean     cancel_editing);
459 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
460                                                              GdkDevice   *device,
461                                                              gboolean     keybinding);
462 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
463 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
464                                                          GtkTreeViewColumn *column,
465                                                          gint               drop_position);
466
467 /* GtkBuildable */
468 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
469                                                             GtkBuilder        *builder,
470                                                             GObject           *child,
471                                                             const gchar       *type);
472 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
473                                                             GtkBuilder        *builder,
474                                                             const gchar       *childname);
475 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
476
477
478 static gboolean scroll_row_timeout                   (gpointer     data);
479 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
480 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
481
482 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
483
484 \f
485
486 /* GType Methods
487  */
488
489 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
490                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
491                                                 gtk_tree_view_buildable_init))
492
493 static void
494 gtk_tree_view_class_init (GtkTreeViewClass *class)
495 {
496   GObjectClass *o_class;
497   GtkObjectClass *object_class;
498   GtkWidgetClass *widget_class;
499   GtkContainerClass *container_class;
500   GtkBindingSet *binding_set;
501
502   binding_set = gtk_binding_set_by_class (class);
503
504   o_class = (GObjectClass *) class;
505   object_class = (GtkObjectClass *) class;
506   widget_class = (GtkWidgetClass *) class;
507   container_class = (GtkContainerClass *) class;
508
509   /* GObject signals */
510   o_class->set_property = gtk_tree_view_set_property;
511   o_class->get_property = gtk_tree_view_get_property;
512   o_class->finalize = gtk_tree_view_finalize;
513
514   /* GtkObject signals */
515   object_class->destroy = gtk_tree_view_destroy;
516
517   /* GtkWidget signals */
518   widget_class->map = gtk_tree_view_map;
519   widget_class->realize = gtk_tree_view_realize;
520   widget_class->unrealize = gtk_tree_view_unrealize;
521   widget_class->size_request = gtk_tree_view_size_request;
522   widget_class->size_allocate = gtk_tree_view_size_allocate;
523   widget_class->button_press_event = gtk_tree_view_button_press;
524   widget_class->button_release_event = gtk_tree_view_button_release;
525   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
526   /*widget_class->configure_event = gtk_tree_view_configure;*/
527   widget_class->motion_notify_event = gtk_tree_view_motion;
528   widget_class->expose_event = gtk_tree_view_expose;
529   widget_class->key_press_event = gtk_tree_view_key_press;
530   widget_class->key_release_event = gtk_tree_view_key_release;
531   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
532   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
533   widget_class->focus_out_event = gtk_tree_view_focus_out;
534   widget_class->drag_begin = gtk_tree_view_drag_begin;
535   widget_class->drag_end = gtk_tree_view_drag_end;
536   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
537   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
538   widget_class->drag_leave = gtk_tree_view_drag_leave;
539   widget_class->drag_motion = gtk_tree_view_drag_motion;
540   widget_class->drag_drop = gtk_tree_view_drag_drop;
541   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
542   widget_class->focus = gtk_tree_view_focus;
543   widget_class->grab_focus = gtk_tree_view_grab_focus;
544   widget_class->style_set = gtk_tree_view_style_set;
545   widget_class->grab_notify = gtk_tree_view_grab_notify;
546   widget_class->state_changed = gtk_tree_view_state_changed;
547
548   /* GtkContainer signals */
549   container_class->remove = gtk_tree_view_remove;
550   container_class->forall = gtk_tree_view_forall;
551   container_class->set_focus_child = gtk_tree_view_set_focus_child;
552
553   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
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_install_property (o_class,
574                                    PROP_HADJUSTMENT,
575                                    g_param_spec_object ("hadjustment",
576                                                         P_("Horizontal Adjustment"),
577                                                         P_("Horizontal Adjustment for the widget"),
578                                                         GTK_TYPE_ADJUSTMENT,
579                                                         GTK_PARAM_READWRITE));
580
581   g_object_class_install_property (o_class,
582                                    PROP_VADJUSTMENT,
583                                    g_param_spec_object ("vadjustment",
584                                                         P_("Vertical Adjustment"),
585                                                         P_("Vertical Adjustment for the widget"),
586                                                         GTK_TYPE_ADJUSTMENT,
587                                                         GTK_PARAM_READWRITE));
588
589   g_object_class_install_property (o_class,
590                                    PROP_HEADERS_VISIBLE,
591                                    g_param_spec_boolean ("headers-visible",
592                                                          P_("Headers Visible"),
593                                                          P_("Show the column header buttons"),
594                                                          TRUE,
595                                                          GTK_PARAM_READWRITE));
596
597   g_object_class_install_property (o_class,
598                                    PROP_HEADERS_CLICKABLE,
599                                    g_param_spec_boolean ("headers-clickable",
600                                                          P_("Headers Clickable"),
601                                                          P_("Column headers respond to click events"),
602                                                          TRUE,
603                                                          GTK_PARAM_READWRITE));
604
605   g_object_class_install_property (o_class,
606                                    PROP_EXPANDER_COLUMN,
607                                    g_param_spec_object ("expander-column",
608                                                         P_("Expander Column"),
609                                                         P_("Set the column for the expander column"),
610                                                         GTK_TYPE_TREE_VIEW_COLUMN,
611                                                         GTK_PARAM_READWRITE));
612
613   g_object_class_install_property (o_class,
614                                    PROP_REORDERABLE,
615                                    g_param_spec_boolean ("reorderable",
616                                                          P_("Reorderable"),
617                                                          P_("View is reorderable"),
618                                                          FALSE,
619                                                          GTK_PARAM_READWRITE));
620
621   g_object_class_install_property (o_class,
622                                    PROP_RULES_HINT,
623                                    g_param_spec_boolean ("rules-hint",
624                                                          P_("Rules Hint"),
625                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
626                                                          FALSE,
627                                                          GTK_PARAM_READWRITE));
628
629     g_object_class_install_property (o_class,
630                                      PROP_ENABLE_SEARCH,
631                                      g_param_spec_boolean ("enable-search",
632                                                            P_("Enable Search"),
633                                                            P_("View allows user to search through columns interactively"),
634                                                            TRUE,
635                                                            GTK_PARAM_READWRITE));
636
637     g_object_class_install_property (o_class,
638                                      PROP_SEARCH_COLUMN,
639                                      g_param_spec_int ("search-column",
640                                                        P_("Search Column"),
641                                                        P_("Model column to search through during interactive search"),
642                                                        -1,
643                                                        G_MAXINT,
644                                                        -1,
645                                                        GTK_PARAM_READWRITE));
646
647     /**
648      * GtkTreeView:fixed-height-mode:
649      *
650      * Setting the ::fixed-height-mode property to %TRUE speeds up 
651      * #GtkTreeView by assuming that all rows have the same height. 
652      * Only enable this option if all rows are the same height.  
653      * Please see gtk_tree_view_set_fixed_height_mode() for more 
654      * information on this option.
655      *
656      * Since: 2.4
657      **/
658     g_object_class_install_property (o_class,
659                                      PROP_FIXED_HEIGHT_MODE,
660                                      g_param_spec_boolean ("fixed-height-mode",
661                                                            P_("Fixed Height Mode"),
662                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
663                                                            FALSE,
664                                                            GTK_PARAM_READWRITE));
665     
666     /**
667      * GtkTreeView:hover-selection:
668      * 
669      * Enables of disables the hover selection mode of @tree_view.
670      * Hover selection makes the selected row follow the pointer.
671      * Currently, this works only for the selection modes 
672      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
673      *
674      * This mode is primarily intended for treeviews in popups, e.g.
675      * in #GtkComboBox or #GtkEntryCompletion.
676      *
677      * Since: 2.6
678      */
679     g_object_class_install_property (o_class,
680                                      PROP_HOVER_SELECTION,
681                                      g_param_spec_boolean ("hover-selection",
682                                                            P_("Hover Selection"),
683                                                            P_("Whether the selection should follow the pointer"),
684                                                            FALSE,
685                                                            GTK_PARAM_READWRITE));
686
687     /**
688      * GtkTreeView:hover-expand:
689      * 
690      * Enables of disables the hover expansion mode of @tree_view.
691      * Hover expansion makes rows expand or collapse if the pointer moves 
692      * over them.
693      *
694      * This mode is primarily intended for treeviews in popups, e.g.
695      * in #GtkComboBox or #GtkEntryCompletion.
696      *
697      * Since: 2.6
698      */
699     g_object_class_install_property (o_class,
700                                      PROP_HOVER_EXPAND,
701                                      g_param_spec_boolean ("hover-expand",
702                                                            P_("Hover Expand"),
703                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
704                                                            FALSE,
705                                                            GTK_PARAM_READWRITE));
706
707     /**
708      * GtkTreeView:show-expanders:
709      *
710      * %TRUE if the view has expanders.
711      *
712      * Since: 2.12
713      */
714     g_object_class_install_property (o_class,
715                                      PROP_SHOW_EXPANDERS,
716                                      g_param_spec_boolean ("show-expanders",
717                                                            P_("Show Expanders"),
718                                                            P_("View has expanders"),
719                                                            TRUE,
720                                                            GTK_PARAM_READWRITE));
721
722     /**
723      * GtkTreeView:level-indentation:
724      *
725      * Extra indentation for each level.
726      *
727      * Since: 2.12
728      */
729     g_object_class_install_property (o_class,
730                                      PROP_LEVEL_INDENTATION,
731                                      g_param_spec_int ("level-indentation",
732                                                        P_("Level Indentation"),
733                                                        P_("Extra indentation for each level"),
734                                                        0,
735                                                        G_MAXINT,
736                                                        0,
737                                                        GTK_PARAM_READWRITE));
738
739     g_object_class_install_property (o_class,
740                                      PROP_RUBBER_BANDING,
741                                      g_param_spec_boolean ("rubber-banding",
742                                                            P_("Rubber Banding"),
743                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
744                                                            FALSE,
745                                                            GTK_PARAM_READWRITE));
746
747     g_object_class_install_property (o_class,
748                                      PROP_ENABLE_GRID_LINES,
749                                      g_param_spec_enum ("enable-grid-lines",
750                                                         P_("Enable Grid Lines"),
751                                                         P_("Whether grid lines should be drawn in the tree view"),
752                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
753                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
754                                                         GTK_PARAM_READWRITE));
755
756     g_object_class_install_property (o_class,
757                                      PROP_ENABLE_TREE_LINES,
758                                      g_param_spec_boolean ("enable-tree-lines",
759                                                            P_("Enable Tree Lines"),
760                                                            P_("Whether tree lines should be drawn in the tree view"),
761                                                            FALSE,
762                                                            GTK_PARAM_READWRITE));
763
764     g_object_class_install_property (o_class,
765                                      PROP_TOOLTIP_COLUMN,
766                                      g_param_spec_int ("tooltip-column",
767                                                        P_("Tooltip Column"),
768                                                        P_("The column in the model containing the tooltip texts for the rows"),
769                                                        -1,
770                                                        G_MAXINT,
771                                                        -1,
772                                                        GTK_PARAM_READWRITE));
773
774   /* Style properties */
775 #define _TREE_VIEW_EXPANDER_SIZE 12
776 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
777 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
778
779   gtk_widget_class_install_style_property (widget_class,
780                                            g_param_spec_int ("expander-size",
781                                                              P_("Expander Size"),
782                                                              P_("Size of the expander arrow"),
783                                                              0,
784                                                              G_MAXINT,
785                                                              _TREE_VIEW_EXPANDER_SIZE,
786                                                              GTK_PARAM_READABLE));
787
788   gtk_widget_class_install_style_property (widget_class,
789                                            g_param_spec_int ("vertical-separator",
790                                                              P_("Vertical Separator Width"),
791                                                              P_("Vertical space between cells.  Must be an even number"),
792                                                              0,
793                                                              G_MAXINT,
794                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
795                                                              GTK_PARAM_READABLE));
796
797   gtk_widget_class_install_style_property (widget_class,
798                                            g_param_spec_int ("horizontal-separator",
799                                                              P_("Horizontal Separator Width"),
800                                                              P_("Horizontal space between cells.  Must be an even number"),
801                                                              0,
802                                                              G_MAXINT,
803                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
804                                                              GTK_PARAM_READABLE));
805
806   gtk_widget_class_install_style_property (widget_class,
807                                            g_param_spec_boolean ("allow-rules",
808                                                                  P_("Allow Rules"),
809                                                                  P_("Allow drawing of alternating color rows"),
810                                                                  TRUE,
811                                                                  GTK_PARAM_READABLE));
812
813   gtk_widget_class_install_style_property (widget_class,
814                                            g_param_spec_boolean ("indent-expanders",
815                                                                  P_("Indent Expanders"),
816                                                                  P_("Make the expanders indented"),
817                                                                  TRUE,
818                                                                  GTK_PARAM_READABLE));
819
820   gtk_widget_class_install_style_property (widget_class,
821                                            g_param_spec_boxed ("even-row-color",
822                                                                P_("Even Row Color"),
823                                                                P_("Color to use for even rows"),
824                                                                GDK_TYPE_COLOR,
825                                                                GTK_PARAM_READABLE));
826
827   gtk_widget_class_install_style_property (widget_class,
828                                            g_param_spec_boxed ("odd-row-color",
829                                                                P_("Odd Row Color"),
830                                                                P_("Color to use for odd rows"),
831                                                                GDK_TYPE_COLOR,
832                                                                GTK_PARAM_READABLE));
833
834   gtk_widget_class_install_style_property (widget_class,
835                                            g_param_spec_boolean ("row-ending-details",
836                                                                  P_("Row Ending details"),
837                                                                  P_("Enable extended row background theming"),
838                                                                  FALSE,
839                                                                  GTK_PARAM_READABLE));
840
841   gtk_widget_class_install_style_property (widget_class,
842                                            g_param_spec_int ("grid-line-width",
843                                                              P_("Grid line width"),
844                                                              P_("Width, in pixels, of the tree view grid lines"),
845                                                              0, G_MAXINT, 1,
846                                                              GTK_PARAM_READABLE));
847
848   gtk_widget_class_install_style_property (widget_class,
849                                            g_param_spec_int ("tree-line-width",
850                                                              P_("Tree line width"),
851                                                              P_("Width, in pixels, of the tree view lines"),
852                                                              0, G_MAXINT, 1,
853                                                              GTK_PARAM_READABLE));
854
855   gtk_widget_class_install_style_property (widget_class,
856                                            g_param_spec_string ("grid-line-pattern",
857                                                                 P_("Grid line pattern"),
858                                                                 P_("Dash pattern used to draw the tree view grid lines"),
859                                                                 "\1\1",
860                                                                 GTK_PARAM_READABLE));
861
862   gtk_widget_class_install_style_property (widget_class,
863                                            g_param_spec_string ("tree-line-pattern",
864                                                                 P_("Tree line pattern"),
865                                                                 P_("Dash pattern used to draw the tree view lines"),
866                                                                 "\1\1",
867                                                                 GTK_PARAM_READABLE));
868
869   /* Signals */
870   /**
871    * GtkTreeView::set-scroll-adjustments
872    * @horizontal: the horizontal #GtkAdjustment
873    * @vertical: the vertical #GtkAdjustment
874    *
875    * Set the scroll adjustments for the tree view. Usually scrolled containers
876    * like #GtkScrolledWindow will emit this signal to connect two instances
877    * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
878    */
879   widget_class->set_scroll_adjustments_signal =
880     g_signal_new (I_("set-scroll-adjustments"),
881                   G_TYPE_FROM_CLASS (o_class),
882                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
883                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
884                   NULL, NULL,
885                   _gtk_marshal_VOID__OBJECT_OBJECT,
886                   G_TYPE_NONE, 2,
887                   GTK_TYPE_ADJUSTMENT,
888                   GTK_TYPE_ADJUSTMENT);
889
890   /**
891    * GtkTreeView::row-activated:
892    * @tree_view: the object on which the signal is emitted
893    * @path: the #GtkTreePath for the activated row
894    * @column: the #GtkTreeViewColumn in which the activation occurred
895    *
896    * The "row-activated" signal is emitted when the method
897    * gtk_tree_view_row_activated() is called or the user double clicks 
898    * a treeview row. It is also emitted when a non-editable row is 
899    * selected and one of the keys: Space, Shift+Space, Return or 
900    * Enter is pressed.
901    * 
902    * For selection handling refer to the <link linkend="TreeWidget">tree 
903    * widget conceptual overview</link> as well as #GtkTreeSelection.
904    */
905   tree_view_signals[ROW_ACTIVATED] =
906     g_signal_new (I_("row-activated"),
907                   G_TYPE_FROM_CLASS (o_class),
908                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
909                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
910                   NULL, NULL,
911                   _gtk_marshal_VOID__BOXED_OBJECT,
912                   G_TYPE_NONE, 2,
913                   GTK_TYPE_TREE_PATH,
914                   GTK_TYPE_TREE_VIEW_COLUMN);
915
916   /**
917    * GtkTreeView::test-expand-row:
918    * @tree_view: the object on which the signal is emitted
919    * @iter: the tree iter of the row to expand
920    * @path: a tree path that points to the row 
921    * 
922    * The given row is about to be expanded (show its children nodes). Use this
923    * signal if you need to control the expandability of individual rows.
924    *
925    * Returns: %FALSE to allow expansion, %TRUE to reject
926    */
927   tree_view_signals[TEST_EXPAND_ROW] =
928     g_signal_new (I_("test-expand-row"),
929                   G_TYPE_FROM_CLASS (o_class),
930                   G_SIGNAL_RUN_LAST,
931                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
932                   _gtk_boolean_handled_accumulator, NULL,
933                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
934                   G_TYPE_BOOLEAN, 2,
935                   GTK_TYPE_TREE_ITER,
936                   GTK_TYPE_TREE_PATH);
937
938   /**
939    * GtkTreeView::test-collapse-row:
940    * @tree_view: the object on which the signal is emitted
941    * @iter: the tree iter of the row to collapse
942    * @path: a tree path that points to the row 
943    * 
944    * The given row is about to be collapsed (hide its children nodes). Use this
945    * signal if you need to control the collapsibility of individual rows.
946    *
947    * Returns: %FALSE to allow collapsing, %TRUE to reject
948    */
949   tree_view_signals[TEST_COLLAPSE_ROW] =
950     g_signal_new (I_("test-collapse-row"),
951                   G_TYPE_FROM_CLASS (o_class),
952                   G_SIGNAL_RUN_LAST,
953                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
954                   _gtk_boolean_handled_accumulator, NULL,
955                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
956                   G_TYPE_BOOLEAN, 2,
957                   GTK_TYPE_TREE_ITER,
958                   GTK_TYPE_TREE_PATH);
959
960   /**
961    * GtkTreeView::row-expanded:
962    * @tree_view: the object on which the signal is emitted
963    * @iter: the tree iter of the expanded row
964    * @path: a tree path that points to the row 
965    * 
966    * The given row has been expanded (child nodes are shown).
967    */
968   tree_view_signals[ROW_EXPANDED] =
969     g_signal_new (I_("row-expanded"),
970                   G_TYPE_FROM_CLASS (o_class),
971                   G_SIGNAL_RUN_LAST,
972                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
973                   NULL, NULL,
974                   _gtk_marshal_VOID__BOXED_BOXED,
975                   G_TYPE_NONE, 2,
976                   GTK_TYPE_TREE_ITER,
977                   GTK_TYPE_TREE_PATH);
978
979   /**
980    * GtkTreeView::row-collapsed:
981    * @tree_view: the object on which the signal is emitted
982    * @iter: the tree iter of the collapsed row
983    * @path: a tree path that points to the row 
984    * 
985    * The given row has been collapsed (child nodes are hidden).
986    */
987   tree_view_signals[ROW_COLLAPSED] =
988     g_signal_new (I_("row-collapsed"),
989                   G_TYPE_FROM_CLASS (o_class),
990                   G_SIGNAL_RUN_LAST,
991                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
992                   NULL, NULL,
993                   _gtk_marshal_VOID__BOXED_BOXED,
994                   G_TYPE_NONE, 2,
995                   GTK_TYPE_TREE_ITER,
996                   GTK_TYPE_TREE_PATH);
997
998   /**
999    * GtkTreeView::columns-changed:
1000    * @tree_view: the object on which the signal is emitted 
1001    * 
1002    * The number of columns of the treeview has changed.
1003    */
1004   tree_view_signals[COLUMNS_CHANGED] =
1005     g_signal_new (I_("columns-changed"),
1006                   G_TYPE_FROM_CLASS (o_class),
1007                   G_SIGNAL_RUN_LAST,
1008                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1009                   NULL, NULL,
1010                   _gtk_marshal_VOID__VOID,
1011                   G_TYPE_NONE, 0);
1012
1013   /**
1014    * GtkTreeView::cursor-changed:
1015    * @tree_view: the object on which the signal is emitted
1016    * 
1017    * The position of the cursor (focused cell) has changed.
1018    */
1019   tree_view_signals[CURSOR_CHANGED] =
1020     g_signal_new (I_("cursor-changed"),
1021                   G_TYPE_FROM_CLASS (o_class),
1022                   G_SIGNAL_RUN_LAST,
1023                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1024                   NULL, NULL,
1025                   _gtk_marshal_VOID__VOID,
1026                   G_TYPE_NONE, 0);
1027
1028   tree_view_signals[MOVE_CURSOR] =
1029     g_signal_new (I_("move-cursor"),
1030                   G_TYPE_FROM_CLASS (object_class),
1031                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1032                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1033                   NULL, NULL,
1034                   _gtk_marshal_BOOLEAN__ENUM_INT,
1035                   G_TYPE_BOOLEAN, 2,
1036                   GTK_TYPE_MOVEMENT_STEP,
1037                   G_TYPE_INT);
1038
1039   tree_view_signals[SELECT_ALL] =
1040     g_signal_new (I_("select-all"),
1041                   G_TYPE_FROM_CLASS (object_class),
1042                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1043                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1044                   NULL, NULL,
1045                   _gtk_marshal_BOOLEAN__VOID,
1046                   G_TYPE_BOOLEAN, 0);
1047
1048   tree_view_signals[UNSELECT_ALL] =
1049     g_signal_new (I_("unselect-all"),
1050                   G_TYPE_FROM_CLASS (object_class),
1051                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1052                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1053                   NULL, NULL,
1054                   _gtk_marshal_BOOLEAN__VOID,
1055                   G_TYPE_BOOLEAN, 0);
1056
1057   tree_view_signals[SELECT_CURSOR_ROW] =
1058     g_signal_new (I_("select-cursor-row"),
1059                   G_TYPE_FROM_CLASS (object_class),
1060                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1061                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1062                   NULL, NULL,
1063                   _gtk_marshal_BOOLEAN__BOOLEAN,
1064                   G_TYPE_BOOLEAN, 1,
1065                   G_TYPE_BOOLEAN);
1066
1067   tree_view_signals[TOGGLE_CURSOR_ROW] =
1068     g_signal_new (I_("toggle-cursor-row"),
1069                   G_TYPE_FROM_CLASS (object_class),
1070                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1071                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1072                   NULL, NULL,
1073                   _gtk_marshal_BOOLEAN__VOID,
1074                   G_TYPE_BOOLEAN, 0);
1075
1076   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1077     g_signal_new (I_("expand-collapse-cursor-row"),
1078                   G_TYPE_FROM_CLASS (object_class),
1079                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1080                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1081                   NULL, NULL,
1082                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1083                   G_TYPE_BOOLEAN, 3,
1084                   G_TYPE_BOOLEAN,
1085                   G_TYPE_BOOLEAN,
1086                   G_TYPE_BOOLEAN);
1087
1088   tree_view_signals[SELECT_CURSOR_PARENT] =
1089     g_signal_new (I_("select-cursor-parent"),
1090                   G_TYPE_FROM_CLASS (object_class),
1091                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1092                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1093                   NULL, NULL,
1094                   _gtk_marshal_BOOLEAN__VOID,
1095                   G_TYPE_BOOLEAN, 0);
1096
1097   tree_view_signals[START_INTERACTIVE_SEARCH] =
1098     g_signal_new (I_("start-interactive-search"),
1099                   G_TYPE_FROM_CLASS (object_class),
1100                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1101                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1102                   NULL, NULL,
1103                   _gtk_marshal_BOOLEAN__VOID,
1104                   G_TYPE_BOOLEAN, 0);
1105
1106   /* Key bindings */
1107   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
1108                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1109   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
1110                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1111
1112   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
1113                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1114   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
1115                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1116
1117   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
1118                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1119
1120   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
1121                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1122
1123   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
1124                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1125   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
1126                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1127
1128   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
1129                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1130   gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
1131                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1132
1133   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
1134                                   GTK_MOVEMENT_PAGES, -1);
1135   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
1136                                   GTK_MOVEMENT_PAGES, -1);
1137
1138   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
1139                                   GTK_MOVEMENT_PAGES, 1);
1140   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
1141                                   GTK_MOVEMENT_PAGES, 1);
1142
1143
1144   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move-cursor", 2,
1145                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1146                                 G_TYPE_INT, 1);
1147
1148   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move-cursor", 2,
1149                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1150                                 G_TYPE_INT, -1);
1151
1152   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move-cursor", 2,
1153                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1154                                 G_TYPE_INT, 1);
1155
1156   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move-cursor", 2,
1157                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1158                                 G_TYPE_INT, -1);
1159
1160   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
1161                                 "move-cursor", 2,
1162                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1163                                 G_TYPE_INT, 1);
1164
1165   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
1166                                 "move-cursor", 2,
1167                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1168                                 G_TYPE_INT, -1);
1169
1170   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1171                                 "move-cursor", 2,
1172                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1173                                 G_TYPE_INT, 1);
1174
1175   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
1176                                 "move-cursor", 2,
1177                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1178                                 G_TYPE_INT, -1);
1179
1180   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1181   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1182
1183   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0);
1184   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
1185
1186   gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1187   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1188
1189   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1190                                 G_TYPE_BOOLEAN, TRUE);
1191   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1192                                 G_TYPE_BOOLEAN, TRUE);
1193
1194   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1,
1195                                 G_TYPE_BOOLEAN, TRUE);
1196   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1,
1197                                 G_TYPE_BOOLEAN, TRUE);
1198   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1,
1199                                 G_TYPE_BOOLEAN, TRUE);
1200   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1,
1201                                 G_TYPE_BOOLEAN, TRUE);
1202   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1,
1203                                 G_TYPE_BOOLEAN, TRUE);
1204
1205   /* expand and collapse rows */
1206   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand-collapse-cursor-row", 3,
1207                                 G_TYPE_BOOLEAN, TRUE,
1208                                 G_TYPE_BOOLEAN, TRUE,
1209                                 G_TYPE_BOOLEAN, FALSE);
1210
1211   gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
1212                                 "expand-collapse-cursor-row", 3,
1213                                 G_TYPE_BOOLEAN, TRUE,
1214                                 G_TYPE_BOOLEAN, TRUE,
1215                                 G_TYPE_BOOLEAN, TRUE);
1216   gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
1217                                 "expand-collapse-cursor-row", 3,
1218                                 G_TYPE_BOOLEAN, TRUE,
1219                                 G_TYPE_BOOLEAN, TRUE,
1220                                 G_TYPE_BOOLEAN, TRUE);
1221
1222   gtk_binding_entry_add_signal (binding_set, GDK_slash, 0,
1223                                 "expand-collapse-cursor-row", 3,
1224                                 G_TYPE_BOOLEAN, TRUE,
1225                                 G_TYPE_BOOLEAN, FALSE,
1226                                 G_TYPE_BOOLEAN, FALSE);
1227   gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
1228                                 "expand-collapse-cursor-row", 3,
1229                                 G_TYPE_BOOLEAN, TRUE,
1230                                 G_TYPE_BOOLEAN, FALSE,
1231                                 G_TYPE_BOOLEAN, FALSE);
1232
1233   /* Not doable on US keyboards */
1234   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1235                                 G_TYPE_BOOLEAN, TRUE,
1236                                 G_TYPE_BOOLEAN, TRUE,
1237                                 G_TYPE_BOOLEAN, TRUE);
1238   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand-collapse-cursor-row", 3,
1239                                 G_TYPE_BOOLEAN, TRUE,
1240                                 G_TYPE_BOOLEAN, TRUE,
1241                                 G_TYPE_BOOLEAN, FALSE);
1242   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1243                                 G_TYPE_BOOLEAN, TRUE,
1244                                 G_TYPE_BOOLEAN, TRUE,
1245                                 G_TYPE_BOOLEAN, TRUE);
1246   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1247                                 G_TYPE_BOOLEAN, TRUE,
1248                                 G_TYPE_BOOLEAN, TRUE,
1249                                 G_TYPE_BOOLEAN, TRUE);
1250   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
1251                                 "expand-collapse-cursor-row", 3,
1252                                 G_TYPE_BOOLEAN, FALSE,
1253                                 G_TYPE_BOOLEAN, TRUE,
1254                                 G_TYPE_BOOLEAN, TRUE);
1255   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
1256                                 "expand-collapse-cursor-row", 3,
1257                                 G_TYPE_BOOLEAN, FALSE,
1258                                 G_TYPE_BOOLEAN, TRUE,
1259                                 G_TYPE_BOOLEAN, TRUE);
1260   gtk_binding_entry_add_signal (binding_set, GDK_Right,
1261                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1262                                 "expand-collapse-cursor-row", 3,
1263                                 G_TYPE_BOOLEAN, FALSE,
1264                                 G_TYPE_BOOLEAN, TRUE,
1265                                 G_TYPE_BOOLEAN, TRUE);
1266   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
1267                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1268                                 "expand-collapse-cursor-row", 3,
1269                                 G_TYPE_BOOLEAN, FALSE,
1270                                 G_TYPE_BOOLEAN, TRUE,
1271                                 G_TYPE_BOOLEAN, TRUE);
1272
1273   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand-collapse-cursor-row", 3,
1274                                 G_TYPE_BOOLEAN, TRUE,
1275                                 G_TYPE_BOOLEAN, FALSE,
1276                                 G_TYPE_BOOLEAN, FALSE);
1277   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1278                                 G_TYPE_BOOLEAN, TRUE,
1279                                 G_TYPE_BOOLEAN, FALSE,
1280                                 G_TYPE_BOOLEAN, TRUE);
1281   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1282                                 G_TYPE_BOOLEAN, TRUE,
1283                                 G_TYPE_BOOLEAN, FALSE,
1284                                 G_TYPE_BOOLEAN, FALSE);
1285   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1286                                 G_TYPE_BOOLEAN, TRUE,
1287                                 G_TYPE_BOOLEAN, FALSE,
1288                                 G_TYPE_BOOLEAN, TRUE);
1289   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
1290                                 "expand-collapse-cursor-row", 3,
1291                                 G_TYPE_BOOLEAN, FALSE,
1292                                 G_TYPE_BOOLEAN, FALSE,
1293                                 G_TYPE_BOOLEAN, TRUE);
1294   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
1295                                 "expand-collapse-cursor-row", 3,
1296                                 G_TYPE_BOOLEAN, FALSE,
1297                                 G_TYPE_BOOLEAN, FALSE,
1298                                 G_TYPE_BOOLEAN, TRUE);
1299   gtk_binding_entry_add_signal (binding_set, GDK_Left,
1300                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1301                                 "expand-collapse-cursor-row", 3,
1302                                 G_TYPE_BOOLEAN, FALSE,
1303                                 G_TYPE_BOOLEAN, FALSE,
1304                                 G_TYPE_BOOLEAN, TRUE);
1305   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
1306                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1307                                 "expand-collapse-cursor-row", 3,
1308                                 G_TYPE_BOOLEAN, FALSE,
1309                                 G_TYPE_BOOLEAN, FALSE,
1310                                 G_TYPE_BOOLEAN, TRUE);
1311
1312   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0);
1313   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1314
1315   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1316
1317   gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1318
1319   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1320 }
1321
1322 static void
1323 gtk_tree_view_init (GtkTreeView *tree_view)
1324 {
1325   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1326
1327   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1328   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1329
1330   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1331                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1332                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1333
1334   /* We need some padding */
1335   tree_view->priv->dy = 0;
1336   tree_view->priv->cursor_offset = 0;
1337   tree_view->priv->n_columns = 0;
1338   tree_view->priv->header_height = 1;
1339   tree_view->priv->x_drag = 0;
1340   tree_view->priv->drag_pos = -1;
1341   tree_view->priv->header_has_focus = FALSE;
1342   tree_view->priv->pressed_button = -1;
1343   tree_view->priv->press_start_x = -1;
1344   tree_view->priv->press_start_y = -1;
1345   tree_view->priv->reorderable = FALSE;
1346   tree_view->priv->presize_handler_timer = 0;
1347   tree_view->priv->scroll_sync_timer = 0;
1348   tree_view->priv->fixed_height = -1;
1349   tree_view->priv->fixed_height_mode = FALSE;
1350   tree_view->priv->fixed_height_check = 0;
1351   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1352   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1353   tree_view->priv->enable_search = TRUE;
1354   tree_view->priv->search_column = -1;
1355   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1356   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1357   tree_view->priv->search_custom_entry_set = FALSE;
1358   tree_view->priv->typeselect_flush_timeout = 0;
1359   tree_view->priv->init_hadjust_value = TRUE;    
1360   tree_view->priv->width = 0;
1361           
1362   tree_view->priv->hover_selection = FALSE;
1363   tree_view->priv->hover_expand = FALSE;
1364
1365   tree_view->priv->level_indentation = 0;
1366
1367   tree_view->priv->rubber_banding_enable = FALSE;
1368
1369   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1370   tree_view->priv->tree_lines_enabled = FALSE;
1371
1372   tree_view->priv->tooltip_column = -1;
1373
1374   tree_view->priv->post_validation_flag = FALSE;
1375
1376   tree_view->priv->last_button_x = -1;
1377   tree_view->priv->last_button_y = -1;
1378
1379   tree_view->priv->event_last_x = -10000;
1380   tree_view->priv->event_last_y = -10000;
1381 }
1382
1383 \f
1384
1385 /* GObject Methods
1386  */
1387
1388 static void
1389 gtk_tree_view_set_property (GObject         *object,
1390                             guint            prop_id,
1391                             const GValue    *value,
1392                             GParamSpec      *pspec)
1393 {
1394   GtkTreeView *tree_view;
1395
1396   tree_view = GTK_TREE_VIEW (object);
1397
1398   switch (prop_id)
1399     {
1400     case PROP_MODEL:
1401       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1402       break;
1403     case PROP_HADJUSTMENT:
1404       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1405       break;
1406     case PROP_VADJUSTMENT:
1407       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1408       break;
1409     case PROP_HEADERS_VISIBLE:
1410       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1411       break;
1412     case PROP_HEADERS_CLICKABLE:
1413       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1414       break;
1415     case PROP_EXPANDER_COLUMN:
1416       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1417       break;
1418     case PROP_REORDERABLE:
1419       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1420       break;
1421     case PROP_RULES_HINT:
1422       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1423       break;
1424     case PROP_ENABLE_SEARCH:
1425       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1426       break;
1427     case PROP_SEARCH_COLUMN:
1428       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1429       break;
1430     case PROP_FIXED_HEIGHT_MODE:
1431       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1432       break;
1433     case PROP_HOVER_SELECTION:
1434       tree_view->priv->hover_selection = g_value_get_boolean (value);
1435       break;
1436     case PROP_HOVER_EXPAND:
1437       tree_view->priv->hover_expand = g_value_get_boolean (value);
1438       break;
1439     case PROP_SHOW_EXPANDERS:
1440       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1441       break;
1442     case PROP_LEVEL_INDENTATION:
1443       tree_view->priv->level_indentation = g_value_get_int (value);
1444       break;
1445     case PROP_RUBBER_BANDING:
1446       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1447       break;
1448     case PROP_ENABLE_GRID_LINES:
1449       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1450       break;
1451     case PROP_ENABLE_TREE_LINES:
1452       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1453       break;
1454     case PROP_TOOLTIP_COLUMN:
1455       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1456       break;
1457     default:
1458       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1459       break;
1460     }
1461 }
1462
1463 static void
1464 gtk_tree_view_get_property (GObject    *object,
1465                             guint       prop_id,
1466                             GValue     *value,
1467                             GParamSpec *pspec)
1468 {
1469   GtkTreeView *tree_view;
1470
1471   tree_view = GTK_TREE_VIEW (object);
1472
1473   switch (prop_id)
1474     {
1475     case PROP_MODEL:
1476       g_value_set_object (value, tree_view->priv->model);
1477       break;
1478     case PROP_HADJUSTMENT:
1479       g_value_set_object (value, tree_view->priv->hadjustment);
1480       break;
1481     case PROP_VADJUSTMENT:
1482       g_value_set_object (value, tree_view->priv->vadjustment);
1483       break;
1484     case PROP_HEADERS_VISIBLE:
1485       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1486       break;
1487     case PROP_HEADERS_CLICKABLE:
1488       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1489       break;
1490     case PROP_EXPANDER_COLUMN:
1491       g_value_set_object (value, tree_view->priv->expander_column);
1492       break;
1493     case PROP_REORDERABLE:
1494       g_value_set_boolean (value, tree_view->priv->reorderable);
1495       break;
1496     case PROP_RULES_HINT:
1497       g_value_set_boolean (value, tree_view->priv->has_rules);
1498       break;
1499     case PROP_ENABLE_SEARCH:
1500       g_value_set_boolean (value, tree_view->priv->enable_search);
1501       break;
1502     case PROP_SEARCH_COLUMN:
1503       g_value_set_int (value, tree_view->priv->search_column);
1504       break;
1505     case PROP_FIXED_HEIGHT_MODE:
1506       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1507       break;
1508     case PROP_HOVER_SELECTION:
1509       g_value_set_boolean (value, tree_view->priv->hover_selection);
1510       break;
1511     case PROP_HOVER_EXPAND:
1512       g_value_set_boolean (value, tree_view->priv->hover_expand);
1513       break;
1514     case PROP_SHOW_EXPANDERS:
1515       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1516       break;
1517     case PROP_LEVEL_INDENTATION:
1518       g_value_set_int (value, tree_view->priv->level_indentation);
1519       break;
1520     case PROP_RUBBER_BANDING:
1521       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1522       break;
1523     case PROP_ENABLE_GRID_LINES:
1524       g_value_set_enum (value, tree_view->priv->grid_lines);
1525       break;
1526     case PROP_ENABLE_TREE_LINES:
1527       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1528       break;
1529     case PROP_TOOLTIP_COLUMN:
1530       g_value_set_int (value, tree_view->priv->tooltip_column);
1531       break;
1532     default:
1533       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1534       break;
1535     }
1536 }
1537
1538 static void
1539 gtk_tree_view_finalize (GObject *object)
1540 {
1541   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1542 }
1543
1544
1545 static GtkBuildableIface *parent_buildable_iface;
1546
1547 static void
1548 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1549 {
1550   parent_buildable_iface = g_type_interface_peek_parent (iface);
1551   iface->add_child = gtk_tree_view_buildable_add_child;
1552   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1553 }
1554
1555 static void
1556 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1557                                    GtkBuilder  *builder,
1558                                    GObject     *child,
1559                                    const gchar *type)
1560 {
1561   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1562 }
1563
1564 static GObject *
1565 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1566                                             GtkBuilder        *builder,
1567                                             const gchar       *childname)
1568 {
1569     if (strcmp (childname, "selection") == 0)
1570       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1571     
1572     return parent_buildable_iface->get_internal_child (buildable,
1573                                                        builder,
1574                                                        childname);
1575 }
1576
1577 /* GtkObject Methods
1578  */
1579
1580 static void
1581 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1582 {
1583   _gtk_rbtree_free (tree_view->priv->tree);
1584   
1585   tree_view->priv->tree = NULL;
1586   tree_view->priv->button_pressed_node = NULL;
1587   tree_view->priv->button_pressed_tree = NULL;
1588   tree_view->priv->prelight_tree = NULL;
1589   tree_view->priv->prelight_node = NULL;
1590   tree_view->priv->expanded_collapsed_node = NULL;
1591   tree_view->priv->expanded_collapsed_tree = NULL;
1592 }
1593
1594 static void
1595 gtk_tree_view_destroy (GtkObject *object)
1596 {
1597   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1598   GList *list;
1599
1600   gtk_tree_view_stop_editing (tree_view, TRUE);
1601
1602   if (tree_view->priv->columns != NULL)
1603     {
1604       list = tree_view->priv->columns;
1605       while (list)
1606         {
1607           GtkTreeViewColumn *column;
1608           column = GTK_TREE_VIEW_COLUMN (list->data);
1609           list = list->next;
1610           gtk_tree_view_remove_column (tree_view, column);
1611         }
1612       tree_view->priv->columns = NULL;
1613     }
1614
1615   if (tree_view->priv->tree != NULL)
1616     {
1617       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1618
1619       gtk_tree_view_free_rbtree (tree_view);
1620     }
1621
1622   if (tree_view->priv->selection != NULL)
1623     {
1624       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1625       g_object_unref (tree_view->priv->selection);
1626       tree_view->priv->selection = NULL;
1627     }
1628
1629   if (tree_view->priv->scroll_to_path != NULL)
1630     {
1631       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1632       tree_view->priv->scroll_to_path = NULL;
1633     }
1634
1635   if (tree_view->priv->drag_dest_row != NULL)
1636     {
1637       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1638       tree_view->priv->drag_dest_row = NULL;
1639     }
1640
1641   if (tree_view->priv->top_row != NULL)
1642     {
1643       gtk_tree_row_reference_free (tree_view->priv->top_row);
1644       tree_view->priv->top_row = NULL;
1645     }
1646
1647   if (tree_view->priv->column_drop_func_data &&
1648       tree_view->priv->column_drop_func_data_destroy)
1649     {
1650       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1651       tree_view->priv->column_drop_func_data = NULL;
1652     }
1653
1654   if (tree_view->priv->destroy_count_destroy &&
1655       tree_view->priv->destroy_count_data)
1656     {
1657       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1658       tree_view->priv->destroy_count_data = NULL;
1659     }
1660
1661   gtk_tree_row_reference_free (tree_view->priv->cursor);
1662   tree_view->priv->cursor = NULL;
1663
1664   gtk_tree_row_reference_free (tree_view->priv->anchor);
1665   tree_view->priv->anchor = NULL;
1666
1667   /* destroy interactive search dialog */
1668   if (tree_view->priv->search_window)
1669     {
1670       gtk_widget_destroy (tree_view->priv->search_window);
1671       tree_view->priv->search_window = NULL;
1672       tree_view->priv->search_entry = NULL;
1673       if (tree_view->priv->typeselect_flush_timeout)
1674         {
1675           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1676           tree_view->priv->typeselect_flush_timeout = 0;
1677         }
1678     }
1679
1680   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1681     {
1682       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1683       tree_view->priv->search_user_data = NULL;
1684     }
1685
1686   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1687     {
1688       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1689       tree_view->priv->search_position_user_data = NULL;
1690     }
1691
1692   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1693     {
1694       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1695       tree_view->priv->row_separator_data = NULL;
1696     }
1697   
1698   gtk_tree_view_set_model (tree_view, NULL);
1699
1700   if (tree_view->priv->hadjustment)
1701     {
1702       g_object_unref (tree_view->priv->hadjustment);
1703       tree_view->priv->hadjustment = NULL;
1704     }
1705   if (tree_view->priv->vadjustment)
1706     {
1707       g_object_unref (tree_view->priv->vadjustment);
1708       tree_view->priv->vadjustment = NULL;
1709     }
1710
1711   GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy (object);
1712 }
1713
1714 \f
1715
1716 /* GtkWidget Methods
1717  */
1718
1719 /* GtkWidget::map helper */
1720 static void
1721 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1722 {
1723   GList *list;
1724
1725   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
1726
1727   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1728     {
1729       GtkTreeViewColumn *column;
1730
1731       for (list = tree_view->priv->columns; list; list = list->next)
1732         {
1733           column = list->data;
1734           if (gtk_widget_get_visible (column->button) &&
1735               !gtk_widget_get_mapped (column->button))
1736             gtk_widget_map (column->button);
1737         }
1738       for (list = tree_view->priv->columns; list; list = list->next)
1739         {
1740           column = list->data;
1741           if (column->visible == FALSE)
1742             continue;
1743           if (column->resizable)
1744             {
1745               gdk_window_raise (column->window);
1746               gdk_window_show (column->window);
1747             }
1748           else
1749             gdk_window_hide (column->window);
1750         }
1751       gdk_window_show (tree_view->priv->header_window);
1752     }
1753 }
1754
1755 static void
1756 gtk_tree_view_map (GtkWidget *widget)
1757 {
1758   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1759   GList *tmp_list;
1760
1761   gtk_widget_set_mapped (widget, TRUE);
1762
1763   tmp_list = tree_view->priv->children;
1764   while (tmp_list)
1765     {
1766       GtkTreeViewChild *child = tmp_list->data;
1767       tmp_list = tmp_list->next;
1768
1769       if (gtk_widget_get_visible (child->widget))
1770         {
1771           if (!gtk_widget_get_mapped (child->widget))
1772             gtk_widget_map (child->widget);
1773         }
1774     }
1775   gdk_window_show (tree_view->priv->bin_window);
1776
1777   gtk_tree_view_map_buttons (tree_view);
1778
1779   gdk_window_show (widget->window);
1780 }
1781
1782 static void
1783 gtk_tree_view_realize (GtkWidget *widget)
1784 {
1785   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1786   GList *tmp_list;
1787   GdkWindowAttr attributes;
1788   gint attributes_mask;
1789
1790   gtk_widget_set_realized (widget, TRUE);
1791
1792   /* Make the main, clipping window */
1793   attributes.window_type = GDK_WINDOW_CHILD;
1794   attributes.x = widget->allocation.x;
1795   attributes.y = widget->allocation.y;
1796   attributes.width = widget->allocation.width;
1797   attributes.height = widget->allocation.height;
1798   attributes.wclass = GDK_INPUT_OUTPUT;
1799   attributes.visual = gtk_widget_get_visual (widget);
1800   attributes.colormap = gtk_widget_get_colormap (widget);
1801   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1802
1803   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1804
1805   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1806                                    &attributes, attributes_mask);
1807   gdk_window_set_user_data (widget->window, widget);
1808
1809   /* Make the window for the tree */
1810   attributes.x = 0;
1811   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1812   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1813   attributes.height = widget->allocation.height;
1814   attributes.event_mask = (GDK_EXPOSURE_MASK |
1815                            GDK_SCROLL_MASK |
1816                            GDK_POINTER_MOTION_MASK |
1817                            GDK_ENTER_NOTIFY_MASK |
1818                            GDK_LEAVE_NOTIFY_MASK |
1819                            GDK_BUTTON_PRESS_MASK |
1820                            GDK_BUTTON_RELEASE_MASK |
1821                            gtk_widget_get_events (widget));
1822
1823   tree_view->priv->bin_window = gdk_window_new (widget->window,
1824                                                 &attributes, attributes_mask);
1825   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1826
1827   /* Make the column header window */
1828   attributes.x = 0;
1829   attributes.y = 0;
1830   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1831   attributes.height = tree_view->priv->header_height;
1832   attributes.event_mask = (GDK_EXPOSURE_MASK |
1833                            GDK_SCROLL_MASK |
1834                            GDK_ENTER_NOTIFY_MASK |
1835                            GDK_LEAVE_NOTIFY_MASK |
1836                            GDK_BUTTON_PRESS_MASK |
1837                            GDK_BUTTON_RELEASE_MASK |
1838                            GDK_KEY_PRESS_MASK |
1839                            GDK_KEY_RELEASE_MASK |
1840                            gtk_widget_get_events (widget));
1841
1842   tree_view->priv->header_window = gdk_window_new (widget->window,
1843                                                    &attributes, attributes_mask);
1844   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1845
1846   /* Add them all up. */
1847   widget->style = gtk_style_attach (widget->style, widget->window);
1848   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1849   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1850   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1851
1852   tmp_list = tree_view->priv->children;
1853   while (tmp_list)
1854     {
1855       GtkTreeViewChild *child = tmp_list->data;
1856       tmp_list = tmp_list->next;
1857
1858       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1859     }
1860
1861   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1862     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1863
1864   /* Need to call those here, since they create GCs */
1865   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1866   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1867
1868   install_presize_handler (tree_view); 
1869 }
1870
1871 static void
1872 gtk_tree_view_unrealize (GtkWidget *widget)
1873 {
1874   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1875   GtkTreeViewPrivate *priv = tree_view->priv;
1876   GList *list;
1877
1878   if (priv->scroll_timeout != 0)
1879     {
1880       g_source_remove (priv->scroll_timeout);
1881       priv->scroll_timeout = 0;
1882     }
1883
1884   if (priv->auto_expand_timeout != 0)
1885     {
1886       g_source_remove (priv->auto_expand_timeout);
1887       priv->auto_expand_timeout = 0;
1888     }
1889
1890   if (priv->open_dest_timeout != 0)
1891     {
1892       g_source_remove (priv->open_dest_timeout);
1893       priv->open_dest_timeout = 0;
1894     }
1895
1896   remove_expand_collapse_timeout (tree_view);
1897   
1898   if (priv->presize_handler_timer != 0)
1899     {
1900       g_source_remove (priv->presize_handler_timer);
1901       priv->presize_handler_timer = 0;
1902     }
1903
1904   if (priv->validate_rows_timer != 0)
1905     {
1906       g_source_remove (priv->validate_rows_timer);
1907       priv->validate_rows_timer = 0;
1908     }
1909
1910   if (priv->scroll_sync_timer != 0)
1911     {
1912       g_source_remove (priv->scroll_sync_timer);
1913       priv->scroll_sync_timer = 0;
1914     }
1915
1916   if (priv->typeselect_flush_timeout)
1917     {
1918       g_source_remove (priv->typeselect_flush_timeout);
1919       priv->typeselect_flush_timeout = 0;
1920     }
1921   
1922   for (list = priv->columns; list; list = list->next)
1923     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1924
1925   gdk_window_set_user_data (priv->bin_window, NULL);
1926   gdk_window_destroy (priv->bin_window);
1927   priv->bin_window = NULL;
1928
1929   gdk_window_set_user_data (priv->header_window, NULL);
1930   gdk_window_destroy (priv->header_window);
1931   priv->header_window = NULL;
1932
1933   if (priv->drag_window)
1934     {
1935       gdk_window_set_user_data (priv->drag_window, NULL);
1936       gdk_window_destroy (priv->drag_window);
1937       priv->drag_window = NULL;
1938     }
1939
1940   if (priv->drag_highlight_window)
1941     {
1942       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1943       gdk_window_destroy (priv->drag_highlight_window);
1944       priv->drag_highlight_window = NULL;
1945     }
1946
1947   if (priv->tree_line_gc)
1948     {
1949       g_object_unref (priv->tree_line_gc);
1950       priv->tree_line_gc = NULL;
1951     }
1952
1953   if (priv->grid_line_gc)
1954     {
1955       g_object_unref (priv->grid_line_gc);
1956       priv->grid_line_gc = NULL;
1957     }
1958
1959   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1960 }
1961
1962 /* GtkWidget::size_request helper */
1963 static void
1964 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1965 {
1966   GList *list;
1967
1968   tree_view->priv->header_height = 0;
1969
1970   if (tree_view->priv->model)
1971     {
1972       for (list = tree_view->priv->columns; list; list = list->next)
1973         {
1974           GtkRequisition requisition;
1975           GtkTreeViewColumn *column = list->data;
1976
1977           if (column->button == NULL)
1978             continue;
1979
1980           column = list->data;
1981           
1982           gtk_widget_size_request (column->button, &requisition);
1983           column->button_request = requisition.width;
1984           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1985         }
1986     }
1987 }
1988
1989
1990 /* Called only by ::size_request */
1991 static void
1992 gtk_tree_view_update_size (GtkTreeView *tree_view)
1993 {
1994   GList *list;
1995   GtkTreeViewColumn *column;
1996   gint i;
1997
1998   if (tree_view->priv->model == NULL)
1999     {
2000       tree_view->priv->width = 0;
2001       tree_view->priv->prev_width = 0;                   
2002       tree_view->priv->height = 0;
2003       return;
2004     }
2005
2006   tree_view->priv->prev_width = tree_view->priv->width;  
2007   tree_view->priv->width = 0;
2008
2009   /* keep this in sync with size_allocate below */
2010   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2011     {
2012       gint real_requested_width = 0;
2013       column = list->data;
2014       if (!column->visible)
2015         continue;
2016
2017       if (column->use_resized_width)
2018         {
2019           real_requested_width = column->resized_width;
2020         }
2021       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2022         {
2023           real_requested_width = column->fixed_width;
2024         }
2025       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2026         {
2027           real_requested_width = MAX (column->requested_width, column->button_request);
2028         }
2029       else
2030         {
2031           real_requested_width = column->requested_width;
2032         }
2033
2034       if (column->min_width != -1)
2035         real_requested_width = MAX (real_requested_width, column->min_width);
2036       if (column->max_width != -1)
2037         real_requested_width = MIN (real_requested_width, column->max_width);
2038
2039       tree_view->priv->width += real_requested_width;
2040     }
2041
2042   if (tree_view->priv->tree == NULL)
2043     tree_view->priv->height = 0;
2044   else
2045     tree_view->priv->height = tree_view->priv->tree->root->offset;
2046 }
2047
2048 static void
2049 gtk_tree_view_size_request (GtkWidget      *widget,
2050                             GtkRequisition *requisition)
2051 {
2052   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2053   GList *tmp_list;
2054
2055   /* we validate some rows initially just to make sure we have some size. 
2056    * In practice, with a lot of static lists, this should get a good width.
2057    */
2058   do_validate_rows (tree_view, FALSE);
2059   gtk_tree_view_size_request_columns (tree_view);
2060   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2061
2062   requisition->width = tree_view->priv->width;
2063   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2064
2065   tmp_list = tree_view->priv->children;
2066
2067   while (tmp_list)
2068     {
2069       GtkTreeViewChild *child = tmp_list->data;
2070       GtkRequisition child_requisition;
2071
2072       tmp_list = tmp_list->next;
2073
2074       if (gtk_widget_get_visible (child->widget))
2075         gtk_widget_size_request (child->widget, &child_requisition);
2076     }
2077 }
2078
2079 static int
2080 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2081 {
2082   int width = 0;
2083   GList *list;
2084   gboolean rtl;
2085
2086   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2087   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2088        list->data != tree_view->priv->expander_column;
2089        list = (rtl ? list->prev : list->next))
2090     {
2091       GtkTreeViewColumn *column = list->data;
2092
2093       width += column->width;
2094     }
2095
2096   return width;
2097 }
2098
2099 static void
2100 invalidate_column (GtkTreeView       *tree_view,
2101                    GtkTreeViewColumn *column)
2102 {
2103   gint column_offset = 0;
2104   GList *list;
2105   GtkWidget *widget = GTK_WIDGET (tree_view);
2106   gboolean rtl;
2107
2108   if (!gtk_widget_get_realized (widget))
2109     return;
2110
2111   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2112   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2113        list;
2114        list = (rtl ? list->prev : list->next))
2115     {
2116       GtkTreeViewColumn *tmpcolumn = list->data;
2117       if (tmpcolumn == column)
2118         {
2119           GdkRectangle invalid_rect;
2120           
2121           invalid_rect.x = column_offset;
2122           invalid_rect.y = 0;
2123           invalid_rect.width = column->width;
2124           invalid_rect.height = widget->allocation.height;
2125           
2126           gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
2127           break;
2128         }
2129       
2130       column_offset += tmpcolumn->width;
2131     }
2132 }
2133
2134 static void
2135 invalidate_last_column (GtkTreeView *tree_view)
2136 {
2137   GList *last_column;
2138   gboolean rtl;
2139
2140   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2141
2142   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2143        last_column;
2144        last_column = (rtl ? last_column->next : last_column->prev))
2145     {
2146       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2147         {
2148           invalidate_column (tree_view, last_column->data);
2149           return;
2150         }
2151     }
2152 }
2153
2154 static gint
2155 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2156                                                     GtkTreeViewColumn *column)
2157 {
2158   gint real_requested_width;
2159
2160   if (column->use_resized_width)
2161     {
2162       real_requested_width = column->resized_width;
2163     }
2164   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2165     {
2166       real_requested_width = column->fixed_width;
2167     }
2168   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2169     {
2170       real_requested_width = MAX (column->requested_width, column->button_request);
2171     }
2172   else
2173     {
2174       real_requested_width = column->requested_width;
2175       if (real_requested_width < 0)
2176         real_requested_width = 0;
2177     }
2178
2179   if (column->min_width != -1)
2180     real_requested_width = MAX (real_requested_width, column->min_width);
2181   if (column->max_width != -1)
2182     real_requested_width = MIN (real_requested_width, column->max_width);
2183
2184   return real_requested_width;
2185 }
2186
2187 /* GtkWidget::size_allocate helper */
2188 static void
2189 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2190                                      gboolean  *width_changed)
2191 {
2192   GtkTreeView *tree_view;
2193   GList *list, *first_column, *last_column;
2194   GtkTreeViewColumn *column;
2195   GtkAllocation allocation;
2196   gint width = 0;
2197   gint extra, extra_per_column, extra_for_last;
2198   gint full_requested_width = 0;
2199   gint number_of_expand_columns = 0;
2200   gboolean column_changed = FALSE;
2201   gboolean rtl;
2202   gboolean update_expand;
2203   
2204   tree_view = GTK_TREE_VIEW (widget);
2205
2206   for (last_column = g_list_last (tree_view->priv->columns);
2207        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2208        last_column = last_column->prev)
2209     ;
2210   if (last_column == NULL)
2211     return;
2212
2213   for (first_column = g_list_first (tree_view->priv->columns);
2214        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2215        first_column = first_column->next)
2216     ;
2217
2218   allocation.y = 0;
2219   allocation.height = tree_view->priv->header_height;
2220
2221   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2222
2223   /* find out how many extra space and expandable columns we have */
2224   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2225     {
2226       column = (GtkTreeViewColumn *)list->data;
2227
2228       if (!column->visible)
2229         continue;
2230
2231       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2232
2233       if (column->expand)
2234         number_of_expand_columns++;
2235     }
2236
2237   /* Only update the expand value if the width of the widget has changed,
2238    * or the number of expand columns has changed, or if there are no expand
2239    * columns, or if we didn't have an size-allocation yet after the
2240    * last validated node.
2241    */
2242   update_expand = (width_changed && *width_changed == TRUE)
2243       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2244       || number_of_expand_columns == 0
2245       || tree_view->priv->post_validation_flag == TRUE;
2246
2247   tree_view->priv->post_validation_flag = FALSE;
2248
2249   if (!update_expand)
2250     {
2251       extra = tree_view->priv->last_extra_space;
2252       extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
2253     }
2254   else
2255     {
2256       extra = MAX (widget->allocation.width - full_requested_width, 0);
2257       extra_for_last = 0;
2258
2259       tree_view->priv->last_extra_space = extra;
2260     }
2261
2262   if (number_of_expand_columns > 0)
2263     extra_per_column = extra/number_of_expand_columns;
2264   else
2265     extra_per_column = 0;
2266
2267   if (update_expand)
2268     {
2269       tree_view->priv->last_extra_space_per_column = extra_per_column;
2270       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2271     }
2272
2273   for (list = (rtl ? last_column : first_column); 
2274        list != (rtl ? first_column->prev : last_column->next);
2275        list = (rtl ? list->prev : list->next)) 
2276     {
2277       gint real_requested_width = 0;
2278       gint old_width;
2279
2280       column = list->data;
2281       old_width = column->width;
2282
2283       if (!column->visible)
2284         continue;
2285
2286       /* We need to handle the dragged button specially.
2287        */
2288       if (column == tree_view->priv->drag_column)
2289         {
2290           GtkAllocation drag_allocation;
2291           gdk_drawable_get_size (tree_view->priv->drag_window,
2292                                  &(drag_allocation.width),
2293                                  &(drag_allocation.height));
2294           drag_allocation.x = 0;
2295           drag_allocation.y = 0;
2296           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2297                                     &drag_allocation);
2298           width += drag_allocation.width;
2299           continue;
2300         }
2301
2302       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2303
2304       allocation.x = width;
2305       column->width = real_requested_width;
2306
2307       if (column->expand)
2308         {
2309           if (number_of_expand_columns == 1)
2310             {
2311               /* We add the remander to the last column as
2312                * */
2313               column->width += extra;
2314             }
2315           else
2316             {
2317               column->width += extra_per_column;
2318               extra -= extra_per_column;
2319               number_of_expand_columns --;
2320             }
2321         }
2322       else if (number_of_expand_columns == 0 &&
2323                list == last_column)
2324         {
2325           column->width += extra;
2326         }
2327
2328       /* In addition to expand, the last column can get even more
2329        * extra space so all available space is filled up.
2330        */
2331       if (extra_for_last > 0 && list == last_column)
2332         column->width += extra_for_last;
2333
2334       g_object_notify (G_OBJECT (column), "width");
2335
2336       allocation.width = column->width;
2337       width += column->width;
2338
2339       if (column->width > old_width)
2340         column_changed = TRUE;
2341
2342       gtk_widget_size_allocate (column->button, &allocation);
2343
2344       if (column->window)
2345         gdk_window_move_resize (column->window,
2346                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2347                                 allocation.y,
2348                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2349     }
2350
2351   /* We change the width here.  The user might have been resizing columns,
2352    * so the total width of the tree view changes.
2353    */
2354   tree_view->priv->width = width;
2355   if (width_changed)
2356     *width_changed = TRUE;
2357
2358   if (column_changed)
2359     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2360 }
2361
2362
2363 static void
2364 gtk_tree_view_size_allocate (GtkWidget     *widget,
2365                              GtkAllocation *allocation)
2366 {
2367   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2368   GList *tmp_list;
2369   gboolean width_changed = FALSE;
2370   gint old_width = widget->allocation.width;
2371
2372   if (allocation->width != widget->allocation.width)
2373     width_changed = TRUE;
2374
2375   widget->allocation = *allocation;
2376
2377   tmp_list = tree_view->priv->children;
2378
2379   while (tmp_list)
2380     {
2381       GtkAllocation allocation;
2382
2383       GtkTreeViewChild *child = tmp_list->data;
2384       tmp_list = tmp_list->next;
2385
2386       /* totally ignore our child's requisition */
2387       allocation.x = child->x;
2388       allocation.y = child->y;
2389       allocation.width = child->width;
2390       allocation.height = child->height;
2391       gtk_widget_size_allocate (child->widget, &allocation);
2392     }
2393
2394   /* We size-allocate the columns first because the width of the
2395    * tree view (used in updating the adjustments below) might change.
2396    */
2397   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2398
2399   tree_view->priv->hadjustment->page_size = allocation->width;
2400   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2401   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2402   tree_view->priv->hadjustment->lower = 0;
2403   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2404
2405   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2406     {
2407       if (allocation->width < tree_view->priv->width)
2408         {
2409           if (tree_view->priv->init_hadjust_value)
2410             {
2411               tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2412               tree_view->priv->init_hadjust_value = FALSE;
2413             }
2414           else if (allocation->width != old_width)
2415             {
2416               tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2417             }
2418           else
2419             tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value), 0, tree_view->priv->width - allocation->width);
2420         }
2421       else
2422         {
2423           tree_view->priv->hadjustment->value = 0;
2424           tree_view->priv->init_hadjust_value = TRUE;
2425         }
2426     }
2427   else
2428     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2429       tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2430
2431   gtk_adjustment_changed (tree_view->priv->hadjustment);
2432
2433   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2434   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2435   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2436   tree_view->priv->vadjustment->lower = 0;
2437   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2438
2439   gtk_adjustment_changed (tree_view->priv->vadjustment);
2440
2441   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2442   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2443     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2444   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2445     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2446                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2447   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2448     gtk_tree_view_top_row_to_dy (tree_view);
2449   else
2450     gtk_tree_view_dy_to_top_row (tree_view);
2451   
2452   if (gtk_widget_get_realized (widget))
2453     {
2454       gdk_window_move_resize (widget->window,
2455                               allocation->x, allocation->y,
2456                               allocation->width, allocation->height);
2457       gdk_window_move_resize (tree_view->priv->header_window,
2458                               - (gint) tree_view->priv->hadjustment->value,
2459                               0,
2460                               MAX (tree_view->priv->width, allocation->width),
2461                               tree_view->priv->header_height);
2462       gdk_window_move_resize (tree_view->priv->bin_window,
2463                               - (gint) tree_view->priv->hadjustment->value,
2464                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2465                               MAX (tree_view->priv->width, allocation->width),
2466                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2467     }
2468
2469   if (tree_view->priv->tree == NULL)
2470     invalidate_empty_focus (tree_view);
2471
2472   if (gtk_widget_get_realized (widget))
2473     {
2474       gboolean has_expand_column = FALSE;
2475       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2476         {
2477           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2478             {
2479               has_expand_column = TRUE;
2480               break;
2481             }
2482         }
2483
2484       if (width_changed && tree_view->priv->expander_column)
2485         {
2486           /* Might seem awkward, but is the best heuristic I could come up
2487            * with.  Only if the width of the columns before the expander
2488            * changes, we will update the prelight status.  It is this
2489            * width that makes the expander move vertically.  Always updating
2490            * prelight status causes trouble with hover selections.
2491            */
2492           gint width_before_expander;
2493
2494           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2495
2496           if (tree_view->priv->prev_width_before_expander
2497               != width_before_expander)
2498               update_prelight (tree_view,
2499                                tree_view->priv->event_last_x,
2500                                tree_view->priv->event_last_y);
2501
2502           tree_view->priv->prev_width_before_expander = width_before_expander;
2503         }
2504
2505       /* This little hack only works if we have an LTR locale, and no column has the  */
2506       if (width_changed)
2507         {
2508           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2509               ! has_expand_column)
2510             invalidate_last_column (tree_view);
2511           else
2512             gtk_widget_queue_draw (widget);
2513         }
2514     }
2515 }
2516
2517 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2518 static void
2519 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2520 {
2521   GtkWidget *widget = GTK_WIDGET (tree_view);
2522
2523   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2524     gtk_widget_grab_focus (widget);
2525   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2526 }
2527
2528 static inline gboolean
2529 row_is_separator (GtkTreeView *tree_view,
2530                   GtkTreeIter *iter,
2531                   GtkTreePath *path)
2532 {
2533   gboolean is_separator = FALSE;
2534
2535   if (tree_view->priv->row_separator_func)
2536     {
2537       GtkTreeIter tmpiter;
2538
2539       if (iter)
2540         tmpiter = *iter;
2541       else
2542         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2543
2544       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2545                                                           &tmpiter,
2546                                                           tree_view->priv->row_separator_data);
2547     }
2548
2549   return is_separator;
2550 }
2551
2552 static gboolean
2553 gtk_tree_view_button_press (GtkWidget      *widget,
2554                             GdkEventButton *event)
2555 {
2556   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2557   GList *list;
2558   GtkTreeViewColumn *column = NULL;
2559   gint i;
2560   GdkRectangle background_area;
2561   GdkRectangle cell_area;
2562   gint vertical_separator;
2563   gint horizontal_separator;
2564   gboolean path_is_selectable;
2565   gboolean rtl;
2566
2567   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2568   gtk_tree_view_stop_editing (tree_view, FALSE);
2569   gtk_widget_style_get (widget,
2570                         "vertical-separator", &vertical_separator,
2571                         "horizontal-separator", &horizontal_separator,
2572                         NULL);
2573
2574
2575   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2576    * we're done handling the button press.
2577    */
2578
2579   if (event->window == tree_view->priv->bin_window)
2580     {
2581       GtkRBNode *node;
2582       GtkRBTree *tree;
2583       GtkTreePath *path;
2584       gchar *path_string;
2585       gint depth;
2586       gint new_y;
2587       gint y_offset;
2588       gint dval;
2589       gint pre_val, aft_val;
2590       GtkTreeViewColumn *column = NULL;
2591       GtkCellRenderer *focus_cell = NULL;
2592       gint column_handled_click = FALSE;
2593       gboolean row_double_click = FALSE;
2594       gboolean rtl;
2595       gboolean node_selected;
2596
2597       /* Empty tree? */
2598       if (tree_view->priv->tree == NULL)
2599         {
2600           grab_focus_and_unset_draw_keyfocus (tree_view);
2601           return TRUE;
2602         }
2603
2604       /* are we in an arrow? */
2605       if (tree_view->priv->prelight_node &&
2606           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2607           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2608         {
2609           if (event->button == 1)
2610             {
2611               gtk_grab_add (widget);
2612               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2613               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2614               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2615                                         tree_view->priv->prelight_tree,
2616                                         tree_view->priv->prelight_node,
2617                                         event->x,
2618                                         event->y);
2619             }
2620
2621           grab_focus_and_unset_draw_keyfocus (tree_view);
2622           return TRUE;
2623         }
2624
2625       /* find the node that was clicked */
2626       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2627       if (new_y < 0)
2628         new_y = 0;
2629       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2630
2631       if (node == NULL)
2632         {
2633           /* We clicked in dead space */
2634           grab_focus_and_unset_draw_keyfocus (tree_view);
2635           return TRUE;
2636         }
2637
2638       /* Get the path and the node */
2639       path = _gtk_tree_view_find_path (tree_view, tree, node);
2640       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2641
2642       if (!path_is_selectable)
2643         {
2644           gtk_tree_path_free (path);
2645           grab_focus_and_unset_draw_keyfocus (tree_view);
2646           return TRUE;
2647         }
2648
2649       depth = gtk_tree_path_get_depth (path);
2650       background_area.y = y_offset + event->y;
2651       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2652       background_area.x = 0;
2653
2654
2655       /* Let the column have a chance at selecting it. */
2656       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2657       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2658            list; list = (rtl ? list->prev : list->next))
2659         {
2660           GtkTreeViewColumn *candidate = list->data;
2661
2662           if (!candidate->visible)
2663             continue;
2664
2665           background_area.width = candidate->width;
2666           if ((background_area.x > (gint) event->x) ||
2667               (background_area.x + background_area.width <= (gint) event->x))
2668             {
2669               background_area.x += background_area.width;
2670               continue;
2671             }
2672
2673           /* we found the focus column */
2674           column = candidate;
2675           cell_area = background_area;
2676           cell_area.width -= horizontal_separator;
2677           cell_area.height -= vertical_separator;
2678           cell_area.x += horizontal_separator/2;
2679           cell_area.y += vertical_separator/2;
2680           if (gtk_tree_view_is_expander_column (tree_view, column))
2681             {
2682               if (!rtl)
2683                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2684               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2685
2686               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2687                 {
2688                   if (!rtl)
2689                     cell_area.x += depth * tree_view->priv->expander_size;
2690                   cell_area.width -= depth * tree_view->priv->expander_size;
2691                 }
2692             }
2693           break;
2694         }
2695
2696       if (column == NULL)
2697         {
2698           gtk_tree_path_free (path);
2699           grab_focus_and_unset_draw_keyfocus (tree_view);
2700           return FALSE;
2701         }
2702
2703       tree_view->priv->focus_column = column;
2704
2705       /* decide if we edit */
2706       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2707           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2708         {
2709           GtkTreePath *anchor;
2710           GtkTreeIter iter;
2711
2712           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2713           gtk_tree_view_column_cell_set_cell_data (column,
2714                                                    tree_view->priv->model,
2715                                                    &iter,
2716                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2717                                                    node->children?TRUE:FALSE);
2718
2719           if (tree_view->priv->anchor)
2720             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2721           else
2722             anchor = NULL;
2723
2724           if ((anchor && !gtk_tree_path_compare (anchor, path))
2725               || !_gtk_tree_view_column_has_editable_cell (column))
2726             {
2727               GtkCellEditable *cell_editable = NULL;
2728
2729               /* FIXME: get the right flags */
2730               guint flags = 0;
2731
2732               path_string = gtk_tree_path_to_string (path);
2733
2734               if (_gtk_tree_view_column_cell_event (column,
2735                                                     &cell_editable,
2736                                                     (GdkEvent *)event,
2737                                                     path_string,
2738                                                     &background_area,
2739                                                     &cell_area, flags))
2740                 {
2741                   if (cell_editable != NULL)
2742                     {
2743                       gint left, right;
2744                       GdkRectangle area;
2745
2746                       area = cell_area;
2747                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2748
2749                       area.x += left;
2750                       area.width -= right + left;
2751
2752                       gtk_tree_view_real_start_editing (tree_view,
2753                                                         column,
2754                                                         path,
2755                                                         cell_editable,
2756                                                         &area,
2757                                                         (GdkEvent *)event,
2758                                                         flags);
2759                       g_free (path_string);
2760                       gtk_tree_path_free (path);
2761                       gtk_tree_path_free (anchor);
2762                       return TRUE;
2763                     }
2764                   column_handled_click = TRUE;
2765                 }
2766               g_free (path_string);
2767             }
2768           if (anchor)
2769             gtk_tree_path_free (anchor);
2770         }
2771
2772       /* select */
2773       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2774       pre_val = tree_view->priv->vadjustment->value;
2775
2776       /* we only handle selection modifications on the first button press
2777        */
2778       if (event->type == GDK_BUTTON_PRESS)
2779         {
2780           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2781             tree_view->priv->ctrl_pressed = TRUE;
2782           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2783             tree_view->priv->shift_pressed = TRUE;
2784
2785           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2786           if (focus_cell)
2787             gtk_tree_view_column_focus_cell (column, focus_cell);
2788
2789           if (event->state & GDK_CONTROL_MASK)
2790             {
2791               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2792               gtk_tree_view_real_toggle_cursor_row (tree_view);
2793             }
2794           else if (event->state & GDK_SHIFT_MASK)
2795             {
2796               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2797               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2798             }
2799           else
2800             {
2801               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2802             }
2803
2804           tree_view->priv->ctrl_pressed = FALSE;
2805           tree_view->priv->shift_pressed = FALSE;
2806         }
2807
2808       /* the treeview may have been scrolled because of _set_cursor,
2809        * correct here
2810        */
2811
2812       aft_val = tree_view->priv->vadjustment->value;
2813       dval = pre_val - aft_val;
2814
2815       cell_area.y += dval;
2816       background_area.y += dval;
2817
2818       /* Save press to possibly begin a drag
2819        */
2820       if (!column_handled_click &&
2821           !tree_view->priv->in_grab &&
2822           tree_view->priv->pressed_button < 0)
2823         {
2824           tree_view->priv->pressed_button = event->button;
2825           tree_view->priv->press_start_x = event->x;
2826           tree_view->priv->press_start_y = event->y;
2827
2828           if (tree_view->priv->rubber_banding_enable
2829               && !node_selected
2830               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2831             {
2832               tree_view->priv->press_start_y += tree_view->priv->dy;
2833               tree_view->priv->rubber_band_x = event->x;
2834               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2835               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2836
2837               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2838                 tree_view->priv->rubber_band_ctrl = TRUE;
2839               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2840                 tree_view->priv->rubber_band_shift = TRUE;
2841             }
2842         }
2843
2844       /* Test if a double click happened on the same row. */
2845       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2846         {
2847           int double_click_time, double_click_distance;
2848
2849           g_object_get (gtk_settings_get_default (),
2850                         "gtk-double-click-time", &double_click_time,
2851                         "gtk-double-click-distance", &double_click_distance,
2852                         NULL);
2853
2854           /* Same conditions as _gdk_event_button_generate */
2855           if (tree_view->priv->last_button_x != -1 &&
2856               (event->time < tree_view->priv->last_button_time + double_click_time) &&
2857               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2858               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2859             {
2860               /* We do no longer compare paths of this row and the
2861                * row clicked previously.  We use the double click
2862                * distance to decide whether this is a valid click,
2863                * allowing the mouse to slightly move over another row.
2864                */
2865               row_double_click = TRUE;
2866
2867               tree_view->priv->last_button_time = 0;
2868               tree_view->priv->last_button_x = -1;
2869               tree_view->priv->last_button_y = -1;
2870             }
2871           else
2872             {
2873               tree_view->priv->last_button_time = event->time;
2874               tree_view->priv->last_button_x = event->x;
2875               tree_view->priv->last_button_y = event->y;
2876             }
2877         }
2878
2879       if (row_double_click)
2880         {
2881           gtk_grab_remove (widget);
2882           gtk_tree_view_row_activated (tree_view, path, column);
2883
2884           if (tree_view->priv->pressed_button == event->button)
2885             tree_view->priv->pressed_button = -1;
2886         }
2887
2888       gtk_tree_path_free (path);
2889
2890       /* If we activated the row through a double click we don't want to grab
2891        * focus back, as moving focus to another widget is pretty common.
2892        */
2893       if (!row_double_click)
2894         grab_focus_and_unset_draw_keyfocus (tree_view);
2895
2896       return TRUE;
2897     }
2898
2899   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2900    */
2901   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2902     {
2903       column = list->data;
2904       if (event->window == column->window &&
2905           column->resizable &&
2906           column->window)
2907         {
2908           gpointer drag_data;
2909
2910           if (event->type == GDK_2BUTTON_PRESS &&
2911               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2912             {
2913               column->use_resized_width = FALSE;
2914               _gtk_tree_view_column_autosize (tree_view, column);
2915               return TRUE;
2916             }
2917
2918           if (gdk_pointer_grab (column->window, FALSE,
2919                                 GDK_POINTER_MOTION_HINT_MASK |
2920                                 GDK_BUTTON1_MOTION_MASK |
2921                                 GDK_BUTTON_RELEASE_MASK,
2922                                 NULL, NULL, event->time))
2923             return FALSE;
2924
2925           gtk_grab_add (widget);
2926           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2927           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2928
2929           /* block attached dnd signal handler */
2930           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2931           if (drag_data)
2932             g_signal_handlers_block_matched (widget,
2933                                              G_SIGNAL_MATCH_DATA,
2934                                              0, 0, NULL, NULL,
2935                                              drag_data);
2936
2937           tree_view->priv->drag_pos = i;
2938           tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
2939
2940           if (!gtk_widget_has_focus (widget))
2941             gtk_widget_grab_focus (widget);
2942
2943           return TRUE;
2944         }
2945     }
2946   return FALSE;
2947 }
2948
2949 /* GtkWidget::button_release_event helper */
2950 static gboolean
2951 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2952                                           GdkEventButton *event)
2953 {
2954   GtkTreeView *tree_view;
2955   GList *l;
2956   gboolean rtl;
2957
2958   tree_view = GTK_TREE_VIEW (widget);
2959
2960   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2961   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2962   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2963
2964   /* Move the button back */
2965   g_object_ref (tree_view->priv->drag_column->button);
2966   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2967   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2968   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2969   g_object_unref (tree_view->priv->drag_column->button);
2970   gtk_widget_queue_resize (widget);
2971   if (tree_view->priv->drag_column->resizable)
2972     {
2973       gdk_window_raise (tree_view->priv->drag_column->window);
2974       gdk_window_show (tree_view->priv->drag_column->window);
2975     }
2976   else
2977     gdk_window_hide (tree_view->priv->drag_column->window);
2978
2979   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2980
2981   if (rtl)
2982     {
2983       if (tree_view->priv->cur_reorder &&
2984           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2985         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2986                                          tree_view->priv->cur_reorder->right_column);
2987     }
2988   else
2989     {
2990       if (tree_view->priv->cur_reorder &&
2991           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2992         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2993                                          tree_view->priv->cur_reorder->left_column);
2994     }
2995   tree_view->priv->drag_column = NULL;
2996   gdk_window_hide (tree_view->priv->drag_window);
2997
2998   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
2999     g_slice_free (GtkTreeViewColumnReorder, l->data);
3000   g_list_free (tree_view->priv->column_drag_info);
3001   tree_view->priv->column_drag_info = NULL;
3002   tree_view->priv->cur_reorder = NULL;
3003
3004   if (tree_view->priv->drag_highlight_window)
3005     gdk_window_hide (tree_view->priv->drag_highlight_window);
3006
3007   /* Reset our flags */
3008   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3009   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
3010
3011   return TRUE;
3012 }
3013
3014 /* GtkWidget::button_release_event helper */
3015 static gboolean
3016 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3017                                             GdkEventButton *event)
3018 {
3019   GtkTreeView *tree_view;
3020   gpointer drag_data;
3021
3022   tree_view = GTK_TREE_VIEW (widget);
3023
3024   tree_view->priv->drag_pos = -1;
3025
3026   /* unblock attached dnd signal handler */
3027   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3028   if (drag_data)
3029     g_signal_handlers_unblock_matched (widget,
3030                                        G_SIGNAL_MATCH_DATA,
3031                                        0, 0, NULL, NULL,
3032                                        drag_data);
3033
3034   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3035   gtk_grab_remove (widget);
3036   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
3037                               event->time);
3038   return TRUE;
3039 }
3040
3041 static gboolean
3042 gtk_tree_view_button_release (GtkWidget      *widget,
3043                               GdkEventButton *event)
3044 {
3045   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3046
3047   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3048     return gtk_tree_view_button_release_drag_column (widget, event);
3049
3050   if (tree_view->priv->rubber_band_status)
3051     gtk_tree_view_stop_rubber_band (tree_view);
3052
3053   if (tree_view->priv->pressed_button == event->button)
3054     tree_view->priv->pressed_button = -1;
3055
3056   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3057     return gtk_tree_view_button_release_column_resize (widget, event);
3058
3059   if (tree_view->priv->button_pressed_node == NULL)
3060     return FALSE;
3061
3062   if (event->button == 1)
3063     {
3064       gtk_grab_remove (widget);
3065       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3066           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3067         {
3068           GtkTreePath *path = NULL;
3069
3070           path = _gtk_tree_view_find_path (tree_view,
3071                                            tree_view->priv->button_pressed_tree,
3072                                            tree_view->priv->button_pressed_node);
3073           /* Actually activate the node */
3074           if (tree_view->priv->button_pressed_node->children == NULL)
3075             gtk_tree_view_real_expand_row (tree_view, path,
3076                                            tree_view->priv->button_pressed_tree,
3077                                            tree_view->priv->button_pressed_node,
3078                                            FALSE, TRUE);
3079           else
3080             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3081                                              tree_view->priv->button_pressed_tree,
3082                                              tree_view->priv->button_pressed_node, TRUE);
3083           gtk_tree_path_free (path);
3084         }
3085
3086       tree_view->priv->button_pressed_tree = NULL;
3087       tree_view->priv->button_pressed_node = NULL;
3088     }
3089
3090   return TRUE;
3091 }
3092
3093 static gboolean
3094 gtk_tree_view_grab_broken (GtkWidget          *widget,
3095                            GdkEventGrabBroken *event)
3096 {
3097   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3098
3099   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3100     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3101
3102   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3103     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3104
3105   return TRUE;
3106 }
3107
3108 #if 0
3109 static gboolean
3110 gtk_tree_view_configure (GtkWidget *widget,
3111                          GdkEventConfigure *event)
3112 {
3113   GtkTreeView *tree_view;
3114
3115   tree_view = GTK_TREE_VIEW (widget);
3116   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3117
3118   return FALSE;
3119 }
3120 #endif
3121
3122 /* GtkWidget::motion_event function set.
3123  */
3124
3125 static gboolean
3126 coords_are_over_arrow (GtkTreeView *tree_view,
3127                        GtkRBTree   *tree,
3128                        GtkRBNode   *node,
3129                        /* these are in bin window coords */
3130                        gint         x,
3131                        gint         y)
3132 {
3133   GdkRectangle arrow;
3134   gint x2;
3135
3136   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3137     return FALSE;
3138
3139   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3140     return FALSE;
3141
3142   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3143
3144   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3145
3146   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3147
3148   arrow.width = x2 - arrow.x;
3149
3150   return (x >= arrow.x &&
3151           x < (arrow.x + arrow.width) &&
3152           y >= arrow.y &&
3153           y < (arrow.y + arrow.height));
3154 }
3155
3156 static gboolean
3157 auto_expand_timeout (gpointer data)
3158 {
3159   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3160   GtkTreePath *path;
3161
3162   if (tree_view->priv->prelight_node)
3163     {
3164       path = _gtk_tree_view_find_path (tree_view,
3165                                        tree_view->priv->prelight_tree,
3166                                        tree_view->priv->prelight_node);   
3167
3168       if (tree_view->priv->prelight_node->children)
3169         gtk_tree_view_collapse_row (tree_view, path);
3170       else
3171         gtk_tree_view_expand_row (tree_view, path, FALSE);
3172
3173       gtk_tree_path_free (path);
3174     }
3175
3176   tree_view->priv->auto_expand_timeout = 0;
3177
3178   return FALSE;
3179 }
3180
3181 static void
3182 remove_auto_expand_timeout (GtkTreeView *tree_view)
3183 {
3184   if (tree_view->priv->auto_expand_timeout != 0)
3185     {
3186       g_source_remove (tree_view->priv->auto_expand_timeout);
3187       tree_view->priv->auto_expand_timeout = 0;
3188     }
3189 }
3190
3191 static void
3192 do_prelight (GtkTreeView *tree_view,
3193              GtkRBTree   *tree,
3194              GtkRBNode   *node,
3195              /* these are in bin_window coords */
3196              gint         x,
3197              gint         y)
3198 {
3199   if (tree_view->priv->prelight_tree == tree &&
3200       tree_view->priv->prelight_node == node)
3201     {
3202       /*  We are still on the same node,
3203           but we might need to take care of the arrow  */
3204
3205       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3206         {
3207           gboolean over_arrow;
3208           gboolean flag_set;
3209
3210           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3211           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3212                                              GTK_TREE_VIEW_ARROW_PRELIT);
3213
3214           if (over_arrow != flag_set)
3215             {
3216               if (over_arrow)
3217                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3218                                         GTK_TREE_VIEW_ARROW_PRELIT);
3219               else
3220                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3221                                           GTK_TREE_VIEW_ARROW_PRELIT);
3222
3223               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3224             }
3225         }
3226
3227       return;
3228     }
3229
3230   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3231     {
3232       /*  Unprelight the old node and arrow  */
3233
3234       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3235                              GTK_RBNODE_IS_PRELIT);
3236
3237       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3238           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3239         {
3240           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3241           
3242           gtk_tree_view_draw_arrow (tree_view,
3243                                     tree_view->priv->prelight_tree,
3244                                     tree_view->priv->prelight_node,
3245                                     x,
3246                                     y);
3247         }
3248
3249       _gtk_tree_view_queue_draw_node (tree_view,
3250                                       tree_view->priv->prelight_tree,
3251                                       tree_view->priv->prelight_node,
3252                                       NULL);
3253     }
3254
3255
3256   if (tree_view->priv->hover_expand)
3257     remove_auto_expand_timeout (tree_view);
3258
3259   /*  Set the new prelight values  */
3260   tree_view->priv->prelight_node = node;
3261   tree_view->priv->prelight_tree = tree;
3262
3263   if (!node || !tree)
3264     return;
3265
3266   /*  Prelight the new node and arrow  */
3267
3268   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3269       && coords_are_over_arrow (tree_view, tree, node, x, y))
3270     {
3271       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3272
3273       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3274     }
3275
3276   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3277
3278   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3279
3280   if (tree_view->priv->hover_expand)
3281     {
3282       tree_view->priv->auto_expand_timeout = 
3283         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3284     }
3285 }
3286
3287 static void
3288 prelight_or_select (GtkTreeView *tree_view,
3289                     GtkRBTree   *tree,
3290                     GtkRBNode   *node,
3291                     /* these are in bin_window coords */
3292                     gint         x,
3293                     gint         y)
3294 {
3295   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3296   
3297   if (tree_view->priv->hover_selection &&
3298       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3299       !(tree_view->priv->edited_column &&
3300         tree_view->priv->edited_column->editable_widget))
3301     {
3302       if (node)
3303         {
3304           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3305             {
3306               GtkTreePath *path;
3307               
3308               path = _gtk_tree_view_find_path (tree_view, tree, node);
3309               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3310               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3311                 {
3312                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3313                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3314                 }
3315               gtk_tree_path_free (path);
3316             }
3317         }
3318
3319       else if (mode == GTK_SELECTION_SINGLE)
3320         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3321     }
3322
3323     do_prelight (tree_view, tree, node, x, y);
3324 }
3325
3326 static void
3327 ensure_unprelighted (GtkTreeView *tree_view)
3328 {
3329   do_prelight (tree_view,
3330                NULL, NULL,
3331                -1000, -1000); /* coords not possibly over an arrow */
3332
3333   g_assert (tree_view->priv->prelight_node == NULL);
3334 }
3335
3336 static void
3337 update_prelight (GtkTreeView *tree_view,
3338                  gint         x,
3339                  gint         y)
3340 {
3341   int new_y;
3342   GtkRBTree *tree;
3343   GtkRBNode *node;
3344
3345   if (tree_view->priv->tree == NULL)
3346     return;
3347
3348   if (x == -10000)
3349     {
3350       ensure_unprelighted (tree_view);
3351       return;
3352     }
3353
3354   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3355   if (new_y < 0)
3356     new_y = 0;
3357
3358   _gtk_rbtree_find_offset (tree_view->priv->tree,
3359                            new_y, &tree, &node);
3360
3361   if (node)
3362     prelight_or_select (tree_view, tree, node, x, y);
3363 }
3364
3365
3366
3367
3368 /* Our motion arrow is either a box (in the case of the original spot)
3369  * or an arrow.  It is expander_size wide.
3370  */
3371 /*
3372  * 11111111111111
3373  * 01111111111110
3374  * 00111111111100
3375  * 00011111111000
3376  * 00001111110000
3377  * 00000111100000
3378  * 00000111100000
3379  * 00000111100000
3380  * ~ ~ ~ ~ ~ ~ ~
3381  * 00000111100000
3382  * 00000111100000
3383  * 00000111100000
3384  * 00001111110000
3385  * 00011111111000
3386  * 00111111111100
3387  * 01111111111110
3388  * 11111111111111
3389  */
3390
3391 static void
3392 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3393 {
3394   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3395   GtkWidget *widget = GTK_WIDGET (tree_view);
3396   GdkBitmap *mask = NULL;
3397   gint x;
3398   gint y;
3399   gint width;
3400   gint height;
3401   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3402   GdkWindowAttr attributes;
3403   guint attributes_mask;
3404
3405   if (!reorder ||
3406       reorder->left_column == tree_view->priv->drag_column ||
3407       reorder->right_column == tree_view->priv->drag_column)
3408     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3409   else if (reorder->left_column || reorder->right_column)
3410     {
3411       GdkRectangle visible_rect;
3412       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3413       if (reorder->left_column)
3414         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
3415       else
3416         x = reorder->right_column->button->allocation.x;
3417
3418       if (x < visible_rect.x)
3419         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3420       else if (x > visible_rect.x + visible_rect.width)
3421         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3422       else
3423         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3424     }
3425
3426   /* We want to draw the rectangle over the initial location. */
3427   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3428     {
3429       GdkGC *gc;
3430       GdkColor col;
3431
3432       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3433         {
3434           if (tree_view->priv->drag_highlight_window)
3435             {
3436               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3437                                         NULL);
3438               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3439             }
3440
3441           attributes.window_type = GDK_WINDOW_CHILD;
3442           attributes.wclass = GDK_INPUT_OUTPUT;
3443           attributes.x = tree_view->priv->drag_column_x;
3444           attributes.y = 0;
3445           width = attributes.width = tree_view->priv->drag_column->button->allocation.width;
3446           height = attributes.height = tree_view->priv->drag_column->button->allocation.height;
3447           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3448           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3449           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3450           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3451           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3452           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3453
3454           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3455           gc = gdk_gc_new (mask);
3456           col.pixel = 1;
3457           gdk_gc_set_foreground (gc, &col);
3458           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3459           col.pixel = 0;
3460           gdk_gc_set_foreground(gc, &col);
3461           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
3462           g_object_unref (gc);
3463
3464           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3465                                          mask, 0, 0);
3466           if (mask) g_object_unref (mask);
3467           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3468         }
3469     }
3470   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3471     {
3472       gint i, j = 1;
3473       GdkGC *gc;
3474       GdkColor col;
3475
3476       width = tree_view->priv->expander_size;
3477
3478       /* Get x, y, width, height of arrow */
3479       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3480       if (reorder->left_column)
3481         {
3482           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
3483           height = reorder->left_column->button->allocation.height;
3484         }
3485       else
3486         {
3487           x += reorder->right_column->button->allocation.x - width/2;
3488           height = reorder->right_column->button->allocation.height;
3489         }
3490       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3491       height += tree_view->priv->expander_size;
3492
3493       /* Create the new window */
3494       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3495         {
3496           if (tree_view->priv->drag_highlight_window)
3497             {
3498               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3499                                         NULL);
3500               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3501             }
3502
3503           attributes.window_type = GDK_WINDOW_TEMP;
3504           attributes.wclass = GDK_INPUT_OUTPUT;
3505           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3506           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3507           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3508           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3509           attributes.x = x;
3510           attributes.y = y;
3511           attributes.width = width;
3512           attributes.height = height;
3513           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3514                                                                    &attributes, attributes_mask);
3515           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3516
3517           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3518           gc = gdk_gc_new (mask);
3519           col.pixel = 1;
3520           gdk_gc_set_foreground (gc, &col);
3521           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3522
3523           /* Draw the 2 arrows as per above */
3524           col.pixel = 0;
3525           gdk_gc_set_foreground (gc, &col);
3526           for (i = 0; i < width; i ++)
3527             {
3528               if (i == (width/2 - 1))
3529                 continue;
3530               gdk_draw_line (mask, gc, i, j, i, height - j);
3531               if (i < (width/2 - 1))
3532                 j++;
3533               else
3534                 j--;
3535             }
3536           g_object_unref (gc);
3537           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3538                                          mask, 0, 0);
3539           if (mask) g_object_unref (mask);
3540         }
3541
3542       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3543       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3544     }
3545   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3546            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3547     {
3548       gint i, j = 1;
3549       GdkGC *gc;
3550       GdkColor col;
3551
3552       width = tree_view->priv->expander_size;
3553
3554       /* Get x, y, width, height of arrow */
3555       width = width/2; /* remember, the arrow only takes half the available width */
3556       gdk_window_get_origin (widget->window, &x, &y);
3557       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3558         x += widget->allocation.width - width;
3559
3560       if (reorder->left_column)
3561         height = reorder->left_column->button->allocation.height;
3562       else
3563         height = reorder->right_column->button->allocation.height;
3564
3565       y -= tree_view->priv->expander_size;
3566       height += 2*tree_view->priv->expander_size;
3567
3568       /* Create the new window */
3569       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3570           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3571         {
3572           if (tree_view->priv->drag_highlight_window)
3573             {
3574               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3575                                         NULL);
3576               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3577             }
3578
3579           attributes.window_type = GDK_WINDOW_TEMP;
3580           attributes.wclass = GDK_INPUT_OUTPUT;
3581           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3582           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3583           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3584           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3585           attributes.x = x;
3586           attributes.y = y;
3587           attributes.width = width;
3588           attributes.height = height;
3589           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3590           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3591
3592           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3593           gc = gdk_gc_new (mask);
3594           col.pixel = 1;
3595           gdk_gc_set_foreground (gc, &col);
3596           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3597
3598           /* Draw the 2 arrows as per above */
3599           col.pixel = 0;
3600           gdk_gc_set_foreground (gc, &col);
3601           j = tree_view->priv->expander_size;
3602           for (i = 0; i < width; i ++)
3603             {
3604               gint k;
3605               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3606                 k = width - i - 1;
3607               else
3608                 k = i;
3609               gdk_draw_line (mask, gc, k, j, k, height - j);
3610               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
3611               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
3612               j--;
3613             }
3614           g_object_unref (gc);
3615           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3616                                          mask, 0, 0);
3617           if (mask) g_object_unref (mask);
3618         }
3619
3620       tree_view->priv->drag_column_window_state = arrow_type;
3621       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3622    }
3623   else
3624     {
3625       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3626       gdk_window_hide (tree_view->priv->drag_highlight_window);
3627       return;
3628     }
3629
3630   gdk_window_show (tree_view->priv->drag_highlight_window);
3631   gdk_window_raise (tree_view->priv->drag_highlight_window);
3632 }
3633
3634 static gboolean
3635 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3636                                     GdkEventMotion *event)
3637 {
3638   gint x;
3639   gint new_width;
3640   GtkTreeViewColumn *column;
3641   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3642
3643   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3644
3645   if (event->is_hint || event->window != widget->window)
3646     gtk_widget_get_pointer (widget, &x, NULL);
3647   else
3648     x = event->x;
3649
3650   if (tree_view->priv->hadjustment)
3651     x += tree_view->priv->hadjustment->value;
3652
3653   new_width = gtk_tree_view_new_column_width (tree_view,
3654                                               tree_view->priv->drag_pos, &x);
3655   if (x != tree_view->priv->x_drag &&
3656       (new_width != column->fixed_width))
3657     {
3658       column->use_resized_width = TRUE;
3659       column->resized_width = new_width;
3660       if (column->expand)
3661         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3662       gtk_widget_queue_resize (widget);
3663     }
3664
3665   return FALSE;
3666 }
3667
3668
3669 static void
3670 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3671 {
3672   GtkTreeViewColumnReorder *reorder = NULL;
3673   GList *list;
3674   gint mouse_x;
3675
3676   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3677   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3678     {
3679       reorder = (GtkTreeViewColumnReorder *) list->data;
3680       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3681         break;
3682       reorder = NULL;
3683     }
3684
3685   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3686       return;*/
3687
3688   tree_view->priv->cur_reorder = reorder;
3689   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3690 }
3691
3692 static void
3693 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3694 {
3695   GdkRectangle visible_rect;
3696   gint y;
3697   gint offset;
3698
3699   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3700   y += tree_view->priv->dy;
3701
3702   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3703
3704   /* see if we are near the edge. */
3705   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3706   if (offset > 0)
3707     {
3708       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3709       if (offset < 0)
3710         return;
3711     }
3712
3713   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3714                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3715 }
3716
3717 static gboolean
3718 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3719 {
3720   GdkRectangle visible_rect;
3721   gint x;
3722   gint offset;
3723
3724   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3725
3726   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3727
3728   /* See if we are near the edge. */
3729   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3730   if (offset > 0)
3731     {
3732       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3733       if (offset < 0)
3734         return TRUE;
3735     }
3736   offset = offset/3;
3737
3738   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3739                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3740
3741   return TRUE;
3742
3743 }
3744
3745 static gboolean
3746 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3747                                   GdkEventMotion *event)
3748 {
3749   GtkTreeView *tree_view = (GtkTreeView *) widget;
3750   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3751   gint x, y;
3752
3753   /* Sanity Check */
3754   if ((column == NULL) ||
3755       (event->window != tree_view->priv->drag_window))
3756     return FALSE;
3757
3758   /* Handle moving the header */
3759   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3760   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3761              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
3762   gdk_window_move (tree_view->priv->drag_window, x, y);
3763   
3764   /* autoscroll, if needed */
3765   gtk_tree_view_horizontal_autoscroll (tree_view);
3766   /* Update the current reorder position and arrow; */
3767   gtk_tree_view_update_current_reorder (tree_view);
3768
3769   return TRUE;
3770 }
3771
3772 static void
3773 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3774 {
3775   remove_scroll_timeout (tree_view);
3776   gtk_grab_remove (GTK_WIDGET (tree_view));
3777
3778   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3779     {
3780       GtkTreePath *tmp_path;
3781
3782       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3783
3784       /* The anchor path should be set to the start path */
3785       tmp_path = _gtk_tree_view_find_path (tree_view,
3786                                            tree_view->priv->rubber_band_start_tree,
3787                                            tree_view->priv->rubber_band_start_node);
3788
3789       if (tree_view->priv->anchor)
3790         gtk_tree_row_reference_free (tree_view->priv->anchor);
3791
3792       tree_view->priv->anchor =
3793         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3794                                           tree_view->priv->model,
3795                                           tmp_path);
3796
3797       gtk_tree_path_free (tmp_path);
3798
3799       /* ... and the cursor to the end path */
3800       tmp_path = _gtk_tree_view_find_path (tree_view,
3801                                            tree_view->priv->rubber_band_end_tree,
3802                                            tree_view->priv->rubber_band_end_node);
3803       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3804       gtk_tree_path_free (tmp_path);
3805
3806       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3807     }
3808
3809   /* Clear status variables */
3810   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3811   tree_view->priv->rubber_band_shift = 0;
3812   tree_view->priv->rubber_band_ctrl = 0;
3813
3814   tree_view->priv->rubber_band_start_node = NULL;
3815   tree_view->priv->rubber_band_start_tree = NULL;
3816   tree_view->priv->rubber_band_end_node = NULL;
3817   tree_view->priv->rubber_band_end_tree = NULL;
3818 }
3819
3820 static void
3821 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3822                                                  GtkRBTree   *start_tree,
3823                                                  GtkRBNode   *start_node,
3824                                                  GtkRBTree   *end_tree,
3825                                                  GtkRBNode   *end_node,
3826                                                  gboolean     select,
3827                                                  gboolean     skip_start,
3828                                                  gboolean     skip_end)
3829 {
3830   if (start_node == end_node)
3831     return;
3832
3833   /* We skip the first node and jump inside the loop */
3834   if (skip_start)
3835     goto skip_first;
3836
3837   do
3838     {
3839       /* Small optimization by assuming insensitive nodes are never
3840        * selected.
3841        */
3842       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3843         {
3844           GtkTreePath *path;
3845           gboolean selectable;
3846
3847           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3848           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3849           gtk_tree_path_free (path);
3850
3851           if (!selectable)
3852             goto node_not_selectable;
3853         }
3854
3855       if (select)
3856         {
3857           if (tree_view->priv->rubber_band_shift)
3858             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3859           else if (tree_view->priv->rubber_band_ctrl)
3860             {
3861               /* Toggle the selection state */
3862               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3863                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3864               else
3865                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3866             }
3867           else
3868             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3869         }
3870       else
3871         {
3872           /* Mirror the above */
3873           if (tree_view->priv->rubber_band_shift)
3874             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3875           else if (tree_view->priv->rubber_band_ctrl)
3876             {
3877               /* Toggle the selection state */
3878               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3879                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3880               else
3881                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3882             }
3883           else
3884             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3885         }
3886
3887       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3888
3889 node_not_selectable:
3890       if (start_node == end_node)
3891         break;
3892
3893 skip_first:
3894
3895       if (start_node->children)
3896         {
3897           start_tree = start_node->children;
3898           start_node = start_tree->root;
3899           while (start_node->left != start_tree->nil)
3900             start_node = start_node->left;
3901         }
3902       else
3903         {
3904           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3905
3906           if (!start_tree)
3907             /* Ran out of tree */
3908             break;
3909         }
3910
3911       if (skip_end && start_node == end_node)
3912         break;
3913     }
3914   while (TRUE);
3915 }
3916
3917 static void
3918 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3919 {
3920   GtkRBTree *start_tree, *end_tree;
3921   GtkRBNode *start_node, *end_node;
3922
3923   _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);
3924   _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);
3925
3926   /* Handle the start area first */
3927   if (!tree_view->priv->rubber_band_start_node)
3928     {
3929       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3930                                                        start_tree,
3931                                                        start_node,
3932                                                        end_tree,
3933                                                        end_node,
3934                                                        TRUE,
3935                                                        FALSE,
3936                                                        FALSE);
3937     }
3938   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3939            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3940     {
3941       /* New node is above the old one; selection became bigger */
3942       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3943                                                        start_tree,
3944                                                        start_node,
3945                                                        tree_view->priv->rubber_band_start_tree,
3946                                                        tree_view->priv->rubber_band_start_node,
3947                                                        TRUE,
3948                                                        FALSE,
3949                                                        TRUE);
3950     }
3951   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3952            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3953     {
3954       /* New node is below the old one; selection became smaller */
3955       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3956                                                        tree_view->priv->rubber_band_start_tree,
3957                                                        tree_view->priv->rubber_band_start_node,
3958                                                        start_tree,
3959                                                        start_node,
3960                                                        FALSE,
3961                                                        FALSE,
3962                                                        TRUE);
3963     }
3964
3965   tree_view->priv->rubber_band_start_tree = start_tree;
3966   tree_view->priv->rubber_band_start_node = start_node;
3967
3968   /* Next, handle the end area */
3969   if (!tree_view->priv->rubber_band_end_node)
3970     {
3971       /* In the event this happens, start_node was also NULL; this case is
3972        * handled above.
3973        */
3974     }
3975   else if (!end_node)
3976     {
3977       /* Find the last node in the tree */
3978       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3979                                &end_tree, &end_node);
3980
3981       /* Selection reached end of the tree */
3982       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3983                                                        tree_view->priv->rubber_band_end_tree,
3984                                                        tree_view->priv->rubber_band_end_node,
3985                                                        end_tree,
3986                                                        end_node,
3987                                                        TRUE,
3988                                                        TRUE,
3989                                                        FALSE);
3990     }
3991   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3992            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3993     {
3994       /* New node is below the old one; selection became bigger */
3995       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3996                                                        tree_view->priv->rubber_band_end_tree,
3997                                                        tree_view->priv->rubber_band_end_node,
3998                                                        end_tree,
3999                                                        end_node,
4000                                                        TRUE,
4001                                                        TRUE,
4002                                                        FALSE);
4003     }
4004   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4005            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4006     {
4007       /* New node is above the old one; selection became smaller */
4008       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4009                                                        end_tree,
4010                                                        end_node,
4011                                                        tree_view->priv->rubber_band_end_tree,
4012                                                        tree_view->priv->rubber_band_end_node,
4013                                                        FALSE,
4014                                                        TRUE,
4015                                                        FALSE);
4016     }
4017
4018   tree_view->priv->rubber_band_end_tree = end_tree;
4019   tree_view->priv->rubber_band_end_node = end_node;
4020 }
4021
4022 static void
4023 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4024 {
4025   gint x, y;
4026   GdkRectangle old_area;
4027   GdkRectangle new_area;
4028   GdkRectangle common;
4029   cairo_region_t *invalid_region;
4030
4031   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4032   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4033   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4034   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4035
4036   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4037
4038   x = MAX (x, 0);
4039   y = MAX (y, 0) + tree_view->priv->dy;
4040
4041   new_area.x = MIN (tree_view->priv->press_start_x, x);
4042   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4043   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4044   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4045
4046   invalid_region = cairo_region_create_rectangle (&old_area);
4047   cairo_region_union_rectangle (invalid_region, &new_area);
4048
4049   gdk_rectangle_intersect (&old_area, &new_area, &common);
4050   if (common.width > 2 && common.height > 2)
4051     {
4052       cairo_region_t *common_region;
4053
4054       /* make sure the border is invalidated */
4055       common.x += 1;
4056       common.y += 1;
4057       common.width -= 2;
4058       common.height -= 2;
4059
4060       common_region = cairo_region_create_rectangle (&common);
4061
4062       cairo_region_subtract (invalid_region, common_region);
4063       cairo_region_destroy (common_region);
4064     }
4065
4066   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4067
4068   cairo_region_destroy (invalid_region);
4069
4070   tree_view->priv->rubber_band_x = x;
4071   tree_view->priv->rubber_band_y = y;
4072
4073   gtk_tree_view_update_rubber_band_selection (tree_view);
4074 }
4075
4076 static void
4077 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4078                                 GdkRectangle *area)
4079 {
4080   cairo_t *cr;
4081   GdkRectangle rect;
4082   GdkRectangle rubber_rect;
4083
4084   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4085   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4086   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4087   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4088
4089   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
4090     return;
4091
4092   cr = gdk_cairo_create (tree_view->priv->bin_window);
4093   cairo_set_line_width (cr, 1.0);
4094
4095   cairo_set_source_rgba (cr,
4096                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4097                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4098                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
4099                          .25);
4100
4101   gdk_cairo_rectangle (cr, &rect);
4102   cairo_clip (cr);
4103   cairo_paint (cr);
4104
4105   cairo_set_source_rgb (cr,
4106                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4107                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4108                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
4109
4110   cairo_rectangle (cr,
4111                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4112                    rubber_rect.width - 1, rubber_rect.height - 1);
4113   cairo_stroke (cr);
4114
4115   cairo_destroy (cr);
4116 }
4117
4118 static gboolean
4119 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4120                                  GdkEventMotion *event)
4121 {
4122   GtkTreeView *tree_view;
4123   GtkRBTree *tree;
4124   GtkRBNode *node;
4125   gint new_y;
4126
4127   tree_view = (GtkTreeView *) widget;
4128
4129   if (tree_view->priv->tree == NULL)
4130     return FALSE;
4131
4132   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4133     {
4134       gtk_grab_add (GTK_WIDGET (tree_view));
4135       gtk_tree_view_update_rubber_band (tree_view);
4136
4137       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4138     }
4139   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4140     {
4141       gtk_tree_view_update_rubber_band (tree_view);
4142
4143       add_scroll_timeout (tree_view);
4144     }
4145
4146   /* only check for an initiated drag when a button is pressed */
4147   if (tree_view->priv->pressed_button >= 0
4148       && !tree_view->priv->rubber_band_status)
4149     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4150
4151   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4152   if (new_y < 0)
4153     new_y = 0;
4154
4155   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4156
4157   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4158   if ((tree_view->priv->button_pressed_node != NULL) &&
4159       (tree_view->priv->button_pressed_node != node))
4160     node = NULL;
4161
4162   tree_view->priv->event_last_x = event->x;
4163   tree_view->priv->event_last_y = event->y;
4164
4165   prelight_or_select (tree_view, tree, node, event->x, event->y);
4166
4167   return TRUE;
4168 }
4169
4170 static gboolean
4171 gtk_tree_view_motion (GtkWidget      *widget,
4172                       GdkEventMotion *event)
4173 {
4174   GtkTreeView *tree_view;
4175
4176   tree_view = (GtkTreeView *) widget;
4177
4178   /* Resizing a column */
4179   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4180     return gtk_tree_view_motion_resize_column (widget, event);
4181
4182   /* Drag column */
4183   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4184     return gtk_tree_view_motion_drag_column (widget, event);
4185
4186   /* Sanity check it */
4187   if (event->window == tree_view->priv->bin_window)
4188     return gtk_tree_view_motion_bin_window (widget, event);
4189
4190   return FALSE;
4191 }
4192
4193 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4194  * the tree is empty.
4195  */
4196 static void
4197 invalidate_empty_focus (GtkTreeView *tree_view)
4198 {
4199   GdkRectangle area;
4200
4201   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4202     return;
4203
4204   area.x = 0;
4205   area.y = 0;
4206   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4207   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4208 }
4209
4210 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4211  * is empty.
4212  */
4213 static void
4214 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4215 {
4216   GtkWidget *widget = GTK_WIDGET (tree_view);
4217   gint w, h;
4218
4219   if (!gtk_widget_has_focus (widget))
4220     return;
4221
4222   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4223
4224   w -= 2;
4225   h -= 2;
4226
4227   if (w > 0 && h > 0)
4228     gtk_paint_focus (gtk_widget_get_style (widget),
4229                      tree_view->priv->bin_window,
4230                      gtk_widget_get_state (widget),
4231                      clip_area,
4232                      widget,
4233                      NULL,
4234                      1, 1, w, h);
4235 }
4236
4237 static void
4238 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4239                                GdkEventExpose *event,
4240                                gint            n_visible_columns)
4241 {
4242   GList *list = tree_view->priv->columns;
4243   gint i = 0;
4244   gint current_x = 0;
4245
4246   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4247       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4248     return;
4249
4250   /* Only draw the lines for visible rows and columns */
4251   for (list = tree_view->priv->columns; list; list = list->next, i++)
4252     {
4253       GtkTreeViewColumn *column = list->data;
4254
4255       /* We don't want a line for the last column */
4256       if (i == n_visible_columns - 1)
4257         break;
4258
4259       if (! column->visible)
4260         continue;
4261
4262       current_x += column->width;
4263
4264       gdk_draw_line (event->window,
4265                      tree_view->priv->grid_line_gc,
4266                      current_x - 1, 0,
4267                      current_x - 1, tree_view->priv->height);
4268     }
4269 }
4270
4271 /* Warning: Very scary function.
4272  * Modify at your own risk
4273  *
4274  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4275  * FIXME: It's not...
4276  */
4277 static gboolean
4278 gtk_tree_view_bin_expose (GtkWidget      *widget,
4279                           GdkEventExpose *event)
4280 {
4281   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4282   GtkTreePath *path;
4283   GtkRBTree *tree;
4284   GList *list;
4285   GtkRBNode *node;
4286   GtkRBNode *cursor = NULL;
4287   GtkRBTree *cursor_tree = NULL;
4288   GtkRBNode *drag_highlight = NULL;
4289   GtkRBTree *drag_highlight_tree = NULL;
4290   GtkTreeIter iter;
4291   gint new_y;
4292   gint y_offset, cell_offset;
4293   gint max_height;
4294   gint depth;
4295   GdkRectangle background_area;
4296   GdkRectangle cell_area;
4297   guint flags;
4298   gint highlight_x;
4299   gint expander_cell_width;
4300   gint bin_window_width;
4301   gint bin_window_height;
4302   GtkTreePath *cursor_path;
4303   GtkTreePath *drag_dest_path;
4304   GList *first_column, *last_column;
4305   gint vertical_separator;
4306   gint horizontal_separator;
4307   gint focus_line_width;
4308   gboolean allow_rules;
4309   gboolean has_special_cell;
4310   gboolean rtl;
4311   gint n_visible_columns;
4312   gint pointer_x, pointer_y;
4313   gint grid_line_width;
4314   gboolean got_pointer = FALSE;
4315   gboolean row_ending_details;
4316   gboolean draw_vgrid_lines, draw_hgrid_lines;
4317
4318   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4319
4320   gtk_widget_style_get (widget,
4321                         "horizontal-separator", &horizontal_separator,
4322                         "vertical-separator", &vertical_separator,
4323                         "allow-rules", &allow_rules,
4324                         "focus-line-width", &focus_line_width,
4325                         "row-ending-details", &row_ending_details,
4326                         NULL);
4327
4328   if (tree_view->priv->tree == NULL)
4329     {
4330       draw_empty_focus (tree_view, &event->area);
4331       return TRUE;
4332     }
4333
4334   /* clip event->area to the visible area */
4335   if (event->area.height < 0)
4336     return TRUE;
4337
4338   validate_visible_area (tree_view);
4339
4340   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4341
4342   if (new_y < 0)
4343     new_y = 0;
4344   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4345   gdk_drawable_get_size (tree_view->priv->bin_window,
4346                          &bin_window_width, &bin_window_height);
4347
4348   if (tree_view->priv->height < bin_window_height)
4349     {
4350       gtk_paint_flat_box (widget->style,
4351                           event->window,
4352                           widget->state,
4353                           GTK_SHADOW_NONE,
4354                           &event->area,
4355                           widget,
4356                           "cell_even",
4357                           0, tree_view->priv->height,
4358                           bin_window_width,
4359                           bin_window_height - tree_view->priv->height);
4360     }
4361
4362   if (node == NULL)
4363     return TRUE;
4364
4365   /* find the path for the node */
4366   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4367                                    tree,
4368                                    node);
4369   gtk_tree_model_get_iter (tree_view->priv->model,
4370                            &iter,
4371                            path);
4372   depth = gtk_tree_path_get_depth (path);
4373   gtk_tree_path_free (path);
4374   
4375   cursor_path = NULL;
4376   drag_dest_path = NULL;
4377
4378   if (tree_view->priv->cursor)
4379     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4380
4381   if (cursor_path)
4382     _gtk_tree_view_find_node (tree_view, cursor_path,
4383                               &cursor_tree, &cursor);
4384
4385   if (tree_view->priv->drag_dest_row)
4386     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4387
4388   if (drag_dest_path)
4389     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4390                               &drag_highlight_tree, &drag_highlight);
4391
4392   draw_vgrid_lines =
4393     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4394     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4395   draw_hgrid_lines =
4396     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4397     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4398
4399   if (draw_vgrid_lines || draw_hgrid_lines)
4400     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4401   
4402   n_visible_columns = 0;
4403   for (list = tree_view->priv->columns; list; list = list->next)
4404     {
4405       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4406         continue;
4407       n_visible_columns ++;
4408     }
4409
4410   /* Find the last column */
4411   for (last_column = g_list_last (tree_view->priv->columns);
4412        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4413        last_column = last_column->prev)
4414     ;
4415
4416   /* and the first */
4417   for (first_column = g_list_first (tree_view->priv->columns);
4418        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4419        first_column = first_column->next)
4420     ;
4421
4422   /* Actually process the expose event.  To do this, we want to
4423    * start at the first node of the event, and walk the tree in
4424    * order, drawing each successive node.
4425    */
4426
4427   do
4428     {
4429       gboolean parity;
4430       gboolean is_separator = FALSE;
4431       gboolean is_first = FALSE;
4432       gboolean is_last = FALSE;
4433       
4434       is_separator = row_is_separator (tree_view, &iter, NULL);
4435
4436       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4437
4438       cell_offset = 0;
4439       highlight_x = 0; /* should match x coord of first cell */
4440       expander_cell_width = 0;
4441
4442       background_area.y = y_offset + event->area.y;
4443       background_area.height = max_height;
4444
4445       flags = 0;
4446
4447       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4448         flags |= GTK_CELL_RENDERER_PRELIT;
4449
4450       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4451         flags |= GTK_CELL_RENDERER_SELECTED;
4452
4453       parity = _gtk_rbtree_node_find_parity (tree, node);
4454
4455       /* we *need* to set cell data on all cells before the call
4456        * to _has_special_cell, else _has_special_cell() does not
4457        * return a correct value.
4458        */
4459       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4460            list;
4461            list = (rtl ? list->prev : list->next))
4462         {
4463           GtkTreeViewColumn *column = list->data;
4464           gtk_tree_view_column_cell_set_cell_data (column,
4465                                                    tree_view->priv->model,
4466                                                    &iter,
4467                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4468                                                    node->children?TRUE:FALSE);
4469         }
4470
4471       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4472
4473       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4474            list;
4475            list = (rtl ? list->prev : list->next))
4476         {
4477           GtkTreeViewColumn *column = list->data;
4478           const gchar *detail = NULL;
4479           GtkStateType state;
4480
4481           if (!column->visible)
4482             continue;
4483
4484           if (cell_offset > event->area.x + event->area.width ||
4485               cell_offset + column->width < event->area.x)
4486             {
4487               cell_offset += column->width;
4488               continue;
4489             }
4490
4491           if (column->show_sort_indicator)
4492             flags |= GTK_CELL_RENDERER_SORTED;
4493           else
4494             flags &= ~GTK_CELL_RENDERER_SORTED;
4495
4496           if (cursor == node)
4497             flags |= GTK_CELL_RENDERER_FOCUSED;
4498           else
4499             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4500
4501           background_area.x = cell_offset;
4502           background_area.width = column->width;
4503
4504           cell_area = background_area;
4505           cell_area.y += vertical_separator / 2;
4506           cell_area.x += horizontal_separator / 2;
4507           cell_area.height -= vertical_separator;
4508           cell_area.width -= horizontal_separator;
4509
4510           if (draw_vgrid_lines)
4511             {
4512               if (list == first_column)
4513                 {
4514                   cell_area.width -= grid_line_width / 2;
4515                 }
4516               else if (list == last_column)
4517                 {
4518                   cell_area.x += grid_line_width / 2;
4519                   cell_area.width -= grid_line_width / 2;
4520                 }
4521               else
4522                 {
4523                   cell_area.x += grid_line_width / 2;
4524                   cell_area.width -= grid_line_width;
4525                 }
4526             }
4527
4528           if (draw_hgrid_lines)
4529             {
4530               cell_area.y += grid_line_width / 2;
4531               cell_area.height -= grid_line_width;
4532             }
4533
4534           if (cairo_region_contains_rectangle (event->region, &background_area) == CAIRO_REGION_OVERLAP_OUT)
4535             {
4536               cell_offset += column->width;
4537               continue;
4538             }
4539
4540           gtk_tree_view_column_cell_set_cell_data (column,
4541                                                    tree_view->priv->model,
4542                                                    &iter,
4543                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4544                                                    node->children?TRUE:FALSE);
4545
4546           /* Select the detail for drawing the cell.  relevant
4547            * factors are parity, sortedness, and whether to
4548            * display rules.
4549            */
4550           if (allow_rules && tree_view->priv->has_rules)
4551             {
4552               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4553                   n_visible_columns >= 3)
4554                 {
4555                   if (parity)
4556                     detail = "cell_odd_ruled_sorted";
4557                   else
4558                     detail = "cell_even_ruled_sorted";
4559                 }
4560               else
4561                 {
4562                   if (parity)
4563                     detail = "cell_odd_ruled";
4564                   else
4565                     detail = "cell_even_ruled";
4566                 }
4567             }
4568           else
4569             {
4570               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4571                   n_visible_columns >= 3)
4572                 {
4573                   if (parity)
4574                     detail = "cell_odd_sorted";
4575                   else
4576                     detail = "cell_even_sorted";
4577                 }
4578               else
4579                 {
4580                   if (parity)
4581                     detail = "cell_odd";
4582                   else
4583                     detail = "cell_even";
4584                 }
4585             }
4586
4587           g_assert (detail);
4588
4589           if (widget->state == GTK_STATE_INSENSITIVE)
4590             state = GTK_STATE_INSENSITIVE;          
4591           else if (flags & GTK_CELL_RENDERER_SELECTED)
4592             state = GTK_STATE_SELECTED;
4593           else
4594             state = GTK_STATE_NORMAL;
4595
4596           /* Draw background */
4597           if (row_ending_details)
4598             {
4599               char new_detail[128];
4600
4601               is_first = (rtl ? !list->next : !list->prev);
4602               is_last = (rtl ? !list->prev : !list->next);
4603
4604               /* (I don't like the snprintfs either, but couldn't find a
4605                * less messy way).
4606                */
4607               if (is_first && is_last)
4608                 g_snprintf (new_detail, 127, "%s", detail);
4609               else if (is_first)
4610                 g_snprintf (new_detail, 127, "%s_start", detail);
4611               else if (is_last)
4612                 g_snprintf (new_detail, 127, "%s_end", detail);
4613               else
4614                 g_snprintf (new_detail, 128, "%s_middle", detail);
4615
4616               gtk_paint_flat_box (widget->style,
4617                                   event->window,
4618                                   state,
4619                                   GTK_SHADOW_NONE,
4620                                   &event->area,
4621                                   widget,
4622                                   new_detail,
4623                                   background_area.x,
4624                                   background_area.y,
4625                                   background_area.width,
4626                                   background_area.height);
4627             }
4628           else
4629             {
4630               gtk_paint_flat_box (widget->style,
4631                                   event->window,
4632                                   state,
4633                                   GTK_SHADOW_NONE,
4634                                   &event->area,
4635                                   widget,
4636                                   detail,
4637                                   background_area.x,
4638                                   background_area.y,
4639                                   background_area.width,
4640                                   background_area.height);
4641             }
4642
4643           if (draw_hgrid_lines)
4644             {
4645               if (background_area.y > 0)
4646                 gdk_draw_line (event->window,
4647                                tree_view->priv->grid_line_gc,
4648                                background_area.x, background_area.y,
4649                                background_area.x + background_area.width,
4650                                background_area.y);
4651
4652               if (y_offset + max_height >= event->area.height)
4653                 gdk_draw_line (event->window,
4654                                tree_view->priv->grid_line_gc,
4655                                background_area.x, background_area.y + max_height,
4656                                background_area.x + background_area.width,
4657                                background_area.y + max_height);
4658             }
4659
4660           if (gtk_tree_view_is_expander_column (tree_view, column))
4661             {
4662               if (!rtl)
4663                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4664               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4665
4666               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4667                 {
4668                   if (!rtl)
4669                     cell_area.x += depth * tree_view->priv->expander_size;
4670                   cell_area.width -= depth * tree_view->priv->expander_size;
4671                 }
4672
4673               /* If we have an expander column, the highlight underline
4674                * starts with that column, so that it indicates which
4675                * level of the tree we're dropping at.
4676                */
4677               highlight_x = cell_area.x;
4678               expander_cell_width = cell_area.width;
4679
4680               if (is_separator)
4681                 gtk_paint_hline (widget->style,
4682                                  event->window,
4683                                  state,
4684                                  &cell_area,
4685                                  widget,
4686                                  NULL,
4687                                  cell_area.x,
4688                                  cell_area.x + cell_area.width,
4689                                  cell_area.y + cell_area.height / 2);
4690               else
4691                 _gtk_tree_view_column_cell_render (column,
4692                                                    event->window,
4693                                                    &background_area,
4694                                                    &cell_area,
4695                                                    &event->area,
4696                                                    flags);
4697               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4698                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4699                 {
4700                   if (!got_pointer)
4701                     {
4702                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4703                                               &pointer_x, &pointer_y, NULL);
4704                       got_pointer = TRUE;
4705                     }
4706
4707                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4708                                             tree,
4709                                             node,
4710                                             pointer_x, pointer_y);
4711                 }
4712             }
4713           else
4714             {
4715               if (is_separator)
4716                 gtk_paint_hline (widget->style,
4717                                  event->window,
4718                                  state,
4719                                  &cell_area,
4720                                  widget,
4721                                  NULL,
4722                                  cell_area.x,
4723                                  cell_area.x + cell_area.width,
4724                                  cell_area.y + cell_area.height / 2);
4725               else
4726                 _gtk_tree_view_column_cell_render (column,
4727                                                    event->window,
4728                                                    &background_area,
4729                                                    &cell_area,
4730                                                    &event->area,
4731                                                    flags);
4732             }
4733
4734           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4735               tree_view->priv->tree_lines_enabled)
4736             {
4737               gint x = background_area.x;
4738               gint mult = rtl ? -1 : 1;
4739               gint y0 = background_area.y;
4740               gint y1 = background_area.y + background_area.height/2;
4741               gint y2 = background_area.y + background_area.height;
4742
4743               if (rtl)
4744                 x += background_area.width - 1;
4745
4746               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4747                   && depth > 1)
4748                 {
4749                   gdk_draw_line (event->window,
4750                                  tree_view->priv->tree_line_gc,
4751                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4752                                  y1,
4753                                  x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4754                                  y1);
4755                 }
4756               else if (depth > 1)
4757                 {
4758                   gdk_draw_line (event->window,
4759                                  tree_view->priv->tree_line_gc,
4760                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4761                                  y1,
4762                                  x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4763                                  y1);
4764                 }
4765
4766               if (depth > 1)
4767                 {
4768                   gint i;
4769                   GtkRBNode *tmp_node;
4770                   GtkRBTree *tmp_tree;
4771
4772                   if (!_gtk_rbtree_next (tree, node))
4773                     gdk_draw_line (event->window,
4774                                    tree_view->priv->tree_line_gc,
4775                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4776                                    y0,
4777                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4778                                    y1);
4779                   else
4780                     gdk_draw_line (event->window,
4781                                    tree_view->priv->tree_line_gc,
4782                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4783                                    y0,
4784                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4785                                    y2);
4786
4787                   tmp_node = tree->parent_node;
4788                   tmp_tree = tree->parent_tree;
4789
4790                   for (i = depth - 2; i > 0; i--)
4791                     {
4792                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4793                         gdk_draw_line (event->window,
4794                                        tree_view->priv->tree_line_gc,
4795                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4796                                        y0,
4797                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4798                                        y2);
4799
4800                       tmp_node = tmp_tree->parent_node;
4801                       tmp_tree = tmp_tree->parent_tree;
4802                     }
4803                 }
4804             }
4805
4806           if (node == cursor && has_special_cell &&
4807               ((column == tree_view->priv->focus_column &&
4808                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4809                 gtk_widget_has_focus (widget)) ||
4810                (column == tree_view->priv->edited_column)))
4811             {
4812               _gtk_tree_view_column_cell_draw_focus (column,
4813                                                      event->window,
4814                                                      &background_area,
4815                                                      &cell_area,
4816                                                      &event->area,
4817                                                      flags);
4818             }
4819
4820           cell_offset += column->width;
4821         }
4822
4823       if (node == drag_highlight)
4824         {
4825           /* Draw indicator for the drop
4826            */
4827           gint highlight_y = -1;
4828           GtkRBTree *tree = NULL;
4829           GtkRBNode *node = NULL;
4830           gint width;
4831
4832           switch (tree_view->priv->drag_dest_pos)
4833             {
4834             case GTK_TREE_VIEW_DROP_BEFORE:
4835               highlight_y = background_area.y - 1;
4836               if (highlight_y < 0)
4837                       highlight_y = 0;
4838               break;
4839
4840             case GTK_TREE_VIEW_DROP_AFTER:
4841               highlight_y = background_area.y + background_area.height - 1;
4842               break;
4843
4844             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4845             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4846               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4847
4848               if (tree == NULL)
4849                 break;
4850               gdk_drawable_get_size (tree_view->priv->bin_window,
4851                                      &width, NULL);
4852
4853               if (row_ending_details)
4854                 gtk_paint_focus (widget->style,
4855                                  tree_view->priv->bin_window,
4856                                  gtk_widget_get_state (widget),
4857                                  &event->area,
4858                                  widget,
4859                                  (is_first
4860                                   ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4861                                   : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4862                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4863                                  - focus_line_width / 2,
4864                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4865                                - focus_line_width + 1);
4866               else
4867                 gtk_paint_focus (widget->style,
4868                                  tree_view->priv->bin_window,
4869                                  gtk_widget_get_state (widget),
4870                                  &event->area,
4871                                  widget,
4872                                  "treeview-drop-indicator",
4873                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4874                                  - focus_line_width / 2,
4875                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4876                                  - focus_line_width + 1);
4877               break;
4878             }
4879
4880           if (highlight_y >= 0)
4881             {
4882               gdk_draw_line (event->window,
4883                              widget->style->fg_gc[gtk_widget_get_state (widget)],
4884                              rtl ? highlight_x + expander_cell_width : highlight_x,
4885                              highlight_y,
4886                              rtl ? 0 : bin_window_width,
4887                              highlight_y);
4888             }
4889         }
4890
4891       /* draw the big row-spanning focus rectangle, if needed */
4892       if (!has_special_cell && node == cursor &&
4893           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4894           gtk_widget_has_focus (widget))
4895         {
4896           gint tmp_y, tmp_height;
4897           gint width;
4898           GtkStateType focus_rect_state;
4899
4900           focus_rect_state =
4901             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4902             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4903              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4904               GTK_STATE_NORMAL));
4905
4906           gdk_drawable_get_size (tree_view->priv->bin_window,
4907                                  &width, NULL);
4908           
4909           if (draw_hgrid_lines)
4910             {
4911               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4912               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4913             }
4914           else
4915             {
4916               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4917               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4918             }
4919
4920           if (row_ending_details)
4921             gtk_paint_focus (widget->style,
4922                              tree_view->priv->bin_window,
4923                              focus_rect_state,
4924                              &event->area,
4925                              widget,
4926                              (is_first
4927                               ? (is_last ? "treeview" : "treeview-left" )
4928                               : (is_last ? "treeview-right" : "treeview-middle" )),
4929                              0, tmp_y,
4930                              width, tmp_height);
4931           else
4932             gtk_paint_focus (widget->style,
4933                              tree_view->priv->bin_window,
4934                              focus_rect_state,
4935                              &event->area,
4936                              widget,
4937                              "treeview",
4938                              0, tmp_y,
4939                              width, tmp_height);
4940         }
4941
4942       y_offset += max_height;
4943       if (node->children)
4944         {
4945           GtkTreeIter parent = iter;
4946           gboolean has_child;
4947
4948           tree = node->children;
4949           node = tree->root;
4950
4951           g_assert (node != tree->nil);
4952
4953           while (node->left != tree->nil)
4954             node = node->left;
4955           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4956                                                     &iter,
4957                                                     &parent);
4958           depth++;
4959
4960           /* Sanity Check! */
4961           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4962         }
4963       else
4964         {
4965           gboolean done = FALSE;
4966
4967           do
4968             {
4969               node = _gtk_rbtree_next (tree, node);
4970               if (node != NULL)
4971                 {
4972                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4973                   done = TRUE;
4974
4975                   /* Sanity Check! */
4976                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4977                 }
4978               else
4979                 {
4980                   GtkTreeIter parent_iter = iter;
4981                   gboolean has_parent;
4982
4983                   node = tree->parent_node;
4984                   tree = tree->parent_tree;
4985                   if (tree == NULL)
4986                     /* we should go to done to free some memory */
4987                     goto done;
4988                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4989                                                            &iter,
4990                                                            &parent_iter);
4991                   depth--;
4992
4993                   /* Sanity check */
4994                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
4995                 }
4996             }
4997           while (!done);
4998         }
4999     }
5000   while (y_offset < event->area.height);
5001
5002 done:
5003   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
5004
5005   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5006     {
5007       GdkRectangle rectangle;
5008       gint n_rectangles;
5009  
5010       n_rectangles = cairo_region_num_rectangles (event->region);
5011  
5012       while (n_rectangles--)
5013         {
5014           cairo_region_get_rectangle (event->region, n_rectangles, &rectangle);
5015           gtk_tree_view_paint_rubber_band (tree_view, &rectangle);
5016         }
5017     }
5018
5019   if (cursor_path)
5020     gtk_tree_path_free (cursor_path);
5021
5022   if (drag_dest_path)
5023     gtk_tree_path_free (drag_dest_path);
5024
5025   return FALSE;
5026 }
5027
5028 static gboolean
5029 gtk_tree_view_expose (GtkWidget      *widget,
5030                       GdkEventExpose *event)
5031 {
5032   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5033
5034   if (event->window == tree_view->priv->bin_window)
5035     {
5036       gboolean retval;
5037       GList *tmp_list;
5038
5039       retval = gtk_tree_view_bin_expose (widget, event);
5040
5041       /* We can't just chain up to Container::expose as it will try to send the
5042        * event to the headers, so we handle propagating it to our children
5043        * (eg. widgets being edited) ourselves.
5044        */
5045       tmp_list = tree_view->priv->children;
5046       while (tmp_list)
5047         {
5048           GtkTreeViewChild *child = tmp_list->data;
5049           tmp_list = tmp_list->next;
5050
5051           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
5052         }
5053
5054       return retval;
5055     }
5056
5057   else if (event->window == tree_view->priv->header_window)
5058     {
5059       GList *list;
5060       
5061       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5062         {
5063           GtkTreeViewColumn *column = list->data;
5064
5065           if (column == tree_view->priv->drag_column)
5066             continue;
5067
5068           if (column->visible)
5069             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5070                                             column->button,
5071                                             event);
5072         }
5073     }
5074   else if (event->window == tree_view->priv->drag_window)
5075     {
5076       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5077                                       tree_view->priv->drag_column->button,
5078                                       event);
5079     }
5080   return TRUE;
5081 }
5082
5083 enum
5084 {
5085   DROP_HOME,
5086   DROP_RIGHT,
5087   DROP_LEFT,
5088   DROP_END
5089 };
5090
5091 /* returns 0x1 when no column has been found -- yes it's hackish */
5092 static GtkTreeViewColumn *
5093 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5094                                GtkTreeViewColumn *column,
5095                                gint               drop_position)
5096 {
5097   GtkTreeViewColumn *left_column = NULL;
5098   GtkTreeViewColumn *cur_column = NULL;
5099   GList *tmp_list;
5100
5101   if (!column->reorderable)
5102     return (GtkTreeViewColumn *)0x1;
5103
5104   switch (drop_position)
5105     {
5106       case DROP_HOME:
5107         /* find first column where we can drop */
5108         tmp_list = tree_view->priv->columns;
5109         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5110           return (GtkTreeViewColumn *)0x1;
5111
5112         while (tmp_list)
5113           {
5114             g_assert (tmp_list);
5115
5116             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5117             tmp_list = tmp_list->next;
5118
5119             if (left_column && left_column->visible == FALSE)
5120               continue;
5121
5122             if (!tree_view->priv->column_drop_func)
5123               return left_column;
5124
5125             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5126               {
5127                 left_column = cur_column;
5128                 continue;
5129               }
5130
5131             return left_column;
5132           }
5133
5134         if (!tree_view->priv->column_drop_func)
5135           return left_column;
5136
5137         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5138           return left_column;
5139         else
5140           return (GtkTreeViewColumn *)0x1;
5141         break;
5142
5143       case DROP_RIGHT:
5144         /* find first column after column where we can drop */
5145         tmp_list = tree_view->priv->columns;
5146
5147         for (; tmp_list; tmp_list = tmp_list->next)
5148           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5149             break;
5150
5151         if (!tmp_list || !tmp_list->next)
5152           return (GtkTreeViewColumn *)0x1;
5153
5154         tmp_list = tmp_list->next;
5155         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5156         tmp_list = tmp_list->next;
5157
5158         while (tmp_list)
5159           {
5160             g_assert (tmp_list);
5161
5162             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5163             tmp_list = tmp_list->next;
5164
5165             if (left_column && left_column->visible == FALSE)
5166               {
5167                 left_column = cur_column;
5168                 if (tmp_list)
5169                   tmp_list = tmp_list->next;
5170                 continue;
5171               }
5172
5173             if (!tree_view->priv->column_drop_func)
5174               return left_column;
5175
5176             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5177               {
5178                 left_column = cur_column;
5179                 continue;
5180               }
5181
5182             return left_column;
5183           }
5184
5185         if (!tree_view->priv->column_drop_func)
5186           return left_column;
5187
5188         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5189           return left_column;
5190         else
5191           return (GtkTreeViewColumn *)0x1;
5192         break;
5193
5194       case DROP_LEFT:
5195         /* find first column before column where we can drop */
5196         tmp_list = tree_view->priv->columns;
5197
5198         for (; tmp_list; tmp_list = tmp_list->next)
5199           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5200             break;
5201
5202         if (!tmp_list || !tmp_list->prev)
5203           return (GtkTreeViewColumn *)0x1;
5204
5205         tmp_list = tmp_list->prev;
5206         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5207         tmp_list = tmp_list->prev;
5208
5209         while (tmp_list)
5210           {
5211             g_assert (tmp_list);
5212
5213             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5214
5215             if (left_column && !left_column->visible)
5216               {
5217                 /*if (!tmp_list->prev)
5218                   return (GtkTreeViewColumn *)0x1;
5219                   */
5220 /*
5221                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5222                 tmp_list = tmp_list->prev->prev;
5223                 continue;*/
5224
5225                 cur_column = left_column;
5226                 if (tmp_list)
5227                   tmp_list = tmp_list->prev;
5228                 continue;
5229               }
5230
5231             if (!tree_view->priv->column_drop_func)
5232               return left_column;
5233
5234             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5235               return left_column;
5236
5237             cur_column = left_column;
5238             tmp_list = tmp_list->prev;
5239           }
5240
5241         if (!tree_view->priv->column_drop_func)
5242           return NULL;
5243
5244         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5245           return NULL;
5246         else
5247           return (GtkTreeViewColumn *)0x1;
5248         break;
5249
5250       case DROP_END:
5251         /* same as DROP_HOME case, but doing it backwards */
5252         tmp_list = g_list_last (tree_view->priv->columns);
5253         cur_column = NULL;
5254
5255         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5256           return (GtkTreeViewColumn *)0x1;
5257
5258         while (tmp_list)
5259           {
5260             g_assert (tmp_list);
5261
5262             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5263
5264             if (left_column && !left_column->visible)
5265               {
5266                 cur_column = left_column;
5267                 tmp_list = tmp_list->prev;
5268               }
5269
5270             if (!tree_view->priv->column_drop_func)
5271               return left_column;
5272
5273             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5274               return left_column;
5275
5276             cur_column = left_column;
5277             tmp_list = tmp_list->prev;
5278           }
5279
5280         if (!tree_view->priv->column_drop_func)
5281           return NULL;
5282
5283         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5284           return NULL;
5285         else
5286           return (GtkTreeViewColumn *)0x1;
5287         break;
5288     }
5289
5290   return (GtkTreeViewColumn *)0x1;
5291 }
5292
5293 static gboolean
5294 gtk_tree_view_key_press (GtkWidget   *widget,
5295                          GdkEventKey *event)
5296 {
5297   GtkTreeView *tree_view = (GtkTreeView *) widget;
5298
5299   if (tree_view->priv->rubber_band_status)
5300     {
5301       if (event->keyval == GDK_Escape)
5302         gtk_tree_view_stop_rubber_band (tree_view);
5303
5304       return TRUE;
5305     }
5306
5307   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5308     {
5309       if (event->keyval == GDK_Escape)
5310         {
5311           tree_view->priv->cur_reorder = NULL;
5312           gtk_tree_view_button_release_drag_column (widget, NULL);
5313         }
5314       return TRUE;
5315     }
5316
5317   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5318     {
5319       GList *focus_column;
5320       gboolean rtl;
5321
5322       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5323
5324       for (focus_column = tree_view->priv->columns;
5325            focus_column;
5326            focus_column = focus_column->next)
5327         {
5328           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5329
5330           if (gtk_widget_has_focus (column->button))
5331             break;
5332         }
5333
5334       if (focus_column &&
5335           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5336           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5337            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
5338         {
5339           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5340
5341           if (!column->resizable)
5342             {
5343               gtk_widget_error_bell (widget);
5344               return TRUE;
5345             }
5346
5347           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5348               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5349             {
5350               gint old_width = column->resized_width;
5351
5352               column->resized_width = MAX (column->resized_width,
5353                                            column->width);
5354               column->resized_width -= 2;
5355               if (column->resized_width < 0)
5356                 column->resized_width = 0;
5357
5358               if (column->min_width == -1)
5359                 column->resized_width = MAX (column->button->requisition.width,
5360                                              column->resized_width);
5361               else
5362                 column->resized_width = MAX (column->min_width,
5363                                              column->resized_width);
5364
5365               if (column->max_width != -1)
5366                 column->resized_width = MIN (column->resized_width,
5367                                              column->max_width);
5368
5369               column->use_resized_width = TRUE;
5370
5371               if (column->resized_width != old_width)
5372                 gtk_widget_queue_resize (widget);
5373               else
5374                 gtk_widget_error_bell (widget);
5375             }
5376           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5377                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5378             {
5379               gint old_width = column->resized_width;
5380
5381               column->resized_width = MAX (column->resized_width,
5382                                            column->width);
5383               column->resized_width += 2;
5384
5385               if (column->max_width != -1)
5386                 column->resized_width = MIN (column->resized_width,
5387                                              column->max_width);
5388
5389               column->use_resized_width = TRUE;
5390
5391               if (column->resized_width != old_width)
5392                 gtk_widget_queue_resize (widget);
5393               else
5394                 gtk_widget_error_bell (widget);
5395             }
5396
5397           return TRUE;
5398         }
5399
5400       if (focus_column &&
5401           (event->state & GDK_MOD1_MASK) &&
5402           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5403            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
5404            || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
5405            || event->keyval == GDK_End || event->keyval == GDK_KP_End))
5406         {
5407           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5408
5409           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5410               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5411             {
5412               GtkTreeViewColumn *col;
5413               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5414               if (col != (GtkTreeViewColumn *)0x1)
5415                 gtk_tree_view_move_column_after (tree_view, column, col);
5416               else
5417                 gtk_widget_error_bell (widget);
5418             }
5419           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5420                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5421             {
5422               GtkTreeViewColumn *col;
5423               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5424               if (col != (GtkTreeViewColumn *)0x1)
5425                 gtk_tree_view_move_column_after (tree_view, column, col);
5426               else
5427                 gtk_widget_error_bell (widget);
5428             }
5429           else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
5430             {
5431               GtkTreeViewColumn *col;
5432               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5433               if (col != (GtkTreeViewColumn *)0x1)
5434                 gtk_tree_view_move_column_after (tree_view, column, col);
5435               else
5436                 gtk_widget_error_bell (widget);
5437             }
5438           else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
5439             {
5440               GtkTreeViewColumn *col;
5441               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5442               if (col != (GtkTreeViewColumn *)0x1)
5443                 gtk_tree_view_move_column_after (tree_view, column, col);
5444               else
5445                 gtk_widget_error_bell (widget);
5446             }
5447
5448           return TRUE;
5449         }
5450     }
5451
5452   /* Chain up to the parent class.  It handles the keybindings. */
5453   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5454     return TRUE;
5455
5456   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5457     {
5458       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5459       return FALSE;
5460     }
5461
5462   /* We pass the event to the search_entry.  If its text changes, then we start
5463    * the typeahead find capabilities. */
5464   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5465       && tree_view->priv->enable_search
5466       && !tree_view->priv->search_custom_entry_set)
5467     {
5468       GdkEvent *new_event;
5469       char *old_text;
5470       const char *new_text;
5471       gboolean retval;
5472       GdkScreen *screen;
5473       gboolean text_modified;
5474       gulong popup_menu_id;
5475
5476       gtk_tree_view_ensure_interactive_directory (tree_view);
5477
5478       /* Make a copy of the current text */
5479       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5480       new_event = gdk_event_copy ((GdkEvent *) event);
5481       g_object_unref (((GdkEventKey *) new_event)->window);
5482       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5483       gtk_widget_realize (tree_view->priv->search_window);
5484
5485       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5486                                         "popup-menu", G_CALLBACK (gtk_true),
5487                                         NULL);
5488
5489       /* Move the entry off screen */
5490       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5491       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5492                        gdk_screen_get_width (screen) + 1,
5493                        gdk_screen_get_height (screen) + 1);
5494       gtk_widget_show (tree_view->priv->search_window);
5495
5496       /* Send the event to the window.  If the preedit_changed signal is emitted
5497        * during this event, we will set priv->imcontext_changed  */
5498       tree_view->priv->imcontext_changed = FALSE;
5499       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5500       gdk_event_free (new_event);
5501       gtk_widget_hide (tree_view->priv->search_window);
5502
5503       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5504                                    popup_menu_id);
5505
5506       /* We check to make sure that the entry tried to handle the text, and that
5507        * the text has changed.
5508        */
5509       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5510       text_modified = strcmp (old_text, new_text) != 0;
5511       g_free (old_text);
5512       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5513           (retval && text_modified))               /* ...or the text was modified */
5514         {
5515           if (gtk_tree_view_real_start_interactive_search (tree_view,
5516                                                            gdk_event_get_device ((GdkEvent *) event),
5517                                                            FALSE))
5518             {
5519               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5520               return TRUE;
5521             }
5522           else
5523             {
5524               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5525               return FALSE;
5526             }
5527         }
5528     }
5529
5530   return FALSE;
5531 }
5532
5533 static gboolean
5534 gtk_tree_view_key_release (GtkWidget   *widget,
5535                            GdkEventKey *event)
5536 {
5537   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5538
5539   if (tree_view->priv->rubber_band_status)
5540     return TRUE;
5541
5542   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5543 }
5544
5545 /* FIXME Is this function necessary? Can I get an enter_notify event
5546  * w/o either an expose event or a mouse motion event?
5547  */
5548 static gboolean
5549 gtk_tree_view_enter_notify (GtkWidget        *widget,
5550                             GdkEventCrossing *event)
5551 {
5552   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5553   GtkRBTree *tree;
5554   GtkRBNode *node;
5555   gint new_y;
5556
5557   /* Sanity check it */
5558   if (event->window != tree_view->priv->bin_window)
5559     return FALSE;
5560
5561   if (tree_view->priv->tree == NULL)
5562     return FALSE;
5563
5564   if (event->mode == GDK_CROSSING_GRAB ||
5565       event->mode == GDK_CROSSING_GTK_GRAB ||
5566       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5567       event->mode == GDK_CROSSING_STATE_CHANGED)
5568     return TRUE;
5569
5570   /* find the node internally */
5571   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5572   if (new_y < 0)
5573     new_y = 0;
5574   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5575
5576   tree_view->priv->event_last_x = event->x;
5577   tree_view->priv->event_last_y = event->y;
5578
5579   if ((tree_view->priv->button_pressed_node == NULL) ||
5580       (tree_view->priv->button_pressed_node == node))
5581     prelight_or_select (tree_view, tree, node, event->x, event->y);
5582
5583   return TRUE;
5584 }
5585
5586 static gboolean
5587 gtk_tree_view_leave_notify (GtkWidget        *widget,
5588                             GdkEventCrossing *event)
5589 {
5590   GtkTreeView *tree_view;
5591
5592   if (event->mode == GDK_CROSSING_GRAB)
5593     return TRUE;
5594
5595   tree_view = GTK_TREE_VIEW (widget);
5596
5597   if (tree_view->priv->prelight_node)
5598     _gtk_tree_view_queue_draw_node (tree_view,
5599                                    tree_view->priv->prelight_tree,
5600                                    tree_view->priv->prelight_node,
5601                                    NULL);
5602
5603   tree_view->priv->event_last_x = -10000;
5604   tree_view->priv->event_last_y = -10000;
5605
5606   prelight_or_select (tree_view,
5607                       NULL, NULL,
5608                       -1000, -1000); /* coords not possibly over an arrow */
5609
5610   return TRUE;
5611 }
5612
5613
5614 static gint
5615 gtk_tree_view_focus_out (GtkWidget     *widget,
5616                          GdkEventFocus *event)
5617 {
5618   GtkTreeView *tree_view;
5619
5620   tree_view = GTK_TREE_VIEW (widget);
5621
5622   gtk_widget_queue_draw (widget);
5623
5624   /* destroy interactive search dialog */
5625   if (tree_view->priv->search_window)
5626     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5627                                       gdk_event_get_device ((GdkEvent *) event));
5628
5629   return FALSE;
5630 }
5631
5632
5633 /* Incremental Reflow
5634  */
5635
5636 static void
5637 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5638                                  GtkRBTree   *tree,
5639                                  GtkRBNode   *node)
5640 {
5641   gint y;
5642
5643   y = _gtk_rbtree_node_find_offset (tree, node)
5644     - tree_view->priv->vadjustment->value
5645     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5646
5647   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5648                               0, y,
5649                               GTK_WIDGET (tree_view)->allocation.width,
5650                               GTK_RBNODE_GET_HEIGHT (node));
5651 }
5652
5653 static gboolean
5654 node_is_visible (GtkTreeView *tree_view,
5655                  GtkRBTree   *tree,
5656                  GtkRBNode   *node)
5657 {
5658   int y;
5659   int height;
5660
5661   y = _gtk_rbtree_node_find_offset (tree, node);
5662   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5663
5664   if (y >= tree_view->priv->vadjustment->value &&
5665       y + height <= (tree_view->priv->vadjustment->value
5666                      + tree_view->priv->vadjustment->page_size))
5667     return TRUE;
5668
5669   return FALSE;
5670 }
5671
5672 /* Returns TRUE if it updated the size
5673  */
5674 static gboolean
5675 validate_row (GtkTreeView *tree_view,
5676               GtkRBTree   *tree,
5677               GtkRBNode   *node,
5678               GtkTreeIter *iter,
5679               GtkTreePath *path)
5680 {
5681   GtkTreeViewColumn *column;
5682   GList *list, *first_column, *last_column;
5683   gint height = 0;
5684   gint horizontal_separator;
5685   gint vertical_separator;
5686   gint focus_line_width;
5687   gint depth = gtk_tree_path_get_depth (path);
5688   gboolean retval = FALSE;
5689   gboolean is_separator = FALSE;
5690   gboolean draw_vgrid_lines, draw_hgrid_lines;
5691   gint focus_pad;
5692   gint grid_line_width;
5693   gboolean wide_separators;
5694   gint separator_height;
5695
5696   /* double check the row needs validating */
5697   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5698       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5699     return FALSE;
5700
5701   is_separator = row_is_separator (tree_view, iter, NULL);
5702
5703   gtk_widget_style_get (GTK_WIDGET (tree_view),
5704                         "focus-padding", &focus_pad,
5705                         "focus-line-width", &focus_line_width,
5706                         "horizontal-separator", &horizontal_separator,
5707                         "vertical-separator", &vertical_separator,
5708                         "grid-line-width", &grid_line_width,
5709                         "wide-separators",  &wide_separators,
5710                         "separator-height", &separator_height,
5711                         NULL);
5712   
5713   draw_vgrid_lines =
5714     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5715     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5716   draw_hgrid_lines =
5717     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5718     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5719
5720   for (last_column = g_list_last (tree_view->priv->columns);
5721        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5722        last_column = last_column->prev)
5723     ;
5724
5725   for (first_column = g_list_first (tree_view->priv->columns);
5726        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5727        first_column = first_column->next)
5728     ;
5729
5730   for (list = tree_view->priv->columns; list; list = list->next)
5731     {
5732       gint tmp_width;
5733       gint tmp_height;
5734
5735       column = list->data;
5736
5737       if (! column->visible)
5738         continue;
5739
5740       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5741         continue;
5742
5743       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5744                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5745                                                node->children?TRUE:FALSE);
5746       gtk_tree_view_column_cell_get_size (column,
5747                                           NULL, NULL, NULL,
5748                                           &tmp_width, &tmp_height);
5749
5750       if (!is_separator)
5751         {
5752           tmp_height += vertical_separator;
5753           height = MAX (height, tmp_height);
5754           height = MAX (height, tree_view->priv->expander_size);
5755         }
5756       else
5757         {
5758           if (wide_separators)
5759             height = separator_height + 2 * focus_pad;
5760           else
5761             height = 2 + 2 * focus_pad;
5762         }
5763
5764       if (gtk_tree_view_is_expander_column (tree_view, column))
5765         {
5766           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5767
5768           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5769             tmp_width += depth * tree_view->priv->expander_size;
5770         }
5771       else
5772         tmp_width = tmp_width + horizontal_separator;
5773
5774       if (draw_vgrid_lines)
5775         {
5776           if (list->data == first_column || list->data == last_column)
5777             tmp_width += grid_line_width / 2.0;
5778           else
5779             tmp_width += grid_line_width;
5780         }
5781
5782       if (tmp_width > column->requested_width)
5783         {
5784           retval = TRUE;
5785           column->requested_width = tmp_width;
5786         }
5787     }
5788
5789   if (draw_hgrid_lines)
5790     height += grid_line_width;
5791
5792   if (height != GTK_RBNODE_GET_HEIGHT (node))
5793     {
5794       retval = TRUE;
5795       _gtk_rbtree_node_set_height (tree, node, height);
5796     }
5797   _gtk_rbtree_node_mark_valid (tree, node);
5798   tree_view->priv->post_validation_flag = TRUE;
5799
5800   return retval;
5801 }
5802
5803
5804 static void
5805 validate_visible_area (GtkTreeView *tree_view)
5806 {
5807   GtkTreePath *path = NULL;
5808   GtkTreePath *above_path = NULL;
5809   GtkTreeIter iter;
5810   GtkRBTree *tree = NULL;
5811   GtkRBNode *node = NULL;
5812   gboolean need_redraw = FALSE;
5813   gboolean size_changed = FALSE;
5814   gint total_height;
5815   gint area_above = 0;
5816   gint area_below = 0;
5817
5818   if (tree_view->priv->tree == NULL)
5819     return;
5820
5821   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5822       tree_view->priv->scroll_to_path == NULL)
5823     return;
5824
5825   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5826
5827   if (total_height == 0)
5828     return;
5829
5830   /* First, we check to see if we need to scroll anywhere
5831    */
5832   if (tree_view->priv->scroll_to_path)
5833     {
5834       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5835       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5836         {
5837           /* we are going to scroll, and will update dy */
5838           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5839           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5840               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5841             {
5842               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5843               if (validate_row (tree_view, tree, node, &iter, path))
5844                 size_changed = TRUE;
5845             }
5846
5847           if (tree_view->priv->scroll_to_use_align)
5848             {
5849               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5850               area_above = (total_height - height) *
5851                 tree_view->priv->scroll_to_row_align;
5852               area_below = total_height - area_above - height;
5853               area_above = MAX (area_above, 0);
5854               area_below = MAX (area_below, 0);
5855             }
5856           else
5857             {
5858               /* two cases:
5859                * 1) row not visible
5860                * 2) row visible
5861                */
5862               gint dy;
5863               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5864
5865               dy = _gtk_rbtree_node_find_offset (tree, node);
5866
5867               if (dy >= tree_view->priv->vadjustment->value &&
5868                   dy + height <= (tree_view->priv->vadjustment->value
5869                                   + tree_view->priv->vadjustment->page_size))
5870                 {
5871                   /* row visible: keep the row at the same position */
5872                   area_above = dy - tree_view->priv->vadjustment->value;
5873                   area_below = (tree_view->priv->vadjustment->value +
5874                                 tree_view->priv->vadjustment->page_size)
5875                                - dy - height;
5876                 }
5877               else
5878                 {
5879                   /* row not visible */
5880                   if (dy >= 0
5881                       && dy + height <= tree_view->priv->vadjustment->page_size)
5882                     {
5883                       /* row at the beginning -- fixed */
5884                       area_above = dy;
5885                       area_below = tree_view->priv->vadjustment->page_size
5886                                    - area_above - height;
5887                     }
5888                   else if (dy >= (tree_view->priv->vadjustment->upper -
5889                                   tree_view->priv->vadjustment->page_size))
5890                     {
5891                       /* row at the end -- fixed */
5892                       area_above = dy - (tree_view->priv->vadjustment->upper -
5893                                    tree_view->priv->vadjustment->page_size);
5894                       area_below = tree_view->priv->vadjustment->page_size -
5895                                    area_above - height;
5896
5897                       if (area_below < 0)
5898                         {
5899                           area_above = tree_view->priv->vadjustment->page_size - height;
5900                           area_below = 0;
5901                         }
5902                     }
5903                   else
5904                     {
5905                       /* row somewhere in the middle, bring it to the top
5906                        * of the view
5907                        */
5908                       area_above = 0;
5909                       area_below = total_height - height;
5910                     }
5911                 }
5912             }
5913         }
5914       else
5915         /* the scroll to isn't valid; ignore it.
5916          */
5917         {
5918           if (tree_view->priv->scroll_to_path && !path)
5919             {
5920               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5921               tree_view->priv->scroll_to_path = NULL;
5922             }
5923           if (path)
5924             gtk_tree_path_free (path);
5925           path = NULL;
5926         }      
5927     }
5928
5929   /* We didn't have a scroll_to set, so we just handle things normally
5930    */
5931   if (path == NULL)
5932     {
5933       gint offset;
5934
5935       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5936                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5937                                         &tree, &node);
5938       if (node == NULL)
5939         {
5940           /* In this case, nothing has been validated */
5941           path = gtk_tree_path_new_first ();
5942           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5943         }
5944       else
5945         {
5946           path = _gtk_tree_view_find_path (tree_view, tree, node);
5947           total_height += offset;
5948         }
5949
5950       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5951
5952       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5953           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5954         {
5955           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5956           if (validate_row (tree_view, tree, node, &iter, path))
5957             size_changed = TRUE;
5958         }
5959       area_above = 0;
5960       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5961     }
5962
5963   above_path = gtk_tree_path_copy (path);
5964
5965   /* if we do not validate any row above the new top_row, we will make sure
5966    * that the row immediately above top_row has been validated. (if we do not
5967    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5968    * when invalidated that row's height will be zero. and this will mess up
5969    * scrolling).
5970    */
5971   if (area_above == 0)
5972     {
5973       GtkRBTree *tmptree;
5974       GtkRBNode *tmpnode;
5975
5976       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5977       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5978
5979       if (tmpnode)
5980         {
5981           GtkTreePath *tmppath;
5982           GtkTreeIter tmpiter;
5983
5984           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5985           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5986
5987           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
5988               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
5989             {
5990               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
5991               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
5992                 size_changed = TRUE;
5993             }
5994
5995           gtk_tree_path_free (tmppath);
5996         }
5997     }
5998
5999   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6000    * backwards is much slower then forward, as there is no iter_prev function.
6001    * We go forwards first in case we run out of tree.  Then we go backwards to
6002    * fill out the top.
6003    */
6004   while (node && area_below > 0)
6005     {
6006       if (node->children)
6007         {
6008           GtkTreeIter parent = iter;
6009           gboolean has_child;
6010
6011           tree = node->children;
6012           node = tree->root;
6013
6014           g_assert (node != tree->nil);
6015
6016           while (node->left != tree->nil)
6017             node = node->left;
6018           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6019                                                     &iter,
6020                                                     &parent);
6021           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6022           gtk_tree_path_down (path);
6023         }
6024       else
6025         {
6026           gboolean done = FALSE;
6027           do
6028             {
6029               node = _gtk_rbtree_next (tree, node);
6030               if (node != NULL)
6031                 {
6032                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6033                   done = TRUE;
6034                   gtk_tree_path_next (path);
6035
6036                   /* Sanity Check! */
6037                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6038                 }
6039               else
6040                 {
6041                   GtkTreeIter parent_iter = iter;
6042                   gboolean has_parent;
6043
6044                   node = tree->parent_node;
6045                   tree = tree->parent_tree;
6046                   if (tree == NULL)
6047                     break;
6048                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6049                                                            &iter,
6050                                                            &parent_iter);
6051                   gtk_tree_path_up (path);
6052
6053                   /* Sanity check */
6054                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6055                 }
6056             }
6057           while (!done);
6058         }
6059
6060       if (!node)
6061         break;
6062
6063       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6064           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6065         {
6066           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6067           if (validate_row (tree_view, tree, node, &iter, path))
6068               size_changed = TRUE;
6069         }
6070
6071       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6072     }
6073   gtk_tree_path_free (path);
6074
6075   /* If we ran out of tree, and have extra area_below left, we need to add it
6076    * to area_above */
6077   if (area_below > 0)
6078     area_above += area_below;
6079
6080   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6081
6082   /* We walk backwards */
6083   while (area_above > 0)
6084     {
6085       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6086
6087       /* Always find the new path in the tree.  We cannot just assume
6088        * a gtk_tree_path_prev() is enough here, as there might be children
6089        * in between this node and the previous sibling node.  If this
6090        * appears to be a performance hotspot in profiles, we can look into
6091        * intrigate logic for keeping path, node and iter in sync like
6092        * we do for forward walks.  (Which will be hard because of the lacking
6093        * iter_prev).
6094        */
6095
6096       if (node == NULL)
6097         break;
6098
6099       gtk_tree_path_free (above_path);
6100       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6101
6102       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6103
6104       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6105           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6106         {
6107           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6108           if (validate_row (tree_view, tree, node, &iter, above_path))
6109             size_changed = TRUE;
6110         }
6111       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6112     }
6113
6114   /* if we scrolled to a path, we need to set the dy here,
6115    * and sync the top row accordingly
6116    */
6117   if (tree_view->priv->scroll_to_path)
6118     {
6119       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6120       gtk_tree_view_top_row_to_dy (tree_view);
6121
6122       need_redraw = TRUE;
6123     }
6124   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6125     {
6126       /* when we are not scrolling, we should never set dy to something
6127        * else than zero. we update top_row to be in sync with dy = 0.
6128        */
6129       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6130       gtk_tree_view_dy_to_top_row (tree_view);
6131     }
6132   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6133     {
6134       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6135       gtk_tree_view_dy_to_top_row (tree_view);
6136     }
6137   else
6138     gtk_tree_view_top_row_to_dy (tree_view);
6139
6140   /* update width/height and queue a resize */
6141   if (size_changed)
6142     {
6143       GtkRequisition requisition;
6144
6145       /* We temporarily guess a size, under the assumption that it will be the
6146        * same when we get our next size_allocate.  If we don't do this, we'll be
6147        * in an inconsistent state if we call top_row_to_dy. */
6148
6149       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
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_size_request (GTK_WIDGET (tree_view), &requisition);
6338       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6339       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6340       gtk_adjustment_changed (tree_view->priv->hadjustment);
6341       gtk_adjustment_changed (tree_view->priv->vadjustment);
6342
6343       if (queue_resize)
6344         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6345     }
6346
6347   if (path) gtk_tree_path_free (path);
6348   g_timer_destroy (timer);
6349
6350   return retval;
6351 }
6352
6353 static gboolean
6354 validate_rows (GtkTreeView *tree_view)
6355 {
6356   gboolean retval;
6357   
6358   retval = do_validate_rows (tree_view, TRUE);
6359   
6360   if (! retval && tree_view->priv->validate_rows_timer)
6361     {
6362       g_source_remove (tree_view->priv->validate_rows_timer);
6363       tree_view->priv->validate_rows_timer = 0;
6364     }
6365
6366   return retval;
6367 }
6368
6369 static gboolean
6370 validate_rows_handler (GtkTreeView *tree_view)
6371 {
6372   gboolean retval;
6373
6374   retval = do_validate_rows (tree_view, TRUE);
6375   if (! retval && tree_view->priv->validate_rows_timer)
6376     {
6377       g_source_remove (tree_view->priv->validate_rows_timer);
6378       tree_view->priv->validate_rows_timer = 0;
6379     }
6380
6381   return retval;
6382 }
6383
6384 static gboolean
6385 do_presize_handler (GtkTreeView *tree_view)
6386 {
6387   if (tree_view->priv->mark_rows_col_dirty)
6388     {
6389       if (tree_view->priv->tree)
6390         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6391       tree_view->priv->mark_rows_col_dirty = FALSE;
6392     }
6393   validate_visible_area (tree_view);
6394   tree_view->priv->presize_handler_timer = 0;
6395
6396   if (tree_view->priv->fixed_height_mode)
6397     {
6398       GtkRequisition requisition;
6399
6400       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6401
6402       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6403       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6404       gtk_adjustment_changed (tree_view->priv->hadjustment);
6405       gtk_adjustment_changed (tree_view->priv->vadjustment);
6406       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6407     }
6408                    
6409   return FALSE;
6410 }
6411
6412 static gboolean
6413 presize_handler_callback (gpointer data)
6414 {
6415   do_presize_handler (GTK_TREE_VIEW (data));
6416                    
6417   return FALSE;
6418 }
6419
6420 static void
6421 install_presize_handler (GtkTreeView *tree_view)
6422 {
6423   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6424     return;
6425
6426   if (! tree_view->priv->presize_handler_timer)
6427     {
6428       tree_view->priv->presize_handler_timer =
6429         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6430     }
6431   if (! tree_view->priv->validate_rows_timer)
6432     {
6433       tree_view->priv->validate_rows_timer =
6434         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6435     }
6436 }
6437
6438 static gboolean
6439 scroll_sync_handler (GtkTreeView *tree_view)
6440 {
6441   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6442     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6443   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6444     gtk_tree_view_top_row_to_dy (tree_view);
6445   else
6446     gtk_tree_view_dy_to_top_row (tree_view);
6447
6448   tree_view->priv->scroll_sync_timer = 0;
6449
6450   return FALSE;
6451 }
6452
6453 static void
6454 install_scroll_sync_handler (GtkTreeView *tree_view)
6455 {
6456   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6457     return;
6458
6459   if (!tree_view->priv->scroll_sync_timer)
6460     {
6461       tree_view->priv->scroll_sync_timer =
6462         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6463     }
6464 }
6465
6466 static void
6467 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6468                            GtkTreePath *path,
6469                            gint         offset)
6470 {
6471   gtk_tree_row_reference_free (tree_view->priv->top_row);
6472
6473   if (!path)
6474     {
6475       tree_view->priv->top_row = NULL;
6476       tree_view->priv->top_row_dy = 0;
6477     }
6478   else
6479     {
6480       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6481       tree_view->priv->top_row_dy = offset;
6482     }
6483 }
6484
6485 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6486  * it's set to be NULL, and top_row_dy is 0;
6487  */
6488 static void
6489 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6490 {
6491   gint offset;
6492   GtkTreePath *path;
6493   GtkRBTree *tree;
6494   GtkRBNode *node;
6495
6496   if (tree_view->priv->tree == NULL)
6497     {
6498       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6499     }
6500   else
6501     {
6502       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6503                                         tree_view->priv->dy,
6504                                         &tree, &node);
6505
6506       if (tree == NULL)
6507         {
6508           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6509         }
6510       else
6511         {
6512           path = _gtk_tree_view_find_path (tree_view, tree, node);
6513           gtk_tree_view_set_top_row (tree_view, path, offset);
6514           gtk_tree_path_free (path);
6515         }
6516     }
6517 }
6518
6519 static void
6520 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6521 {
6522   GtkTreePath *path;
6523   GtkRBTree *tree;
6524   GtkRBNode *node;
6525   int new_dy;
6526
6527   /* Avoid recursive calls */
6528   if (tree_view->priv->in_top_row_to_dy)
6529     return;
6530
6531   if (tree_view->priv->top_row)
6532     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6533   else
6534     path = NULL;
6535
6536   if (!path)
6537     tree = NULL;
6538   else
6539     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6540
6541   if (path)
6542     gtk_tree_path_free (path);
6543
6544   if (tree == NULL)
6545     {
6546       /* keep dy and set new toprow */
6547       gtk_tree_row_reference_free (tree_view->priv->top_row);
6548       tree_view->priv->top_row = NULL;
6549       tree_view->priv->top_row_dy = 0;
6550       /* DO NOT install the idle handler */
6551       gtk_tree_view_dy_to_top_row (tree_view);
6552       return;
6553     }
6554
6555   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6556       < tree_view->priv->top_row_dy)
6557     {
6558       /* new top row -- do NOT install the idle handler */
6559       gtk_tree_view_dy_to_top_row (tree_view);
6560       return;
6561     }
6562
6563   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6564   new_dy += tree_view->priv->top_row_dy;
6565
6566   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6567     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6568
6569   new_dy = MAX (0, new_dy);
6570
6571   tree_view->priv->in_top_row_to_dy = TRUE;
6572   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6573   tree_view->priv->in_top_row_to_dy = FALSE;
6574 }
6575
6576
6577 void
6578 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6579 {
6580   tree_view->priv->mark_rows_col_dirty = TRUE;
6581
6582   install_presize_handler (tree_view);
6583 }
6584
6585 /*
6586  * This function works synchronously (due to the while (validate_rows...)
6587  * loop).
6588  *
6589  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6590  * here. You now need to check that yourself.
6591  */
6592 void
6593 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6594                                 GtkTreeViewColumn *column)
6595 {
6596   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6597   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6598
6599   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6600
6601   do_presize_handler (tree_view);
6602   while (validate_rows (tree_view));
6603
6604   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6605 }
6606
6607 /* Drag-and-drop */
6608
6609 static void
6610 set_source_row (GdkDragContext *context,
6611                 GtkTreeModel   *model,
6612                 GtkTreePath    *source_row)
6613 {
6614   g_object_set_data_full (G_OBJECT (context),
6615                           I_("gtk-tree-view-source-row"),
6616                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6617                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6618 }
6619
6620 static GtkTreePath*
6621 get_source_row (GdkDragContext *context)
6622 {
6623   GtkTreeRowReference *ref =
6624     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6625
6626   if (ref)
6627     return gtk_tree_row_reference_get_path (ref);
6628   else
6629     return NULL;
6630 }
6631
6632 typedef struct
6633 {
6634   GtkTreeRowReference *dest_row;
6635   guint                path_down_mode   : 1;
6636   guint                empty_view_drop  : 1;
6637   guint                drop_append_mode : 1;
6638 }
6639 DestRow;
6640
6641 static void
6642 dest_row_free (gpointer data)
6643 {
6644   DestRow *dr = (DestRow *)data;
6645
6646   gtk_tree_row_reference_free (dr->dest_row);
6647   g_slice_free (DestRow, dr);
6648 }
6649
6650 static void
6651 set_dest_row (GdkDragContext *context,
6652               GtkTreeModel   *model,
6653               GtkTreePath    *dest_row,
6654               gboolean        path_down_mode,
6655               gboolean        empty_view_drop,
6656               gboolean        drop_append_mode)
6657 {
6658   DestRow *dr;
6659
6660   if (!dest_row)
6661     {
6662       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6663                               NULL, NULL);
6664       return;
6665     }
6666
6667   dr = g_slice_new (DestRow);
6668
6669   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6670   dr->path_down_mode = path_down_mode != FALSE;
6671   dr->empty_view_drop = empty_view_drop != FALSE;
6672   dr->drop_append_mode = drop_append_mode != FALSE;
6673
6674   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6675                           dr, (GDestroyNotify) dest_row_free);
6676 }
6677
6678 static GtkTreePath*
6679 get_dest_row (GdkDragContext *context,
6680               gboolean       *path_down_mode)
6681 {
6682   DestRow *dr =
6683     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6684
6685   if (dr)
6686     {
6687       GtkTreePath *path = NULL;
6688
6689       if (path_down_mode)
6690         *path_down_mode = dr->path_down_mode;
6691
6692       if (dr->dest_row)
6693         path = gtk_tree_row_reference_get_path (dr->dest_row);
6694       else if (dr->empty_view_drop)
6695         path = gtk_tree_path_new_from_indices (0, -1);
6696       else
6697         path = NULL;
6698
6699       if (path && dr->drop_append_mode)
6700         gtk_tree_path_next (path);
6701
6702       return path;
6703     }
6704   else
6705     return NULL;
6706 }
6707
6708 /* Get/set whether drag_motion requested the drag data and
6709  * drag_data_received should thus not actually insert the data,
6710  * since the data doesn't result from a drop.
6711  */
6712 static void
6713 set_status_pending (GdkDragContext *context,
6714                     GdkDragAction   suggested_action)
6715 {
6716   g_object_set_data (G_OBJECT (context),
6717                      I_("gtk-tree-view-status-pending"),
6718                      GINT_TO_POINTER (suggested_action));
6719 }
6720
6721 static GdkDragAction
6722 get_status_pending (GdkDragContext *context)
6723 {
6724   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6725                                              "gtk-tree-view-status-pending"));
6726 }
6727
6728 static TreeViewDragInfo*
6729 get_info (GtkTreeView *tree_view)
6730 {
6731   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6732 }
6733
6734 static void
6735 destroy_info (TreeViewDragInfo *di)
6736 {
6737   g_slice_free (TreeViewDragInfo, di);
6738 }
6739
6740 static TreeViewDragInfo*
6741 ensure_info (GtkTreeView *tree_view)
6742 {
6743   TreeViewDragInfo *di;
6744
6745   di = get_info (tree_view);
6746
6747   if (di == NULL)
6748     {
6749       di = g_slice_new0 (TreeViewDragInfo);
6750
6751       g_object_set_data_full (G_OBJECT (tree_view),
6752                               I_("gtk-tree-view-drag-info"),
6753                               di,
6754                               (GDestroyNotify) destroy_info);
6755     }
6756
6757   return di;
6758 }
6759
6760 static void
6761 remove_info (GtkTreeView *tree_view)
6762 {
6763   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6764 }
6765
6766 #if 0
6767 static gint
6768 drag_scan_timeout (gpointer data)
6769 {
6770   GtkTreeView *tree_view;
6771   gint x, y;
6772   GdkModifierType state;
6773   GtkTreePath *path = NULL;
6774   GtkTreeViewColumn *column = NULL;
6775   GdkRectangle visible_rect;
6776
6777   GDK_THREADS_ENTER ();
6778
6779   tree_view = GTK_TREE_VIEW (data);
6780
6781   gdk_window_get_pointer (tree_view->priv->bin_window,
6782                           &x, &y, &state);
6783
6784   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6785
6786   /* See if we are near the edge. */
6787   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6788       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6789       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6790       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6791     {
6792       gtk_tree_view_get_path_at_pos (tree_view,
6793                                      tree_view->priv->bin_window,
6794                                      x, y,
6795                                      &path,
6796                                      &column,
6797                                      NULL,
6798                                      NULL);
6799
6800       if (path != NULL)
6801         {
6802           gtk_tree_view_scroll_to_cell (tree_view,
6803                                         path,
6804                                         column,
6805                                         TRUE,
6806                                         0.5, 0.5);
6807
6808           gtk_tree_path_free (path);
6809         }
6810     }
6811
6812   GDK_THREADS_LEAVE ();
6813
6814   return TRUE;
6815 }
6816 #endif /* 0 */
6817
6818 static void
6819 add_scroll_timeout (GtkTreeView *tree_view)
6820 {
6821   if (tree_view->priv->scroll_timeout == 0)
6822     {
6823       tree_view->priv->scroll_timeout =
6824         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6825     }
6826 }
6827
6828 static void
6829 remove_scroll_timeout (GtkTreeView *tree_view)
6830 {
6831   if (tree_view->priv->scroll_timeout != 0)
6832     {
6833       g_source_remove (tree_view->priv->scroll_timeout);
6834       tree_view->priv->scroll_timeout = 0;
6835     }
6836 }
6837
6838 static gboolean
6839 check_model_dnd (GtkTreeModel *model,
6840                  GType         required_iface,
6841                  const gchar  *signal)
6842 {
6843   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6844     {
6845       g_warning ("You must override the default '%s' handler "
6846                  "on GtkTreeView when using models that don't support "
6847                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6848                  "is to connect to '%s' and call "
6849                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6850                  "the default handler from running. Look at the source code "
6851                  "for the default handler in gtktreeview.c to get an idea what "
6852                  "your handler should do. (gtktreeview.c is in the GTK source "
6853                  "code.) If you're using GTK from a language other than C, "
6854                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6855                  signal, g_type_name (required_iface), signal);
6856       return FALSE;
6857     }
6858   else
6859     return TRUE;
6860 }
6861
6862 static void
6863 remove_open_timeout (GtkTreeView *tree_view)
6864 {
6865   if (tree_view->priv->open_dest_timeout != 0)
6866     {
6867       g_source_remove (tree_view->priv->open_dest_timeout);
6868       tree_view->priv->open_dest_timeout = 0;
6869     }
6870 }
6871
6872
6873 static gint
6874 open_row_timeout (gpointer data)
6875 {
6876   GtkTreeView *tree_view = data;
6877   GtkTreePath *dest_path = NULL;
6878   GtkTreeViewDropPosition pos;
6879   gboolean result = FALSE;
6880
6881   gtk_tree_view_get_drag_dest_row (tree_view,
6882                                    &dest_path,
6883                                    &pos);
6884
6885   if (dest_path &&
6886       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6887        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6888     {
6889       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6890       tree_view->priv->open_dest_timeout = 0;
6891
6892       gtk_tree_path_free (dest_path);
6893     }
6894   else
6895     {
6896       if (dest_path)
6897         gtk_tree_path_free (dest_path);
6898
6899       result = TRUE;
6900     }
6901
6902   return result;
6903 }
6904
6905 static gboolean
6906 scroll_row_timeout (gpointer data)
6907 {
6908   GtkTreeView *tree_view = data;
6909
6910   gtk_tree_view_vertical_autoscroll (tree_view);
6911
6912   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6913     gtk_tree_view_update_rubber_band (tree_view);
6914
6915   return TRUE;
6916 }
6917
6918 /* Returns TRUE if event should not be propagated to parent widgets */
6919 static gboolean
6920 set_destination_row (GtkTreeView    *tree_view,
6921                      GdkDragContext *context,
6922                      /* coordinates relative to the widget */
6923                      gint            x,
6924                      gint            y,
6925                      GdkDragAction  *suggested_action,
6926                      GdkAtom        *target)
6927 {
6928   GtkTreePath *path = NULL;
6929   GtkTreeViewDropPosition pos;
6930   GtkTreeViewDropPosition old_pos;
6931   TreeViewDragInfo *di;
6932   GtkWidget *widget;
6933   GtkTreePath *old_dest_path = NULL;
6934   gboolean can_drop = FALSE;
6935
6936   *suggested_action = 0;
6937   *target = GDK_NONE;
6938
6939   widget = GTK_WIDGET (tree_view);
6940
6941   di = get_info (tree_view);
6942
6943   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6944     {
6945       /* someone unset us as a drag dest, note that if
6946        * we return FALSE drag_leave isn't called
6947        */
6948
6949       gtk_tree_view_set_drag_dest_row (tree_view,
6950                                        NULL,
6951                                        GTK_TREE_VIEW_DROP_BEFORE);
6952
6953       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6954       remove_open_timeout (GTK_TREE_VIEW (widget));
6955
6956       return FALSE; /* no longer a drop site */
6957     }
6958
6959   *target = gtk_drag_dest_find_target (widget, context,
6960                                        gtk_drag_dest_get_target_list (widget));
6961   if (*target == GDK_NONE)
6962     {
6963       return FALSE;
6964     }
6965
6966   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6967                                           x, y,
6968                                           &path,
6969                                           &pos))
6970     {
6971       gint n_children;
6972       GtkTreeModel *model;
6973
6974       remove_open_timeout (tree_view);
6975
6976       /* the row got dropped on empty space, let's setup a special case
6977        */
6978
6979       if (path)
6980         gtk_tree_path_free (path);
6981
6982       model = gtk_tree_view_get_model (tree_view);
6983
6984       n_children = gtk_tree_model_iter_n_children (model, NULL);
6985       if (n_children)
6986         {
6987           pos = GTK_TREE_VIEW_DROP_AFTER;
6988           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6989         }
6990       else
6991         {
6992           pos = GTK_TREE_VIEW_DROP_BEFORE;
6993           path = gtk_tree_path_new_from_indices (0, -1);
6994         }
6995
6996       can_drop = TRUE;
6997
6998       goto out;
6999     }
7000
7001   g_assert (path);
7002
7003   /* If we left the current row's "open" zone, unset the timeout for
7004    * opening the row
7005    */
7006   gtk_tree_view_get_drag_dest_row (tree_view,
7007                                    &old_dest_path,
7008                                    &old_pos);
7009
7010   if (old_dest_path &&
7011       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7012        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7013          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7014     remove_open_timeout (tree_view);
7015
7016   if (old_dest_path)
7017     gtk_tree_path_free (old_dest_path);
7018
7019   if (TRUE /* FIXME if the location droppable predicate */)
7020     {
7021       can_drop = TRUE;
7022     }
7023
7024 out:
7025   if (can_drop)
7026     {
7027       GtkWidget *source_widget;
7028
7029       *suggested_action = context->suggested_action;
7030       source_widget = gtk_drag_get_source_widget (context);
7031
7032       if (source_widget == widget)
7033         {
7034           /* Default to MOVE, unless the user has
7035            * pressed ctrl or shift to affect available actions
7036            */
7037           if ((context->actions & GDK_ACTION_MOVE) != 0)
7038             *suggested_action = GDK_ACTION_MOVE;
7039         }
7040
7041       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7042                                        path, pos);
7043     }
7044   else
7045     {
7046       /* can't drop here */
7047       remove_open_timeout (tree_view);
7048
7049       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7050                                        NULL,
7051                                        GTK_TREE_VIEW_DROP_BEFORE);
7052     }
7053
7054   if (path)
7055     gtk_tree_path_free (path);
7056
7057   return TRUE;
7058 }
7059
7060 static GtkTreePath*
7061 get_logical_dest_row (GtkTreeView *tree_view,
7062                       gboolean    *path_down_mode,
7063                       gboolean    *drop_append_mode)
7064 {
7065   /* adjust path to point to the row the drop goes in front of */
7066   GtkTreePath *path = NULL;
7067   GtkTreeViewDropPosition pos;
7068
7069   g_return_val_if_fail (path_down_mode != NULL, NULL);
7070   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7071
7072   *path_down_mode = FALSE;
7073   *drop_append_mode = 0;
7074
7075   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7076
7077   if (path == NULL)
7078     return NULL;
7079
7080   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7081     ; /* do nothing */
7082   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7083            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7084     *path_down_mode = TRUE;
7085   else
7086     {
7087       GtkTreeIter iter;
7088       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7089
7090       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7091
7092       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7093           !gtk_tree_model_iter_next (model, &iter))
7094         *drop_append_mode = 1;
7095       else
7096         {
7097           *drop_append_mode = 0;
7098           gtk_tree_path_next (path);
7099         }
7100     }
7101
7102   return path;
7103 }
7104
7105 static gboolean
7106 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7107                                         GdkEventMotion   *event)
7108 {
7109   GtkWidget *widget = GTK_WIDGET (tree_view);
7110   GdkDragContext *context;
7111   TreeViewDragInfo *di;
7112   GtkTreePath *path = NULL;
7113   gint button;
7114   gint cell_x, cell_y;
7115   GtkTreeModel *model;
7116   gboolean retval = FALSE;
7117
7118   di = get_info (tree_view);
7119
7120   if (di == NULL || !di->source_set)
7121     goto out;
7122
7123   if (tree_view->priv->pressed_button < 0)
7124     goto out;
7125
7126   if (!gtk_drag_check_threshold (widget,
7127                                  tree_view->priv->press_start_x,
7128                                  tree_view->priv->press_start_y,
7129                                  event->x, event->y))
7130     goto out;
7131
7132   model = gtk_tree_view_get_model (tree_view);
7133
7134   if (model == NULL)
7135     goto out;
7136
7137   button = tree_view->priv->pressed_button;
7138   tree_view->priv->pressed_button = -1;
7139
7140   gtk_tree_view_get_path_at_pos (tree_view,
7141                                  tree_view->priv->press_start_x,
7142                                  tree_view->priv->press_start_y,
7143                                  &path,
7144                                  NULL,
7145                                  &cell_x,
7146                                  &cell_y);
7147
7148   if (path == NULL)
7149     goto out;
7150
7151   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7152       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7153                                            path))
7154     goto out;
7155
7156   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7157     goto out;
7158
7159   /* Now we can begin the drag */
7160
7161   retval = TRUE;
7162
7163   context = gtk_drag_begin (widget,
7164                             gtk_drag_source_get_target_list (widget),
7165                             di->source_actions,
7166                             button,
7167                             (GdkEvent*)event);
7168
7169   set_source_row (context, model, path);
7170
7171  out:
7172   if (path)
7173     gtk_tree_path_free (path);
7174
7175   return retval;
7176 }
7177
7178
7179 static void
7180 gtk_tree_view_drag_begin (GtkWidget      *widget,
7181                           GdkDragContext *context)
7182 {
7183   GtkTreeView *tree_view;
7184   GtkTreePath *path = NULL;
7185   gint cell_x, cell_y;
7186   GdkPixmap *row_pix;
7187   TreeViewDragInfo *di;
7188
7189   tree_view = GTK_TREE_VIEW (widget);
7190
7191   /* if the user uses a custom DND source impl, we don't set the icon here */
7192   di = get_info (tree_view);
7193
7194   if (di == NULL || !di->source_set)
7195     return;
7196
7197   gtk_tree_view_get_path_at_pos (tree_view,
7198                                  tree_view->priv->press_start_x,
7199                                  tree_view->priv->press_start_y,
7200                                  &path,
7201                                  NULL,
7202                                  &cell_x,
7203                                  &cell_y);
7204
7205   g_return_if_fail (path != NULL);
7206
7207   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7208                                                 path);
7209
7210   gtk_drag_set_icon_pixmap (context,
7211                             gdk_drawable_get_colormap (row_pix),
7212                             row_pix,
7213                             NULL,
7214                             /* the + 1 is for the black border in the icon */
7215                             tree_view->priv->press_start_x + 1,
7216                             cell_y + 1);
7217
7218   g_object_unref (row_pix);
7219   gtk_tree_path_free (path);
7220 }
7221
7222 static void
7223 gtk_tree_view_drag_end (GtkWidget      *widget,
7224                         GdkDragContext *context)
7225 {
7226   /* do nothing */
7227 }
7228
7229 /* Default signal implementations for the drag signals */
7230 static void
7231 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7232                              GdkDragContext   *context,
7233                              GtkSelectionData *selection_data,
7234                              guint             info,
7235                              guint             time)
7236 {
7237   GtkTreeView *tree_view;
7238   GtkTreeModel *model;
7239   TreeViewDragInfo *di;
7240   GtkTreePath *source_row;
7241
7242   tree_view = GTK_TREE_VIEW (widget);
7243
7244   model = gtk_tree_view_get_model (tree_view);
7245
7246   if (model == NULL)
7247     return;
7248
7249   di = get_info (GTK_TREE_VIEW (widget));
7250
7251   if (di == NULL)
7252     return;
7253
7254   source_row = get_source_row (context);
7255
7256   if (source_row == NULL)
7257     return;
7258
7259   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7260    * any model; for DragSource models there are some other targets
7261    * we also support.
7262    */
7263
7264   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7265       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7266                                           source_row,
7267                                           selection_data))
7268     goto done;
7269
7270   /* If drag_data_get does nothing, try providing row data. */
7271   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7272     {
7273       gtk_tree_set_row_drag_data (selection_data,
7274                                   model,
7275                                   source_row);
7276     }
7277
7278  done:
7279   gtk_tree_path_free (source_row);
7280 }
7281
7282
7283 static void
7284 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7285                                 GdkDragContext *context)
7286 {
7287   TreeViewDragInfo *di;
7288   GtkTreeModel *model;
7289   GtkTreeView *tree_view;
7290   GtkTreePath *source_row;
7291
7292   tree_view = GTK_TREE_VIEW (widget);
7293   model = gtk_tree_view_get_model (tree_view);
7294
7295   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7296     return;
7297
7298   di = get_info (tree_view);
7299
7300   if (di == NULL)
7301     return;
7302
7303   source_row = get_source_row (context);
7304
7305   if (source_row == NULL)
7306     return;
7307
7308   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7309                                          source_row);
7310
7311   gtk_tree_path_free (source_row);
7312
7313   set_source_row (context, NULL, NULL);
7314 }
7315
7316 static void
7317 gtk_tree_view_drag_leave (GtkWidget      *widget,
7318                           GdkDragContext *context,
7319                           guint             time)
7320 {
7321   /* unset any highlight row */
7322   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7323                                    NULL,
7324                                    GTK_TREE_VIEW_DROP_BEFORE);
7325
7326   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7327   remove_open_timeout (GTK_TREE_VIEW (widget));
7328 }
7329
7330
7331 static gboolean
7332 gtk_tree_view_drag_motion (GtkWidget        *widget,
7333                            GdkDragContext   *context,
7334                            /* coordinates relative to the widget */
7335                            gint              x,
7336                            gint              y,
7337                            guint             time)
7338 {
7339   gboolean empty;
7340   GtkTreePath *path = NULL;
7341   GtkTreeViewDropPosition pos;
7342   GtkTreeView *tree_view;
7343   GdkDragAction suggested_action = 0;
7344   GdkAtom target;
7345
7346   tree_view = GTK_TREE_VIEW (widget);
7347
7348   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7349     return FALSE;
7350
7351   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7352
7353   /* we only know this *after* set_desination_row */
7354   empty = tree_view->priv->empty_view_drop;
7355
7356   if (path == NULL && !empty)
7357     {
7358       /* Can't drop here. */
7359       gdk_drag_status (context, 0, time);
7360     }
7361   else
7362     {
7363       if (tree_view->priv->open_dest_timeout == 0 &&
7364           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7365            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7366         {
7367           tree_view->priv->open_dest_timeout =
7368             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7369         }
7370       else
7371         {
7372           add_scroll_timeout (tree_view);
7373         }
7374
7375       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7376         {
7377           /* Request data so we can use the source row when
7378            * determining whether to accept the drop
7379            */
7380           set_status_pending (context, suggested_action);
7381           gtk_drag_get_data (widget, context, target, time);
7382         }
7383       else
7384         {
7385           set_status_pending (context, 0);
7386           gdk_drag_status (context, suggested_action, time);
7387         }
7388     }
7389
7390   if (path)
7391     gtk_tree_path_free (path);
7392
7393   return TRUE;
7394 }
7395
7396
7397 static gboolean
7398 gtk_tree_view_drag_drop (GtkWidget        *widget,
7399                          GdkDragContext   *context,
7400                          /* coordinates relative to the widget */
7401                          gint              x,
7402                          gint              y,
7403                          guint             time)
7404 {
7405   GtkTreeView *tree_view;
7406   GtkTreePath *path;
7407   GdkDragAction suggested_action = 0;
7408   GdkAtom target = GDK_NONE;
7409   TreeViewDragInfo *di;
7410   GtkTreeModel *model;
7411   gboolean path_down_mode;
7412   gboolean drop_append_mode;
7413
7414   tree_view = GTK_TREE_VIEW (widget);
7415
7416   model = gtk_tree_view_get_model (tree_view);
7417
7418   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7419   remove_open_timeout (GTK_TREE_VIEW (widget));
7420
7421   di = get_info (tree_view);
7422
7423   if (di == NULL)
7424     return FALSE;
7425
7426   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7427     return FALSE;
7428
7429   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7430     return FALSE;
7431
7432   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7433
7434   if (target != GDK_NONE && path != NULL)
7435     {
7436       /* in case a motion had requested drag data, change things so we
7437        * treat drag data receives as a drop.
7438        */
7439       set_status_pending (context, 0);
7440       set_dest_row (context, model, path,
7441                     path_down_mode, tree_view->priv->empty_view_drop,
7442                     drop_append_mode);
7443     }
7444
7445   if (path)
7446     gtk_tree_path_free (path);
7447
7448   /* Unset this thing */
7449   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7450                                    NULL,
7451                                    GTK_TREE_VIEW_DROP_BEFORE);
7452
7453   if (target != GDK_NONE)
7454     {
7455       gtk_drag_get_data (widget, context, target, time);
7456       return TRUE;
7457     }
7458   else
7459     return FALSE;
7460 }
7461
7462 static void
7463 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7464                                   GdkDragContext   *context,
7465                                   /* coordinates relative to the widget */
7466                                   gint              x,
7467                                   gint              y,
7468                                   GtkSelectionData *selection_data,
7469                                   guint             info,
7470                                   guint             time)
7471 {
7472   GtkTreePath *path;
7473   TreeViewDragInfo *di;
7474   gboolean accepted = FALSE;
7475   GtkTreeModel *model;
7476   GtkTreeView *tree_view;
7477   GtkTreePath *dest_row;
7478   GdkDragAction suggested_action;
7479   gboolean path_down_mode;
7480   gboolean drop_append_mode;
7481
7482   tree_view = GTK_TREE_VIEW (widget);
7483
7484   model = gtk_tree_view_get_model (tree_view);
7485
7486   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7487     return;
7488
7489   di = get_info (tree_view);
7490
7491   if (di == NULL)
7492     return;
7493
7494   suggested_action = get_status_pending (context);
7495
7496   if (suggested_action)
7497     {
7498       /* We are getting this data due to a request in drag_motion,
7499        * rather than due to a request in drag_drop, so we are just
7500        * supposed to call drag_status, not actually paste in the
7501        * data.
7502        */
7503       path = get_logical_dest_row (tree_view, &path_down_mode,
7504                                    &drop_append_mode);
7505
7506       if (path == NULL)
7507         suggested_action = 0;
7508       else if (path_down_mode)
7509         gtk_tree_path_down (path);
7510
7511       if (suggested_action)
7512         {
7513           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7514                                                      path,
7515                                                      selection_data))
7516             {
7517               if (path_down_mode)
7518                 {
7519                   path_down_mode = FALSE;
7520                   gtk_tree_path_up (path);
7521
7522                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7523                                                              path,
7524                                                              selection_data))
7525                     suggested_action = 0;
7526                 }
7527               else
7528                 suggested_action = 0;
7529             }
7530         }
7531
7532       gdk_drag_status (context, suggested_action, time);
7533
7534       if (path)
7535         gtk_tree_path_free (path);
7536
7537       /* If you can't drop, remove user drop indicator until the next motion */
7538       if (suggested_action == 0)
7539         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7540                                          NULL,
7541                                          GTK_TREE_VIEW_DROP_BEFORE);
7542
7543       return;
7544     }
7545
7546   dest_row = get_dest_row (context, &path_down_mode);
7547
7548   if (dest_row == NULL)
7549     return;
7550
7551   if (selection_data->length >= 0)
7552     {
7553       if (path_down_mode)
7554         {
7555           gtk_tree_path_down (dest_row);
7556           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7557                                                      dest_row, selection_data))
7558             gtk_tree_path_up (dest_row);
7559         }
7560     }
7561
7562   if (selection_data->length >= 0)
7563     {
7564       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7565                                                  dest_row,
7566                                                  selection_data))
7567         accepted = TRUE;
7568     }
7569
7570   gtk_drag_finish (context,
7571                    accepted,
7572                    (context->action == GDK_ACTION_MOVE),
7573                    time);
7574
7575   if (gtk_tree_path_get_depth (dest_row) == 1
7576       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7577     {
7578       /* special special case drag to "0", scroll to first item */
7579       if (!tree_view->priv->scroll_to_path)
7580         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7581     }
7582
7583   gtk_tree_path_free (dest_row);
7584
7585   /* drop dest_row */
7586   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7587 }
7588
7589
7590
7591 /* GtkContainer Methods
7592  */
7593
7594
7595 static void
7596 gtk_tree_view_remove (GtkContainer *container,
7597                       GtkWidget    *widget)
7598 {
7599   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7600   GtkTreeViewChild *child = NULL;
7601   GList *tmp_list;
7602
7603   tmp_list = tree_view->priv->children;
7604   while (tmp_list)
7605     {
7606       child = tmp_list->data;
7607       if (child->widget == widget)
7608         {
7609           gtk_widget_unparent (widget);
7610
7611           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7612           g_list_free_1 (tmp_list);
7613           g_slice_free (GtkTreeViewChild, child);
7614           return;
7615         }
7616
7617       tmp_list = tmp_list->next;
7618     }
7619
7620   tmp_list = tree_view->priv->columns;
7621
7622   while (tmp_list)
7623     {
7624       GtkTreeViewColumn *column;
7625       column = tmp_list->data;
7626       if (column->button == widget)
7627         {
7628           gtk_widget_unparent (widget);
7629           return;
7630         }
7631       tmp_list = tmp_list->next;
7632     }
7633 }
7634
7635 static void
7636 gtk_tree_view_forall (GtkContainer *container,
7637                       gboolean      include_internals,
7638                       GtkCallback   callback,
7639                       gpointer      callback_data)
7640 {
7641   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7642   GtkTreeViewChild *child = NULL;
7643   GtkTreeViewColumn *column;
7644   GList *tmp_list;
7645
7646   tmp_list = tree_view->priv->children;
7647   while (tmp_list)
7648     {
7649       child = tmp_list->data;
7650       tmp_list = tmp_list->next;
7651
7652       (* callback) (child->widget, callback_data);
7653     }
7654   if (include_internals == FALSE)
7655     return;
7656
7657   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7658     {
7659       column = tmp_list->data;
7660
7661       if (column->button)
7662         (* callback) (column->button, callback_data);
7663     }
7664 }
7665
7666 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7667  * cells. If so we draw one big row-spanning focus rectangle.
7668  */
7669 static gboolean
7670 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7671 {
7672   GList *list;
7673
7674   for (list = tree_view->priv->columns; list; list = list->next)
7675     {
7676       if (!((GtkTreeViewColumn *)list->data)->visible)
7677         continue;
7678       if (_gtk_tree_view_column_count_special_cells (list->data))
7679         return TRUE;
7680     }
7681
7682   return FALSE;
7683 }
7684
7685 static void
7686 column_sizing_notify (GObject    *object,
7687                       GParamSpec *pspec,
7688                       gpointer    data)
7689 {
7690   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7691
7692   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7693     /* disable fixed height mode */
7694     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7695 }
7696
7697 /**
7698  * gtk_tree_view_set_fixed_height_mode:
7699  * @tree_view: a #GtkTreeView 
7700  * @enable: %TRUE to enable fixed height mode
7701  * 
7702  * Enables or disables the fixed height mode of @tree_view. 
7703  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7704  * rows have the same height. 
7705  * Only enable this option if all rows are the same height and all
7706  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7707  *
7708  * Since: 2.6 
7709  **/
7710 void
7711 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7712                                      gboolean     enable)
7713 {
7714   GList *l;
7715   
7716   enable = enable != FALSE;
7717
7718   if (enable == tree_view->priv->fixed_height_mode)
7719     return;
7720
7721   if (!enable)
7722     {
7723       tree_view->priv->fixed_height_mode = 0;
7724       tree_view->priv->fixed_height = -1;
7725
7726       /* force a revalidation */
7727       install_presize_handler (tree_view);
7728     }
7729   else 
7730     {
7731       /* make sure all columns are of type FIXED */
7732       for (l = tree_view->priv->columns; l; l = l->next)
7733         {
7734           GtkTreeViewColumn *c = l->data;
7735           
7736           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7737         }
7738       
7739       /* yes, we really have to do this is in a separate loop */
7740       for (l = tree_view->priv->columns; l; l = l->next)
7741         g_signal_connect (l->data, "notify::sizing",
7742                           G_CALLBACK (column_sizing_notify), tree_view);
7743       
7744       tree_view->priv->fixed_height_mode = 1;
7745       tree_view->priv->fixed_height = -1;
7746       
7747       if (tree_view->priv->tree)
7748         initialize_fixed_height_mode (tree_view);
7749     }
7750
7751   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7752 }
7753
7754 /**
7755  * gtk_tree_view_get_fixed_height_mode:
7756  * @tree_view: a #GtkTreeView
7757  * 
7758  * Returns whether fixed height mode is turned on for @tree_view.
7759  * 
7760  * Return value: %TRUE if @tree_view is in fixed height mode
7761  * 
7762  * Since: 2.6
7763  **/
7764 gboolean
7765 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7766 {
7767   return tree_view->priv->fixed_height_mode;
7768 }
7769
7770 /* Returns TRUE if the focus is within the headers, after the focus operation is
7771  * done
7772  */
7773 static gboolean
7774 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7775                             GtkDirectionType  dir,
7776                             gboolean          clamp_column_visible)
7777 {
7778   GtkWidget *focus_child;
7779
7780   GList *last_column, *first_column;
7781   GList *tmp_list;
7782   gboolean rtl;
7783
7784   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7785     return FALSE;
7786
7787   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
7788
7789   first_column = tree_view->priv->columns;
7790   while (first_column)
7791     {
7792       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7793           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7794           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7795            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7796         break;
7797       first_column = first_column->next;
7798     }
7799
7800   /* No headers are visible, or are focusable.  We can't focus in or out.
7801    */
7802   if (first_column == NULL)
7803     return FALSE;
7804
7805   last_column = g_list_last (tree_view->priv->columns);
7806   while (last_column)
7807     {
7808       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7809           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7810           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7811            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7812         break;
7813       last_column = last_column->prev;
7814     }
7815
7816
7817   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7818
7819   switch (dir)
7820     {
7821     case GTK_DIR_TAB_BACKWARD:
7822     case GTK_DIR_TAB_FORWARD:
7823     case GTK_DIR_UP:
7824     case GTK_DIR_DOWN:
7825       if (focus_child == NULL)
7826         {
7827           if (tree_view->priv->focus_column != NULL &&
7828               gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
7829             focus_child = tree_view->priv->focus_column->button;
7830           else
7831             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7832           gtk_widget_grab_focus (focus_child);
7833           break;
7834         }
7835       return FALSE;
7836
7837     case GTK_DIR_LEFT:
7838     case GTK_DIR_RIGHT:
7839       if (focus_child == NULL)
7840         {
7841           if (tree_view->priv->focus_column != NULL)
7842             focus_child = tree_view->priv->focus_column->button;
7843           else if (dir == GTK_DIR_LEFT)
7844             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->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
7851       if (gtk_widget_child_focus (focus_child, dir))
7852         {
7853           /* The focus moves inside the button. */
7854           /* This is probably a great example of bad UI */
7855           break;
7856         }
7857
7858       /* We need to move the focus among the row of buttons. */
7859       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7860         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7861           break;
7862
7863       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7864           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7865         {
7866           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7867           break;
7868         }
7869
7870       while (tmp_list)
7871         {
7872           GtkTreeViewColumn *column;
7873
7874           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7875             tmp_list = tmp_list->next;
7876           else
7877             tmp_list = tmp_list->prev;
7878
7879           if (tmp_list == NULL)
7880             {
7881               g_warning ("Internal button not found");
7882               break;
7883             }
7884           column = tmp_list->data;
7885           if (column->button &&
7886               column->visible &&
7887               gtk_widget_get_can_focus (column->button))
7888             {
7889               focus_child = column->button;
7890               gtk_widget_grab_focus (column->button);
7891               break;
7892             }
7893         }
7894       break;
7895     default:
7896       g_assert_not_reached ();
7897       break;
7898     }
7899
7900   /* if focus child is non-null, we assume it's been set to the current focus child
7901    */
7902   if (focus_child)
7903     {
7904       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7905         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7906           {
7907             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7908             break;
7909           }
7910
7911       if (clamp_column_visible)
7912         {
7913           gtk_tree_view_clamp_column_visible (tree_view,
7914                                               tree_view->priv->focus_column,
7915                                               FALSE);
7916         }
7917     }
7918
7919   return (focus_child != NULL);
7920 }
7921
7922 /* This function returns in 'path' the first focusable path, if the given path
7923  * is already focusable, it's the returned one.
7924  */
7925 static gboolean
7926 search_first_focusable_path (GtkTreeView  *tree_view,
7927                              GtkTreePath **path,
7928                              gboolean      search_forward,
7929                              GtkRBTree   **new_tree,
7930                              GtkRBNode   **new_node)
7931 {
7932   GtkRBTree *tree = NULL;
7933   GtkRBNode *node = NULL;
7934
7935   if (!path || !*path)
7936     return FALSE;
7937
7938   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7939
7940   if (!tree || !node)
7941     return FALSE;
7942
7943   while (node && row_is_separator (tree_view, NULL, *path))
7944     {
7945       if (search_forward)
7946         _gtk_rbtree_next_full (tree, node, &tree, &node);
7947       else
7948         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7949
7950       if (*path)
7951         gtk_tree_path_free (*path);
7952
7953       if (node)
7954         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7955       else
7956         *path = NULL;
7957     }
7958
7959   if (new_tree)
7960     *new_tree = tree;
7961
7962   if (new_node)
7963     *new_node = node;
7964
7965   return (*path != NULL);
7966 }
7967
7968 static gint
7969 gtk_tree_view_focus (GtkWidget        *widget,
7970                      GtkDirectionType  direction)
7971 {
7972   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7973   GtkContainer *container = GTK_CONTAINER (widget);
7974   GtkWidget *focus_child;
7975
7976   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
7977     return FALSE;
7978
7979   focus_child = gtk_container_get_focus_child (container);
7980
7981   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
7982   /* Case 1.  Headers currently have focus. */
7983   if (focus_child)
7984     {
7985       switch (direction)
7986         {
7987         case GTK_DIR_LEFT:
7988         case GTK_DIR_RIGHT:
7989           gtk_tree_view_header_focus (tree_view, direction, TRUE);
7990           return TRUE;
7991         case GTK_DIR_TAB_BACKWARD:
7992         case GTK_DIR_UP:
7993           return FALSE;
7994         case GTK_DIR_TAB_FORWARD:
7995         case GTK_DIR_DOWN:
7996           gtk_widget_grab_focus (widget);
7997           return TRUE;
7998         default:
7999           g_assert_not_reached ();
8000           return FALSE;
8001         }
8002     }
8003
8004   /* Case 2. We don't have focus at all. */
8005   if (!gtk_widget_has_focus (widget))
8006     {
8007       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
8008         gtk_widget_grab_focus (widget);
8009       return TRUE;
8010     }
8011
8012   /* Case 3. We have focus already. */
8013   if (direction == GTK_DIR_TAB_BACKWARD)
8014     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8015   else if (direction == GTK_DIR_TAB_FORWARD)
8016     return FALSE;
8017
8018   /* Other directions caught by the keybindings */
8019   gtk_widget_grab_focus (widget);
8020   return TRUE;
8021 }
8022
8023 static void
8024 gtk_tree_view_grab_focus (GtkWidget *widget)
8025 {
8026   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8027
8028   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8029 }
8030
8031 static void
8032 gtk_tree_view_style_set (GtkWidget *widget,
8033                          GtkStyle *previous_style)
8034 {
8035   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8036   GList *list;
8037   GtkTreeViewColumn *column;
8038
8039   if (gtk_widget_get_realized (widget))
8040     {
8041       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
8042       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
8043       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8044
8045       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8046       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8047     }
8048
8049   gtk_widget_style_get (widget,
8050                         "expander-size", &tree_view->priv->expander_size,
8051                         NULL);
8052   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8053
8054   for (list = tree_view->priv->columns; list; list = list->next)
8055     {
8056       column = list->data;
8057       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8058     }
8059
8060   tree_view->priv->fixed_height = -1;
8061   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8062
8063   gtk_widget_queue_resize (widget);
8064 }
8065
8066
8067 static void
8068 gtk_tree_view_set_focus_child (GtkContainer *container,
8069                                GtkWidget    *child)
8070 {
8071   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8072   GList *list;
8073
8074   for (list = tree_view->priv->columns; list; list = list->next)
8075     {
8076       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8077         {
8078           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8079           break;
8080         }
8081     }
8082
8083   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8084 }
8085
8086 static void
8087 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
8088                                GtkAdjustment *hadj,
8089                                GtkAdjustment *vadj)
8090 {
8091   gboolean need_adjust = FALSE;
8092
8093   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8094
8095   if (hadj)
8096     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
8097   else
8098     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8099   if (vadj)
8100     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
8101   else
8102     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8103
8104   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
8105     {
8106       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
8107                                             gtk_tree_view_adjustment_changed,
8108                                             tree_view);
8109       g_object_unref (tree_view->priv->hadjustment);
8110     }
8111
8112   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
8113     {
8114       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8115                                             gtk_tree_view_adjustment_changed,
8116                                             tree_view);
8117       g_object_unref (tree_view->priv->vadjustment);
8118     }
8119
8120   if (tree_view->priv->hadjustment != hadj)
8121     {
8122       tree_view->priv->hadjustment = hadj;
8123       g_object_ref_sink (tree_view->priv->hadjustment);
8124
8125       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8126                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8127                         tree_view);
8128       need_adjust = TRUE;
8129     }
8130
8131   if (tree_view->priv->vadjustment != vadj)
8132     {
8133       tree_view->priv->vadjustment = vadj;
8134       g_object_ref_sink (tree_view->priv->vadjustment);
8135
8136       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8137                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8138                         tree_view);
8139       need_adjust = TRUE;
8140     }
8141
8142   if (need_adjust)
8143     gtk_tree_view_adjustment_changed (NULL, tree_view);
8144 }
8145
8146
8147 static gboolean
8148 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8149                                 GtkMovementStep    step,
8150                                 gint               count)
8151 {
8152   GdkModifierType state;
8153
8154   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8155   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8156                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8157                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8158                         step == GTK_MOVEMENT_PAGES ||
8159                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8160
8161   if (tree_view->priv->tree == NULL)
8162     return FALSE;
8163   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8164     return FALSE;
8165
8166   gtk_tree_view_stop_editing (tree_view, FALSE);
8167   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8168   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8169
8170   if (gtk_get_current_event_state (&state))
8171     {
8172       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8173         tree_view->priv->ctrl_pressed = TRUE;
8174       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8175         tree_view->priv->shift_pressed = TRUE;
8176     }
8177   /* else we assume not pressed */
8178
8179   switch (step)
8180     {
8181       /* currently we make no distinction.  When we go bi-di, we need to */
8182     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8183     case GTK_MOVEMENT_VISUAL_POSITIONS:
8184       gtk_tree_view_move_cursor_left_right (tree_view, count);
8185       break;
8186     case GTK_MOVEMENT_DISPLAY_LINES:
8187       gtk_tree_view_move_cursor_up_down (tree_view, count);
8188       break;
8189     case GTK_MOVEMENT_PAGES:
8190       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8191       break;
8192     case GTK_MOVEMENT_BUFFER_ENDS:
8193       gtk_tree_view_move_cursor_start_end (tree_view, count);
8194       break;
8195     default:
8196       g_assert_not_reached ();
8197     }
8198
8199   tree_view->priv->ctrl_pressed = FALSE;
8200   tree_view->priv->shift_pressed = FALSE;
8201
8202   return TRUE;
8203 }
8204
8205 static void
8206 gtk_tree_view_put (GtkTreeView *tree_view,
8207                    GtkWidget   *child_widget,
8208                    /* in bin_window coordinates */
8209                    gint         x,
8210                    gint         y,
8211                    gint         width,
8212                    gint         height)
8213 {
8214   GtkTreeViewChild *child;
8215   
8216   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8217   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8218
8219   child = g_slice_new (GtkTreeViewChild);
8220
8221   child->widget = child_widget;
8222   child->x = x;
8223   child->y = y;
8224   child->width = width;
8225   child->height = height;
8226
8227   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8228
8229   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8230     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8231   
8232   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8233 }
8234
8235 void
8236 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8237                                   GtkWidget   *widget,
8238                                   /* in tree coordinates */
8239                                   gint         x,
8240                                   gint         y,
8241                                   gint         width,
8242                                   gint         height)
8243 {
8244   GtkTreeViewChild *child = NULL;
8245   GList *list;
8246   GdkRectangle allocation;
8247
8248   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8249   g_return_if_fail (GTK_IS_WIDGET (widget));
8250
8251   for (list = tree_view->priv->children; list; list = list->next)
8252     {
8253       if (((GtkTreeViewChild *)list->data)->widget == widget)
8254         {
8255           child = list->data;
8256           break;
8257         }
8258     }
8259   if (child == NULL)
8260     return;
8261
8262   allocation.x = child->x = x;
8263   allocation.y = child->y = y;
8264   allocation.width = child->width = width;
8265   allocation.height = child->height = height;
8266
8267   if (gtk_widget_get_realized (widget))
8268     gtk_widget_size_allocate (widget, &allocation);
8269 }
8270
8271
8272 /* TreeModel Callbacks
8273  */
8274
8275 static void
8276 gtk_tree_view_row_changed (GtkTreeModel *model,
8277                            GtkTreePath  *path,
8278                            GtkTreeIter  *iter,
8279                            gpointer      data)
8280 {
8281   GtkTreeView *tree_view = (GtkTreeView *)data;
8282   GtkRBTree *tree;
8283   GtkRBNode *node;
8284   gboolean free_path = FALSE;
8285   GList *list;
8286   GtkTreePath *cursor_path;
8287
8288   g_return_if_fail (path != NULL || iter != NULL);
8289
8290   if (tree_view->priv->cursor != NULL)
8291     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8292   else
8293     cursor_path = NULL;
8294
8295   if (tree_view->priv->edited_column &&
8296       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8297     gtk_tree_view_stop_editing (tree_view, TRUE);
8298
8299   if (cursor_path != NULL)
8300     gtk_tree_path_free (cursor_path);
8301
8302   if (path == NULL)
8303     {
8304       path = gtk_tree_model_get_path (model, iter);
8305       free_path = TRUE;
8306     }
8307   else if (iter == NULL)
8308     gtk_tree_model_get_iter (model, iter, path);
8309
8310   if (_gtk_tree_view_find_node (tree_view,
8311                                 path,
8312                                 &tree,
8313                                 &node))
8314     /* We aren't actually showing the node */
8315     goto done;
8316
8317   if (tree == NULL)
8318     goto done;
8319
8320   if (tree_view->priv->fixed_height_mode
8321       && tree_view->priv->fixed_height >= 0)
8322     {
8323       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8324       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8325         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8326     }
8327   else
8328     {
8329       _gtk_rbtree_node_mark_invalid (tree, node);
8330       for (list = tree_view->priv->columns; list; list = list->next)
8331         {
8332           GtkTreeViewColumn *column;
8333
8334           column = list->data;
8335           if (! column->visible)
8336             continue;
8337
8338           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8339             {
8340               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8341             }
8342         }
8343     }
8344
8345  done:
8346   if (!tree_view->priv->fixed_height_mode &&
8347       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8348     install_presize_handler (tree_view);
8349   if (free_path)
8350     gtk_tree_path_free (path);
8351 }
8352
8353 static void
8354 gtk_tree_view_row_inserted (GtkTreeModel *model,
8355                             GtkTreePath  *path,
8356                             GtkTreeIter  *iter,
8357                             gpointer      data)
8358 {
8359   GtkTreeView *tree_view = (GtkTreeView *) data;
8360   gint *indices;
8361   GtkRBTree *tmptree, *tree;
8362   GtkRBNode *tmpnode = NULL;
8363   gint depth;
8364   gint i = 0;
8365   gint height;
8366   gboolean free_path = FALSE;
8367   gboolean node_visible = TRUE;
8368
8369   g_return_if_fail (path != NULL || iter != NULL);
8370
8371   if (tree_view->priv->fixed_height_mode
8372       && tree_view->priv->fixed_height >= 0)
8373     height = tree_view->priv->fixed_height;
8374   else
8375     height = 0;
8376
8377   if (path == NULL)
8378     {
8379       path = gtk_tree_model_get_path (model, iter);
8380       free_path = TRUE;
8381     }
8382   else if (iter == NULL)
8383     gtk_tree_model_get_iter (model, iter, path);
8384
8385   if (tree_view->priv->tree == NULL)
8386     tree_view->priv->tree = _gtk_rbtree_new ();
8387
8388   tmptree = tree = tree_view->priv->tree;
8389
8390   /* Update all row-references */
8391   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8392   depth = gtk_tree_path_get_depth (path);
8393   indices = gtk_tree_path_get_indices (path);
8394
8395   /* First, find the parent tree */
8396   while (i < depth - 1)
8397     {
8398       if (tmptree == NULL)
8399         {
8400           /* We aren't showing the node */
8401           node_visible = FALSE;
8402           goto done;
8403         }
8404
8405       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8406       if (tmpnode == NULL)
8407         {
8408           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8409                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8410                      "before the parent was inserted.");
8411           goto done;
8412         }
8413       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8414         {
8415           /* FIXME enforce correct behavior on model, probably */
8416           /* In theory, the model should have emitted has_child_toggled here.  We
8417            * try to catch it anyway, just to be safe, in case the model hasn't.
8418            */
8419           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8420                                                            tree,
8421                                                            tmpnode);
8422           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8423           gtk_tree_path_free (tmppath);
8424           goto done;
8425         }
8426
8427       tmptree = tmpnode->children;
8428       tree = tmptree;
8429       i++;
8430     }
8431
8432   if (tree == NULL)
8433     {
8434       node_visible = FALSE;
8435       goto done;
8436     }
8437
8438   /* ref the node */
8439   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8440   if (indices[depth - 1] == 0)
8441     {
8442       tmpnode = _gtk_rbtree_find_count (tree, 1);
8443       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8444     }
8445   else
8446     {
8447       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8448       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8449     }
8450
8451  done:
8452   if (height > 0)
8453     {
8454       if (tree)
8455         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8456
8457       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8458         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8459       else
8460         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8461     }
8462   else
8463     install_presize_handler (tree_view);
8464   if (free_path)
8465     gtk_tree_path_free (path);
8466 }
8467
8468 static void
8469 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8470                                      GtkTreePath  *path,
8471                                      GtkTreeIter  *iter,
8472                                      gpointer      data)
8473 {
8474   GtkTreeView *tree_view = (GtkTreeView *)data;
8475   GtkTreeIter real_iter;
8476   gboolean has_child;
8477   GtkRBTree *tree;
8478   GtkRBNode *node;
8479   gboolean free_path = FALSE;
8480
8481   g_return_if_fail (path != NULL || iter != NULL);
8482
8483   if (iter)
8484     real_iter = *iter;
8485
8486   if (path == NULL)
8487     {
8488       path = gtk_tree_model_get_path (model, iter);
8489       free_path = TRUE;
8490     }
8491   else if (iter == NULL)
8492     gtk_tree_model_get_iter (model, &real_iter, path);
8493
8494   if (_gtk_tree_view_find_node (tree_view,
8495                                 path,
8496                                 &tree,
8497                                 &node))
8498     /* We aren't actually showing the node */
8499     goto done;
8500
8501   if (tree == NULL)
8502     goto done;
8503
8504   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8505   /* Sanity check.
8506    */
8507   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8508     goto done;
8509
8510   if (has_child)
8511     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8512   else
8513     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8514
8515   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8516     {
8517       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8518       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8519         {
8520           GList *list;
8521
8522           for (list = tree_view->priv->columns; list; list = list->next)
8523             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8524               {
8525                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8526                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8527                 break;
8528               }
8529         }
8530       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8531     }
8532   else
8533     {
8534       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8535     }
8536
8537  done:
8538   if (free_path)
8539     gtk_tree_path_free (path);
8540 }
8541
8542 static void
8543 count_children_helper (GtkRBTree *tree,
8544                        GtkRBNode *node,
8545                        gpointer   data)
8546 {
8547   if (node->children)
8548     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8549   (*((gint *)data))++;
8550 }
8551
8552 static void
8553 check_selection_helper (GtkRBTree *tree,
8554                         GtkRBNode *node,
8555                         gpointer   data)
8556 {
8557   gint *value = (gint *)data;
8558
8559   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8560
8561   if (node->children && !*value)
8562     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8563 }
8564
8565 static void
8566 gtk_tree_view_row_deleted (GtkTreeModel *model,
8567                            GtkTreePath  *path,
8568                            gpointer      data)
8569 {
8570   GtkTreeView *tree_view = (GtkTreeView *)data;
8571   GtkRBTree *tree;
8572   GtkRBNode *node;
8573   GList *list;
8574   gint selection_changed = FALSE;
8575
8576   g_return_if_fail (path != NULL);
8577
8578   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8579
8580   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8581     return;
8582
8583   if (tree == NULL)
8584     return;
8585
8586   /* check if the selection has been changed */
8587   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8588                         check_selection_helper, &selection_changed);
8589
8590   for (list = tree_view->priv->columns; list; list = list->next)
8591     if (((GtkTreeViewColumn *)list->data)->visible &&
8592         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8593       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8594
8595   /* Ensure we don't have a dangling pointer to a dead node */
8596   ensure_unprelighted (tree_view);
8597
8598   /* Cancel editting if we've started */
8599   gtk_tree_view_stop_editing (tree_view, TRUE);
8600
8601   /* If we have a node expanded/collapsed timeout, remove it */
8602   remove_expand_collapse_timeout (tree_view);
8603
8604   if (tree_view->priv->destroy_count_func)
8605     {
8606       gint child_count = 0;
8607       if (node->children)
8608         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8609       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8610     }
8611
8612   if (tree->root->count == 1)
8613     {
8614       if (tree_view->priv->tree == tree)
8615         tree_view->priv->tree = NULL;
8616
8617       _gtk_rbtree_remove (tree);
8618     }
8619   else
8620     {
8621       _gtk_rbtree_remove_node (tree, node);
8622     }
8623
8624   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8625     {
8626       gtk_tree_row_reference_free (tree_view->priv->top_row);
8627       tree_view->priv->top_row = NULL;
8628     }
8629
8630   install_scroll_sync_handler (tree_view);
8631
8632   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8633
8634   if (selection_changed)
8635     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8636 }
8637
8638 static void
8639 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8640                               GtkTreePath  *parent,
8641                               GtkTreeIter  *iter,
8642                               gint         *new_order,
8643                               gpointer      data)
8644 {
8645   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8646   GtkRBTree *tree;
8647   GtkRBNode *node;
8648   gint len;
8649
8650   len = gtk_tree_model_iter_n_children (model, iter);
8651
8652   if (len < 2)
8653     return;
8654
8655   gtk_tree_row_reference_reordered (G_OBJECT (data),
8656                                     parent,
8657                                     iter,
8658                                     new_order);
8659
8660   if (_gtk_tree_view_find_node (tree_view,
8661                                 parent,
8662                                 &tree,
8663                                 &node))
8664     return;
8665
8666   /* We need to special case the parent path */
8667   if (tree == NULL)
8668     tree = tree_view->priv->tree;
8669   else
8670     tree = node->children;
8671
8672   if (tree == NULL)
8673     return;
8674
8675   if (tree_view->priv->edited_column)
8676     gtk_tree_view_stop_editing (tree_view, TRUE);
8677
8678   /* we need to be unprelighted */
8679   ensure_unprelighted (tree_view);
8680
8681   /* clear the timeout */
8682   cancel_arrow_animation (tree_view);
8683   
8684   _gtk_rbtree_reorder (tree, new_order, len);
8685
8686   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8687
8688   gtk_tree_view_dy_to_top_row (tree_view);
8689 }
8690
8691
8692 /* Internal tree functions
8693  */
8694
8695
8696 static void
8697 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8698                                      GtkRBTree         *tree,
8699                                      GtkTreeViewColumn *column,
8700                                      gint              *x1,
8701                                      gint              *x2)
8702 {
8703   GtkTreeViewColumn *tmp_column = NULL;
8704   gint total_width;
8705   GList *list;
8706   gboolean rtl;
8707
8708   if (x1)
8709     *x1 = 0;
8710
8711   if (x2)
8712     *x2 = 0;
8713
8714   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8715
8716   total_width = 0;
8717   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8718        list;
8719        list = (rtl ? list->prev : list->next))
8720     {
8721       tmp_column = list->data;
8722
8723       if (tmp_column == column)
8724         break;
8725
8726       if (tmp_column->visible)
8727         total_width += tmp_column->width;
8728     }
8729
8730   if (tmp_column != column)
8731     {
8732       g_warning (G_STRLOC": passed-in column isn't in the tree");
8733       return;
8734     }
8735
8736   if (x1)
8737     *x1 = total_width;
8738
8739   if (x2)
8740     {
8741       if (column->visible)
8742         *x2 = total_width + column->width;
8743       else
8744         *x2 = total_width; /* width of 0 */
8745     }
8746 }
8747 static void
8748 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8749                                 GtkRBTree   *tree,
8750                                 gint        *x1,
8751                                 gint        *x2)
8752 {
8753   gint x_offset = 0;
8754   GList *list;
8755   GtkTreeViewColumn *tmp_column = NULL;
8756   gint total_width;
8757   gboolean indent_expanders;
8758   gboolean rtl;
8759
8760   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8761
8762   total_width = 0;
8763   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8764        list;
8765        list = (rtl ? list->prev : list->next))
8766     {
8767       tmp_column = list->data;
8768
8769       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8770         {
8771           if (rtl)
8772             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8773           else
8774             x_offset = total_width;
8775           break;
8776         }
8777
8778       if (tmp_column->visible)
8779         total_width += tmp_column->width;
8780     }
8781
8782   gtk_widget_style_get (GTK_WIDGET (tree_view),
8783                         "indent-expanders", &indent_expanders,
8784                         NULL);
8785
8786   if (indent_expanders)
8787     {
8788       if (rtl)
8789         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8790       else
8791         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8792     }
8793
8794   *x1 = x_offset;
8795   
8796   if (tmp_column && tmp_column->visible)
8797     /* +1 because x2 isn't included in the range. */
8798     *x2 = *x1 + tree_view->priv->expander_size + 1;
8799   else
8800     *x2 = *x1;
8801 }
8802
8803 static void
8804 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8805                           GtkRBTree   *tree,
8806                           GtkTreeIter *iter,
8807                           gint         depth,
8808                           gboolean     recurse)
8809 {
8810   GtkRBNode *temp = NULL;
8811   GtkTreePath *path = NULL;
8812   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8813
8814   do
8815     {
8816       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8817       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8818
8819       if (tree_view->priv->fixed_height > 0)
8820         {
8821           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8822             {
8823               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8824               _gtk_rbtree_node_mark_valid (tree, temp);
8825             }
8826         }
8827
8828       if (is_list)
8829         continue;
8830
8831       if (recurse)
8832         {
8833           GtkTreeIter child;
8834
8835           if (!path)
8836             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8837           else
8838             gtk_tree_path_next (path);
8839
8840           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8841             {
8842               gboolean expand;
8843
8844               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8845
8846               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8847                   && !expand)
8848                 {
8849                   temp->children = _gtk_rbtree_new ();
8850                   temp->children->parent_tree = tree;
8851                   temp->children->parent_node = temp;
8852                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8853                 }
8854             }
8855         }
8856
8857       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8858         {
8859           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8860             temp->flags ^= GTK_RBNODE_IS_PARENT;
8861         }
8862     }
8863   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8864
8865   if (path)
8866     gtk_tree_path_free (path);
8867 }
8868
8869 /* Make sure the node is visible vertically */
8870 static void
8871 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8872                                   GtkRBTree   *tree,
8873                                   GtkRBNode   *node)
8874 {
8875   gint node_dy, height;
8876   GtkTreePath *path = NULL;
8877
8878   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8879     return;
8880
8881   /* just return if the node is visible, avoiding a costly expose */
8882   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8883   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8884   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8885       && node_dy >= tree_view->priv->vadjustment->value
8886       && node_dy + height <= (tree_view->priv->vadjustment->value
8887                               + tree_view->priv->vadjustment->page_size))
8888     return;
8889
8890   path = _gtk_tree_view_find_path (tree_view, tree, node);
8891   if (path)
8892     {
8893       /* We process updates because we want to clear old selected items when we scroll.
8894        * if this is removed, we get a "selection streak" at the bottom. */
8895       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8896       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8897       gtk_tree_path_free (path);
8898     }
8899 }
8900
8901 static void
8902 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8903                                     GtkTreeViewColumn *column,
8904                                     gboolean           focus_to_cell)
8905 {
8906   gint x, width;
8907
8908   if (column == NULL)
8909     return;
8910
8911   x = column->button->allocation.x;
8912   width = column->button->allocation.width;
8913
8914   if (width > tree_view->priv->hadjustment->page_size)
8915     {
8916       /* The column is larger than the horizontal page size.  If the
8917        * column has cells which can be focussed individually, then we make
8918        * sure the cell which gets focus is fully visible (if even the
8919        * focus cell is bigger than the page size, we make sure the
8920        * left-hand side of the cell is visible).
8921        *
8922        * If the column does not have those so-called special cells, we
8923        * make sure the left-hand side of the column is visible.
8924        */
8925
8926       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8927         {
8928           GtkTreePath *cursor_path;
8929           GdkRectangle background_area, cell_area, focus_area;
8930
8931           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8932
8933           gtk_tree_view_get_cell_area (tree_view,
8934                                        cursor_path, column, &cell_area);
8935           gtk_tree_view_get_background_area (tree_view,
8936                                              cursor_path, column,
8937                                              &background_area);
8938
8939           gtk_tree_path_free (cursor_path);
8940
8941           _gtk_tree_view_column_get_focus_area (column,
8942                                                 &background_area,
8943                                                 &cell_area,
8944                                                 &focus_area);
8945
8946           x = focus_area.x;
8947           width = focus_area.width;
8948
8949           if (width < tree_view->priv->hadjustment->page_size)
8950             {
8951               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8952                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8953                                           x + width - tree_view->priv->hadjustment->page_size);
8954               else if (tree_view->priv->hadjustment->value > x)
8955                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8956             }
8957         }
8958
8959       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8960     }
8961   else
8962     {
8963       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8964           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8965                                     x + width - tree_view->priv->hadjustment->page_size);
8966       else if (tree_view->priv->hadjustment->value > x)
8967         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8968   }
8969 }
8970
8971 /* This function could be more efficient.  I'll optimize it if profiling seems
8972  * to imply that it is important */
8973 GtkTreePath *
8974 _gtk_tree_view_find_path (GtkTreeView *tree_view,
8975                           GtkRBTree   *tree,
8976                           GtkRBNode   *node)
8977 {
8978   GtkTreePath *path;
8979   GtkRBTree *tmp_tree;
8980   GtkRBNode *tmp_node, *last;
8981   gint count;
8982
8983   path = gtk_tree_path_new ();
8984
8985   g_return_val_if_fail (node != NULL, path);
8986   g_return_val_if_fail (node != tree->nil, path);
8987
8988   count = 1 + node->left->count;
8989
8990   last = node;
8991   tmp_node = node->parent;
8992   tmp_tree = tree;
8993   while (tmp_tree)
8994     {
8995       while (tmp_node != tmp_tree->nil)
8996         {
8997           if (tmp_node->right == last)
8998             count += 1 + tmp_node->left->count;
8999           last = tmp_node;
9000           tmp_node = tmp_node->parent;
9001         }
9002       gtk_tree_path_prepend_index (path, count - 1);
9003       last = tmp_tree->parent_node;
9004       tmp_tree = tmp_tree->parent_tree;
9005       if (last)
9006         {
9007           count = 1 + last->left->count;
9008           tmp_node = last->parent;
9009         }
9010     }
9011   return path;
9012 }
9013
9014 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9015  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9016  * both set to NULL.
9017  */
9018 gboolean
9019 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9020                           GtkTreePath  *path,
9021                           GtkRBTree   **tree,
9022                           GtkRBNode   **node)
9023 {
9024   GtkRBNode *tmpnode = NULL;
9025   GtkRBTree *tmptree = tree_view->priv->tree;
9026   gint *indices = gtk_tree_path_get_indices (path);
9027   gint depth = gtk_tree_path_get_depth (path);
9028   gint i = 0;
9029
9030   *node = NULL;
9031   *tree = NULL;
9032
9033   if (depth == 0 || tmptree == NULL)
9034     return FALSE;
9035   do
9036     {
9037       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9038       ++i;
9039       if (tmpnode == NULL)
9040         {
9041           *tree = NULL;
9042           *node = NULL;
9043           return FALSE;
9044         }
9045       if (i >= depth)
9046         {
9047           *tree = tmptree;
9048           *node = tmpnode;
9049           return FALSE;
9050         }
9051       *tree = tmptree;
9052       *node = tmpnode;
9053       tmptree = tmpnode->children;
9054       if (tmptree == NULL)
9055         return TRUE;
9056     }
9057   while (1);
9058 }
9059
9060 static gboolean
9061 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9062                                   GtkTreeViewColumn *column)
9063 {
9064   GList *list;
9065
9066   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9067     return FALSE;
9068
9069   if (tree_view->priv->expander_column != NULL)
9070     {
9071       if (tree_view->priv->expander_column == column)
9072         return TRUE;
9073       return FALSE;
9074     }
9075   else
9076     {
9077       for (list = tree_view->priv->columns;
9078            list;
9079            list = list->next)
9080         if (((GtkTreeViewColumn *)list->data)->visible)
9081           break;
9082       if (list && list->data == column)
9083         return TRUE;
9084     }
9085   return FALSE;
9086 }
9087
9088 static void
9089 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9090                                 guint           keyval,
9091                                 guint           modmask,
9092                                 gboolean        add_shifted_binding,
9093                                 GtkMovementStep step,
9094                                 gint            count)
9095 {
9096   
9097   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9098                                 "move-cursor", 2,
9099                                 G_TYPE_ENUM, step,
9100                                 G_TYPE_INT, count);
9101
9102   if (add_shifted_binding)
9103     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9104                                   "move-cursor", 2,
9105                                   G_TYPE_ENUM, step,
9106                                   G_TYPE_INT, count);
9107
9108   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9109    return;
9110
9111   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9112                                 "move-cursor", 2,
9113                                 G_TYPE_ENUM, step,
9114                                 G_TYPE_INT, count);
9115
9116   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9117                                 "move-cursor", 2,
9118                                 G_TYPE_ENUM, step,
9119                                 G_TYPE_INT, count);
9120 }
9121
9122 static gint
9123 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9124                                  GtkTreeIter  *iter,
9125                                  GtkRBTree    *tree,
9126                                  GtkRBNode    *node)
9127 {
9128   gint retval = FALSE;
9129   do
9130     {
9131       g_return_val_if_fail (node != NULL, FALSE);
9132
9133       if (node->children)
9134         {
9135           GtkTreeIter child;
9136           GtkRBTree *new_tree;
9137           GtkRBNode *new_node;
9138
9139           new_tree = node->children;
9140           new_node = new_tree->root;
9141
9142           while (new_node && new_node->left != new_tree->nil)
9143             new_node = new_node->left;
9144
9145           if (!gtk_tree_model_iter_children (model, &child, iter))
9146             return FALSE;
9147
9148           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9149         }
9150
9151       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9152         retval = TRUE;
9153       gtk_tree_model_unref_node (model, iter);
9154       node = _gtk_rbtree_next (tree, node);
9155     }
9156   while (gtk_tree_model_iter_next (model, iter));
9157
9158   return retval;
9159 }
9160
9161 static gint
9162 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9163                                               GtkRBTree   *tree)
9164 {
9165   GtkTreeIter iter;
9166   GtkTreePath *path;
9167   GtkRBNode *node;
9168   gint retval;
9169
9170   if (!tree)
9171     return FALSE;
9172
9173   node = tree->root;
9174   while (node && node->left != tree->nil)
9175     node = node->left;
9176
9177   g_return_val_if_fail (node != NULL, FALSE);
9178   path = _gtk_tree_view_find_path (tree_view, tree, node);
9179   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9180                            &iter, path);
9181   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9182   gtk_tree_path_free (path);
9183
9184   return retval;
9185 }
9186
9187 static void
9188 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9189                                     GtkTreeViewColumn *column)
9190 {
9191   GtkTreeViewColumn *left_column;
9192   GtkTreeViewColumn *cur_column = NULL;
9193   GtkTreeViewColumnReorder *reorder;
9194   gboolean rtl;
9195   GList *tmp_list;
9196   gint left;
9197
9198   /* We want to precalculate the motion list such that we know what column slots
9199    * are available.
9200    */
9201   left_column = NULL;
9202   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9203
9204   /* First, identify all possible drop spots */
9205   if (rtl)
9206     tmp_list = g_list_last (tree_view->priv->columns);
9207   else
9208     tmp_list = g_list_first (tree_view->priv->columns);
9209
9210   while (tmp_list)
9211     {
9212       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9213       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9214
9215       if (cur_column->visible == FALSE)
9216         continue;
9217
9218       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9219       if (left_column != column && cur_column != column &&
9220           tree_view->priv->column_drop_func &&
9221           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9222         {
9223           left_column = cur_column;
9224           continue;
9225         }
9226       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9227       reorder->left_column = left_column;
9228       left_column = reorder->right_column = cur_column;
9229
9230       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9231     }
9232
9233   /* Add the last one */
9234   if (tree_view->priv->column_drop_func == NULL ||
9235       ((left_column != column) &&
9236        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9237     {
9238       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9239       reorder->left_column = left_column;
9240       reorder->right_column = NULL;
9241       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9242     }
9243
9244   /* We quickly check to see if it even makes sense to reorder columns. */
9245   /* If there is nothing that can be moved, then we return */
9246
9247   if (tree_view->priv->column_drag_info == NULL)
9248     return;
9249
9250   /* We know there are always 2 slots possbile, as you can always return column. */
9251   /* If that's all there is, return */
9252   if (tree_view->priv->column_drag_info->next == NULL || 
9253       (tree_view->priv->column_drag_info->next->next == NULL &&
9254        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9255        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9256     {
9257       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9258         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9259       g_list_free (tree_view->priv->column_drag_info);
9260       tree_view->priv->column_drag_info = NULL;
9261       return;
9262     }
9263   /* We fill in the ranges for the columns, now that we've isolated them */
9264   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9265
9266   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9267     {
9268       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9269
9270       reorder->left_align = left;
9271       if (tmp_list->next != NULL)
9272         {
9273           g_assert (tmp_list->next->data);
9274           left = reorder->right_align = (reorder->right_column->button->allocation.x +
9275                                          reorder->right_column->button->allocation.width +
9276                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
9277         }
9278       else
9279         {
9280           gint width;
9281
9282           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9283           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9284         }
9285     }
9286 }
9287
9288 void
9289 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9290                                   GtkTreeViewColumn *column,
9291                                   GdkDevice         *device)
9292 {
9293   GdkEvent *send_event;
9294   GtkAllocation allocation;
9295   gint x, y, width, height;
9296   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9297   GdkDisplay *display = gdk_screen_get_display (screen);
9298
9299   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9300   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9301
9302   gtk_tree_view_set_column_drag_info (tree_view, column);
9303
9304   if (tree_view->priv->column_drag_info == NULL)
9305     return;
9306
9307   if (tree_view->priv->drag_window == NULL)
9308     {
9309       GdkWindowAttr attributes;
9310       guint attributes_mask;
9311
9312       attributes.window_type = GDK_WINDOW_CHILD;
9313       attributes.wclass = GDK_INPUT_OUTPUT;
9314       attributes.x = column->button->allocation.x;
9315       attributes.y = 0;
9316       attributes.width = column->button->allocation.width;
9317       attributes.height = column->button->allocation.height;
9318       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9319       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
9320       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9321       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
9322
9323       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9324                                                      &attributes,
9325                                                      attributes_mask);
9326       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9327     }
9328
9329   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9330   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9331
9332   gtk_grab_remove (column->button);
9333
9334   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9335   send_event->crossing.send_event = TRUE;
9336   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9337   send_event->crossing.subwindow = NULL;
9338   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9339   send_event->crossing.time = GDK_CURRENT_TIME;
9340   gdk_event_set_device (send_event, device);
9341
9342   gtk_propagate_event (column->button, send_event);
9343   gdk_event_free (send_event);
9344
9345   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9346   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9347   send_event->button.send_event = TRUE;
9348   send_event->button.time = GDK_CURRENT_TIME;
9349   send_event->button.x = -1;
9350   send_event->button.y = -1;
9351   send_event->button.axes = NULL;
9352   send_event->button.state = 0;
9353   send_event->button.button = 1;
9354   send_event->button.x_root = 0;
9355   send_event->button.y_root = 0;
9356   gdk_event_set_device (send_event, device);
9357
9358   gtk_propagate_event (column->button, send_event);
9359   gdk_event_free (send_event);
9360
9361   /* Kids, don't try this at home */
9362   g_object_ref (column->button);
9363   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9364   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9365   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9366   g_object_unref (column->button);
9367
9368   tree_view->priv->drag_column_x = column->button->allocation.x;
9369   allocation = column->button->allocation;
9370   allocation.x = 0;
9371   gtk_widget_size_allocate (column->button, &allocation);
9372   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9373
9374   tree_view->priv->drag_column = column;
9375   gdk_window_show (tree_view->priv->drag_window);
9376
9377   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9378   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9379
9380   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9381   while (gtk_events_pending ())
9382     gtk_main_iteration ();
9383
9384   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9385   gdk_pointer_grab (tree_view->priv->drag_window,
9386                     FALSE,
9387                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9388                     NULL, NULL, GDK_CURRENT_TIME);
9389   gdk_keyboard_grab (tree_view->priv->drag_window,
9390                      FALSE,
9391                      GDK_CURRENT_TIME);
9392 }
9393
9394 static void
9395 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9396                                 GtkRBTree          *tree,
9397                                 GtkRBNode          *node,
9398                                 const GdkRectangle *clip_rect)
9399 {
9400   GdkRectangle rect;
9401
9402   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9403     return;
9404
9405   rect.x = 0;
9406   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
9407
9408   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9409   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9410
9411   if (clip_rect)
9412     {
9413       GdkRectangle new_rect;
9414
9415       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9416
9417       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9418     }
9419   else
9420     {
9421       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9422     }
9423 }
9424
9425 void
9426 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9427                                 GtkRBTree          *tree,
9428                                 GtkRBNode          *node,
9429                                 const GdkRectangle *clip_rect)
9430 {
9431   GdkRectangle rect;
9432
9433   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9434     return;
9435
9436   rect.x = 0;
9437   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
9438
9439   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9440   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9441
9442   if (clip_rect)
9443     {
9444       GdkRectangle new_rect;
9445
9446       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9447
9448       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9449     }
9450   else
9451     {
9452       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9453     }
9454 }
9455
9456 static void
9457 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9458                                GtkTreePath        *path,
9459                                const GdkRectangle *clip_rect)
9460 {
9461   GtkRBTree *tree = NULL;
9462   GtkRBNode *node = NULL;
9463
9464   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9465
9466   if (tree)
9467     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9468 }
9469
9470 /* x and y are the mouse position
9471  */
9472 static void
9473 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9474                           GtkRBTree   *tree,
9475                           GtkRBNode   *node,
9476                           /* in bin_window coordinates */
9477                           gint         x,
9478                           gint         y)
9479 {
9480   GdkRectangle area;
9481   GtkStateType state;
9482   GtkWidget *widget;
9483   gint x_offset = 0;
9484   gint x2;
9485   gint vertical_separator;
9486   gint expander_size;
9487   GtkExpanderStyle expander_style;
9488
9489   widget = GTK_WIDGET (tree_view);
9490
9491   gtk_widget_style_get (widget,
9492                         "vertical-separator", &vertical_separator,
9493                         NULL);
9494   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9495
9496   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9497     return;
9498
9499   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9500
9501   area.x = x_offset;
9502   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9503   area.width = expander_size + 2;
9504   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9505
9506   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9507     {
9508       state = GTK_STATE_INSENSITIVE;
9509     }
9510   else if (node == tree_view->priv->button_pressed_node)
9511     {
9512       if (x >= area.x && x <= (area.x + area.width) &&
9513           y >= area.y && y <= (area.y + area.height))
9514         state = GTK_STATE_ACTIVE;
9515       else
9516         state = GTK_STATE_NORMAL;
9517     }
9518   else
9519     {
9520       if (node == tree_view->priv->prelight_node &&
9521           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9522         state = GTK_STATE_PRELIGHT;
9523       else
9524         state = GTK_STATE_NORMAL;
9525     }
9526
9527   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9528     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9529   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9530     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9531   else if (node->children != NULL)
9532     expander_style = GTK_EXPANDER_EXPANDED;
9533   else
9534     expander_style = GTK_EXPANDER_COLLAPSED;
9535
9536   gtk_paint_expander (widget->style,
9537                       tree_view->priv->bin_window,
9538                       state,
9539                       &area,
9540                       widget,
9541                       "treeview",
9542                       area.x + area.width / 2,
9543                       area.y + area.height / 2,
9544                       expander_style);
9545 }
9546
9547 static void
9548 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9549
9550 {
9551   GtkTreePath *cursor_path;
9552
9553   if ((tree_view->priv->tree == NULL) ||
9554       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
9555     return;
9556
9557   cursor_path = NULL;
9558   if (tree_view->priv->cursor)
9559     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9560
9561   if (cursor_path == NULL)
9562     {
9563       /* Consult the selection before defaulting to the
9564        * first focusable element
9565        */
9566       GList *selected_rows;
9567       GtkTreeModel *model;
9568       GtkTreeSelection *selection;
9569
9570       selection = gtk_tree_view_get_selection (tree_view);
9571       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9572
9573       if (selected_rows)
9574         {
9575           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9576           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9577           g_list_free (selected_rows);
9578         }
9579       else
9580         {
9581           cursor_path = gtk_tree_path_new_first ();
9582           search_first_focusable_path (tree_view, &cursor_path,
9583                                        TRUE, NULL, NULL);
9584         }
9585
9586       gtk_tree_row_reference_free (tree_view->priv->cursor);
9587       tree_view->priv->cursor = NULL;
9588
9589       if (cursor_path)
9590         {
9591           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9592             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9593           else
9594             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9595         }
9596     }
9597
9598   if (cursor_path)
9599     {
9600       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9601
9602       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9603       gtk_tree_path_free (cursor_path);
9604
9605       if (tree_view->priv->focus_column == NULL)
9606         {
9607           GList *list;
9608           for (list = tree_view->priv->columns; list; list = list->next)
9609             {
9610               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9611                 {
9612                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9613                   break;
9614                 }
9615             }
9616         }
9617     }
9618 }
9619
9620 static void
9621 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9622                                    gint         count)
9623 {
9624   gint selection_count;
9625   GtkRBTree *cursor_tree = NULL;
9626   GtkRBNode *cursor_node = NULL;
9627   GtkRBTree *new_cursor_tree = NULL;
9628   GtkRBNode *new_cursor_node = NULL;
9629   GtkTreePath *cursor_path = NULL;
9630   gboolean grab_focus = TRUE;
9631   gboolean selectable;
9632
9633   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9634     return;
9635
9636   cursor_path = NULL;
9637   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9638     /* FIXME: we lost the cursor; should we get the first? */
9639     return;
9640
9641   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9642   _gtk_tree_view_find_node (tree_view, cursor_path,
9643                             &cursor_tree, &cursor_node);
9644
9645   if (cursor_tree == NULL)
9646     /* FIXME: we lost the cursor; should we get the first? */
9647     return;
9648
9649   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9650   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9651                                                       cursor_node,
9652                                                       cursor_path);
9653
9654   if (selection_count == 0
9655       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9656       && !tree_view->priv->ctrl_pressed
9657       && selectable)
9658     {
9659       /* Don't move the cursor, but just select the current node */
9660       new_cursor_tree = cursor_tree;
9661       new_cursor_node = cursor_node;
9662     }
9663   else
9664     {
9665       if (count == -1)
9666         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9667                                &new_cursor_tree, &new_cursor_node);
9668       else
9669         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9670                                &new_cursor_tree, &new_cursor_node);
9671     }
9672
9673   gtk_tree_path_free (cursor_path);
9674
9675   if (new_cursor_node)
9676     {
9677       cursor_path = _gtk_tree_view_find_path (tree_view,
9678                                               new_cursor_tree, new_cursor_node);
9679
9680       search_first_focusable_path (tree_view, &cursor_path,
9681                                    (count != -1),
9682                                    &new_cursor_tree,
9683                                    &new_cursor_node);
9684
9685       if (cursor_path)
9686         gtk_tree_path_free (cursor_path);
9687     }
9688
9689   /*
9690    * If the list has only one item and multi-selection is set then select
9691    * the row (if not yet selected).
9692    */
9693   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9694       new_cursor_node == NULL)
9695     {
9696       if (count == -1)
9697         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9698                                &new_cursor_tree, &new_cursor_node);
9699       else
9700         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9701                                &new_cursor_tree, &new_cursor_node);
9702
9703       if (new_cursor_node == NULL
9704           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9705         {
9706           new_cursor_node = cursor_node;
9707           new_cursor_tree = cursor_tree;
9708         }
9709       else
9710         {
9711           new_cursor_node = NULL;
9712         }
9713     }
9714
9715   if (new_cursor_node)
9716     {
9717       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9718       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9719       gtk_tree_path_free (cursor_path);
9720     }
9721   else
9722     {
9723       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9724
9725       if (!tree_view->priv->shift_pressed)
9726         {
9727           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9728                                           count < 0 ?
9729                                           GTK_DIR_UP : GTK_DIR_DOWN))
9730             {
9731               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9732
9733               if (toplevel)
9734                 gtk_widget_child_focus (toplevel,
9735                                         count < 0 ?
9736                                         GTK_DIR_TAB_BACKWARD :
9737                                         GTK_DIR_TAB_FORWARD);
9738
9739               grab_focus = FALSE;
9740             }
9741         }
9742       else
9743         {
9744           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9745         }
9746     }
9747
9748   if (grab_focus)
9749     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9750 }
9751
9752 static void
9753 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9754                                         gint         count)
9755 {
9756   GtkRBTree *cursor_tree = NULL;
9757   GtkRBNode *cursor_node = NULL;
9758   GtkTreePath *old_cursor_path = NULL;
9759   GtkTreePath *cursor_path = NULL;
9760   GtkRBTree *start_cursor_tree = NULL;
9761   GtkRBNode *start_cursor_node = NULL;
9762   gint y;
9763   gint window_y;
9764   gint vertical_separator;
9765
9766   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9767     return;
9768
9769   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9770     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9771   else
9772     /* This is sorta weird.  Focus in should give us a cursor */
9773     return;
9774
9775   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9776   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9777                             &cursor_tree, &cursor_node);
9778
9779   if (cursor_tree == NULL)
9780     {
9781       /* FIXME: we lost the cursor.  Should we try to get one? */
9782       gtk_tree_path_free (old_cursor_path);
9783       return;
9784     }
9785   g_return_if_fail (cursor_node != NULL);
9786
9787   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9788   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9789   y += tree_view->priv->cursor_offset;
9790   y += count * (int)tree_view->priv->vadjustment->page_increment;
9791   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9792
9793   if (y >= tree_view->priv->height)
9794     y = tree_view->priv->height - 1;
9795
9796   tree_view->priv->cursor_offset =
9797     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9798                              &cursor_tree, &cursor_node);
9799
9800   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9801     {
9802       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9803                              &cursor_tree, &cursor_node);
9804       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9805     }
9806
9807   y -= tree_view->priv->cursor_offset;
9808   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9809
9810   start_cursor_tree = cursor_tree;
9811   start_cursor_node = cursor_node;
9812
9813   if (! search_first_focusable_path (tree_view, &cursor_path,
9814                                      (count != -1),
9815                                      &cursor_tree, &cursor_node))
9816     {
9817       /* It looks like we reached the end of the view without finding
9818        * a focusable row.  We will step backwards to find the last
9819        * focusable row.
9820        */
9821       cursor_tree = start_cursor_tree;
9822       cursor_node = start_cursor_node;
9823       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9824
9825       search_first_focusable_path (tree_view, &cursor_path,
9826                                    (count == -1),
9827                                    &cursor_tree, &cursor_node);
9828     }
9829
9830   if (!cursor_path)
9831     goto cleanup;
9832
9833   /* update y */
9834   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9835
9836   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9837
9838   y -= window_y;
9839   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9840   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9841   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9842
9843   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9844     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9845
9846   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9847
9848 cleanup:
9849   gtk_tree_path_free (old_cursor_path);
9850   gtk_tree_path_free (cursor_path);
9851 }
9852
9853 static void
9854 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9855                                       gint         count)
9856 {
9857   GtkRBTree *cursor_tree = NULL;
9858   GtkRBNode *cursor_node = NULL;
9859   GtkTreePath *cursor_path = NULL;
9860   GtkTreeViewColumn *column;
9861   GtkTreeIter iter;
9862   GList *list;
9863   gboolean found_column = FALSE;
9864   gboolean rtl;
9865
9866   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9867
9868   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9869     return;
9870
9871   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9872     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9873   else
9874     return;
9875
9876   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9877   if (cursor_tree == NULL)
9878     return;
9879   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9880     {
9881       gtk_tree_path_free (cursor_path);
9882       return;
9883     }
9884   gtk_tree_path_free (cursor_path);
9885
9886   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9887   if (tree_view->priv->focus_column)
9888     {
9889       for (; list; list = (rtl ? list->prev : list->next))
9890         {
9891           if (list->data == tree_view->priv->focus_column)
9892             break;
9893         }
9894     }
9895
9896   while (list)
9897     {
9898       gboolean left, right;
9899
9900       column = list->data;
9901       if (column->visible == FALSE)
9902         goto loop_end;
9903
9904       gtk_tree_view_column_cell_set_cell_data (column,
9905                                                tree_view->priv->model,
9906                                                &iter,
9907                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9908                                                cursor_node->children?TRUE:FALSE);
9909
9910       if (rtl)
9911         {
9912           right = list->prev ? TRUE : FALSE;
9913           left = list->next ? TRUE : FALSE;
9914         }
9915       else
9916         {
9917           left = list->prev ? TRUE : FALSE;
9918           right = list->next ? TRUE : FALSE;
9919         }
9920
9921       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9922         {
9923           tree_view->priv->focus_column = column;
9924           found_column = TRUE;
9925           break;
9926         }
9927     loop_end:
9928       if (count == 1)
9929         list = rtl ? list->prev : list->next;
9930       else
9931         list = rtl ? list->next : list->prev;
9932     }
9933
9934   if (found_column)
9935     {
9936       if (!gtk_tree_view_has_special_cell (tree_view))
9937         _gtk_tree_view_queue_draw_node (tree_view,
9938                                         cursor_tree,
9939                                         cursor_node,
9940                                         NULL);
9941       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9942       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9943     }
9944   else
9945     {
9946       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9947     }
9948
9949   gtk_tree_view_clamp_column_visible (tree_view,
9950                                       tree_view->priv->focus_column, TRUE);
9951 }
9952
9953 static void
9954 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9955                                      gint         count)
9956 {
9957   GtkRBTree *cursor_tree;
9958   GtkRBNode *cursor_node;
9959   GtkTreePath *path;
9960   GtkTreePath *old_path;
9961
9962   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9963     return;
9964
9965   g_return_if_fail (tree_view->priv->tree != NULL);
9966
9967   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9968
9969   cursor_tree = tree_view->priv->tree;
9970   cursor_node = cursor_tree->root;
9971
9972   if (count == -1)
9973     {
9974       while (cursor_node && cursor_node->left != cursor_tree->nil)
9975         cursor_node = cursor_node->left;
9976
9977       /* Now go forward to find the first focusable row. */
9978       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9979       search_first_focusable_path (tree_view, &path,
9980                                    TRUE, &cursor_tree, &cursor_node);
9981     }
9982   else
9983     {
9984       do
9985         {
9986           while (cursor_node && cursor_node->right != cursor_tree->nil)
9987             cursor_node = cursor_node->right;
9988           if (cursor_node->children == NULL)
9989             break;
9990
9991           cursor_tree = cursor_node->children;
9992           cursor_node = cursor_tree->root;
9993         }
9994       while (1);
9995
9996       /* Now go backwards to find last focusable row. */
9997       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9998       search_first_focusable_path (tree_view, &path,
9999                                    FALSE, &cursor_tree, &cursor_node);
10000     }
10001
10002   if (!path)
10003     goto cleanup;
10004
10005   if (gtk_tree_path_compare (old_path, path))
10006     {
10007       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10008       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10009     }
10010   else
10011     {
10012       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10013     }
10014
10015 cleanup:
10016   gtk_tree_path_free (old_path);
10017   gtk_tree_path_free (path);
10018 }
10019
10020 static gboolean
10021 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10022 {
10023   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10024     return FALSE;
10025
10026   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10027     return FALSE;
10028
10029   gtk_tree_selection_select_all (tree_view->priv->selection);
10030
10031   return TRUE;
10032 }
10033
10034 static gboolean
10035 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10036 {
10037   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10038     return FALSE;
10039
10040   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10041     return FALSE;
10042
10043   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10044
10045   return TRUE;
10046 }
10047
10048 static gboolean
10049 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10050                                       gboolean     start_editing)
10051 {
10052   GtkRBTree *new_tree = NULL;
10053   GtkRBNode *new_node = NULL;
10054   GtkRBTree *cursor_tree = NULL;
10055   GtkRBNode *cursor_node = NULL;
10056   GtkTreePath *cursor_path = NULL;
10057   GtkTreeSelectMode mode = 0;
10058
10059   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10060     return FALSE;
10061
10062   if (tree_view->priv->cursor)
10063     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10064
10065   if (cursor_path == NULL)
10066     return FALSE;
10067
10068   _gtk_tree_view_find_node (tree_view, cursor_path,
10069                             &cursor_tree, &cursor_node);
10070
10071   if (cursor_tree == NULL)
10072     {
10073       gtk_tree_path_free (cursor_path);
10074       return FALSE;
10075     }
10076
10077   if (!tree_view->priv->shift_pressed && start_editing &&
10078       tree_view->priv->focus_column)
10079     {
10080       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10081         {
10082           gtk_tree_path_free (cursor_path);
10083           return TRUE;
10084         }
10085     }
10086
10087   if (tree_view->priv->ctrl_pressed)
10088     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10089   if (tree_view->priv->shift_pressed)
10090     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10091
10092   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10093                                             cursor_node,
10094                                             cursor_tree,
10095                                             cursor_path,
10096                                             mode,
10097                                             FALSE);
10098
10099   /* We bail out if the original (tree, node) don't exist anymore after
10100    * handling the selection-changed callback.  We do return TRUE because
10101    * the key press has been handled at this point.
10102    */
10103   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10104
10105   if (cursor_tree != new_tree || cursor_node != new_node)
10106     return FALSE;
10107
10108   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10109
10110   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10111   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10112
10113   if (!tree_view->priv->shift_pressed)
10114     gtk_tree_view_row_activated (tree_view, cursor_path,
10115                                  tree_view->priv->focus_column);
10116     
10117   gtk_tree_path_free (cursor_path);
10118
10119   return TRUE;
10120 }
10121
10122 static gboolean
10123 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10124 {
10125   GtkRBTree *new_tree = NULL;
10126   GtkRBNode *new_node = NULL;
10127   GtkRBTree *cursor_tree = NULL;
10128   GtkRBNode *cursor_node = NULL;
10129   GtkTreePath *cursor_path = NULL;
10130
10131   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10132     return FALSE;
10133
10134   cursor_path = NULL;
10135   if (tree_view->priv->cursor)
10136     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10137
10138   if (cursor_path == NULL)
10139     return FALSE;
10140
10141   _gtk_tree_view_find_node (tree_view, cursor_path,
10142                             &cursor_tree, &cursor_node);
10143   if (cursor_tree == NULL)
10144     {
10145       gtk_tree_path_free (cursor_path);
10146       return FALSE;
10147     }
10148
10149   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10150                                             cursor_node,
10151                                             cursor_tree,
10152                                             cursor_path,
10153                                             GTK_TREE_SELECT_MODE_TOGGLE,
10154                                             FALSE);
10155
10156   /* We bail out if the original (tree, node) don't exist anymore after
10157    * handling the selection-changed callback.  We do return TRUE because
10158    * the key press has been handled at this point.
10159    */
10160   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10161
10162   if (cursor_tree != new_tree || cursor_node != new_node)
10163     return FALSE;
10164
10165   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10166
10167   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10168   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10169   gtk_tree_path_free (cursor_path);
10170
10171   return TRUE;
10172 }
10173
10174 static gboolean
10175 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10176                                                gboolean     logical,
10177                                                gboolean     expand,
10178                                                gboolean     open_all)
10179 {
10180   GtkTreePath *cursor_path = NULL;
10181   GtkRBTree *tree;
10182   GtkRBNode *node;
10183
10184   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10185     return FALSE;
10186
10187   cursor_path = NULL;
10188   if (tree_view->priv->cursor)
10189     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10190
10191   if (cursor_path == NULL)
10192     return FALSE;
10193
10194   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10195     return FALSE;
10196
10197   /* Don't handle the event if we aren't an expander */
10198   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10199     return FALSE;
10200
10201   if (!logical
10202       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10203     expand = !expand;
10204
10205   if (expand)
10206     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10207   else
10208     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10209
10210   gtk_tree_path_free (cursor_path);
10211
10212   return TRUE;
10213 }
10214
10215 static gboolean
10216 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10217 {
10218   GtkRBTree *cursor_tree = NULL;
10219   GtkRBNode *cursor_node = NULL;
10220   GtkTreePath *cursor_path = NULL;
10221   GdkModifierType state;
10222
10223   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10224     goto out;
10225
10226   cursor_path = NULL;
10227   if (tree_view->priv->cursor)
10228     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10229
10230   if (cursor_path == NULL)
10231     goto out;
10232
10233   _gtk_tree_view_find_node (tree_view, cursor_path,
10234                             &cursor_tree, &cursor_node);
10235   if (cursor_tree == NULL)
10236     {
10237       gtk_tree_path_free (cursor_path);
10238       goto out;
10239     }
10240
10241   if (cursor_tree->parent_node)
10242     {
10243       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10244       cursor_node = cursor_tree->parent_node;
10245       cursor_tree = cursor_tree->parent_tree;
10246
10247       gtk_tree_path_up (cursor_path);
10248
10249       if (gtk_get_current_event_state (&state))
10250         {
10251           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10252             tree_view->priv->ctrl_pressed = TRUE;
10253         }
10254
10255       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10256       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10257
10258       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10259       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10260       gtk_tree_path_free (cursor_path);
10261
10262       tree_view->priv->ctrl_pressed = FALSE;
10263
10264       return TRUE;
10265     }
10266
10267  out:
10268
10269   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10270   return FALSE;
10271 }
10272
10273 static gboolean
10274 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10275 {
10276   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10277   tree_view->priv->typeselect_flush_timeout = 0;
10278
10279   return FALSE;
10280 }
10281
10282 /* Cut and paste from gtkwindow.c */
10283 static void
10284 send_focus_change (GtkWidget *widget,
10285                    GdkDevice *device,
10286                    gboolean   in)
10287 {
10288   GdkDeviceManager *device_manager;
10289   GList *devices, *d;
10290
10291   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10292   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10293   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10294   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10295
10296   for (d = devices; d; d = d->next)
10297     {
10298       GdkDevice *dev = d->data;
10299       GdkEvent *fevent;
10300
10301       if (dev->source != GDK_SOURCE_KEYBOARD)
10302         continue;
10303
10304       /* Skip non-master keyboards that haven't
10305        * selected for events from this window
10306        */
10307       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10308           !gdk_window_get_device_events (widget->window, dev))
10309         continue;
10310
10311       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10312
10313       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10314       fevent->focus_change.window = g_object_ref (widget->window);
10315       fevent->focus_change.in = in;
10316       gdk_event_set_device (fevent, device);
10317
10318       gtk_widget_send_focus_change (widget, fevent);
10319
10320       gdk_event_free (fevent);
10321     }
10322 }
10323
10324 static void
10325 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10326 {
10327   GtkWidget *frame, *vbox, *toplevel;
10328   GdkScreen *screen;
10329
10330   if (tree_view->priv->search_custom_entry_set)
10331     return;
10332
10333   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10334   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10335
10336    if (tree_view->priv->search_window != NULL)
10337      {
10338        if (GTK_WINDOW (toplevel)->group)
10339          gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10340                                       GTK_WINDOW (tree_view->priv->search_window));
10341        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
10342          gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
10343                                          GTK_WINDOW (tree_view->priv->search_window));
10344        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10345        return;
10346      }
10347    
10348   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10349   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10350
10351   if (GTK_WINDOW (toplevel)->group)
10352     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10353                                  GTK_WINDOW (tree_view->priv->search_window));
10354
10355   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10356                             GDK_WINDOW_TYPE_HINT_UTILITY);
10357   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10358   g_signal_connect (tree_view->priv->search_window, "delete-event",
10359                     G_CALLBACK (gtk_tree_view_search_delete_event),
10360                     tree_view);
10361   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10362                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10363                     tree_view);
10364   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10365                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10366                     tree_view);
10367   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10368                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10369                     tree_view);
10370
10371   frame = gtk_frame_new (NULL);
10372   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10373   gtk_widget_show (frame);
10374   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10375
10376   vbox = gtk_vbox_new (FALSE, 0);
10377   gtk_widget_show (vbox);
10378   gtk_container_add (GTK_CONTAINER (frame), vbox);
10379   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10380
10381   /* add entry */
10382   tree_view->priv->search_entry = gtk_entry_new ();
10383   gtk_widget_show (tree_view->priv->search_entry);
10384   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10385                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10386                     tree_view);
10387   g_signal_connect (tree_view->priv->search_entry,
10388                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10389                     tree_view);
10390   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10391                     "preedit-changed",
10392                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10393                     tree_view);
10394   gtk_container_add (GTK_CONTAINER (vbox),
10395                      tree_view->priv->search_entry);
10396
10397   gtk_widget_realize (tree_view->priv->search_entry);
10398 }
10399
10400 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10401  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10402  */
10403 static gboolean
10404 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10405                                              GdkDevice   *device,
10406                                              gboolean     keybinding)
10407 {
10408   /* We only start interactive search if we have focus or the columns
10409    * have focus.  If one of our children have focus, we don't want to
10410    * start the search.
10411    */
10412   GList *list;
10413   gboolean found_focus = FALSE;
10414   GtkWidgetClass *entry_parent_class;
10415   
10416   if (!tree_view->priv->enable_search && !keybinding)
10417     return FALSE;
10418
10419   if (tree_view->priv->search_custom_entry_set)
10420     return FALSE;
10421
10422   if (tree_view->priv->search_window != NULL &&
10423       gtk_widget_get_visible (tree_view->priv->search_window))
10424     return TRUE;
10425
10426   for (list = tree_view->priv->columns; list; list = list->next)
10427     {
10428       GtkTreeViewColumn *column;
10429
10430       column = list->data;
10431       if (! column->visible)
10432         continue;
10433
10434       if (gtk_widget_has_focus (column->button))
10435         {
10436           found_focus = TRUE;
10437           break;
10438         }
10439     }
10440   
10441   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10442     found_focus = TRUE;
10443
10444   if (!found_focus)
10445     return FALSE;
10446
10447   if (tree_view->priv->search_column < 0)
10448     return FALSE;
10449
10450   gtk_tree_view_ensure_interactive_directory (tree_view);
10451
10452   if (keybinding)
10453     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10454
10455   /* done, show it */
10456   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10457   gtk_widget_show (tree_view->priv->search_window);
10458   if (tree_view->priv->search_entry_changed_id == 0)
10459     {
10460       tree_view->priv->search_entry_changed_id =
10461         g_signal_connect (tree_view->priv->search_entry, "changed",
10462                           G_CALLBACK (gtk_tree_view_search_init),
10463                           tree_view);
10464     }
10465
10466   tree_view->priv->typeselect_flush_timeout =
10467     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10468                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10469                    tree_view);
10470
10471   /* Grab focus will select all the text.  We don't want that to happen, so we
10472    * call the parent instance and bypass the selection change.  This is probably
10473    * really non-kosher. */
10474   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10475   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10476
10477   /* send focus-in event */
10478   send_focus_change (tree_view->priv->search_entry, device, TRUE);
10479
10480   /* search first matching iter */
10481   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10482
10483   return TRUE;
10484 }
10485
10486 static gboolean
10487 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10488 {
10489   return gtk_tree_view_real_start_interactive_search (tree_view,
10490                                                       gtk_get_current_event_device (),
10491                                                       TRUE);
10492 }
10493
10494 /* this function returns the new width of the column being resized given
10495  * the column and x position of the cursor; the x cursor position is passed
10496  * in as a pointer and automagicly corrected if it's beyond min/max limits
10497  */
10498 static gint
10499 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10500                                 gint       i,
10501                                 gint      *x)
10502 {
10503   GtkTreeViewColumn *column;
10504   gint width;
10505   gboolean rtl;
10506
10507   /* first translate the x position from widget->window
10508    * to clist->clist_window
10509    */
10510   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10511   column = g_list_nth (tree_view->priv->columns, i)->data;
10512   width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
10513  
10514   /* Clamp down the value */
10515   if (column->min_width == -1)
10516     width = MAX (column->button->requisition.width,
10517                  width);
10518   else
10519     width = MAX (column->min_width,
10520                  width);
10521   if (column->max_width != -1)
10522     width = MIN (width, column->max_width);
10523
10524   *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
10525  
10526   return width;
10527 }
10528
10529
10530 /* FIXME this adjust_allocation is a big cut-and-paste from
10531  * GtkCList, needs to be some "official" way to do this
10532  * factored out.
10533  */
10534 typedef struct
10535 {
10536   GdkWindow *window;
10537   int dx;
10538   int dy;
10539 } ScrollData;
10540
10541 /* The window to which widget->window is relative */
10542 #define ALLOCATION_WINDOW(widget)               \
10543    (!gtk_widget_get_has_window (widget) ?               \
10544     (widget)->window :                          \
10545      gdk_window_get_parent ((widget)->window))
10546
10547 static void
10548 adjust_allocation_recurse (GtkWidget *widget,
10549                            gpointer   data)
10550 {
10551   ScrollData *scroll_data = data;
10552
10553   /* Need to really size allocate instead of just poking
10554    * into widget->allocation if the widget is not realized.
10555    * FIXME someone figure out why this was.
10556    */
10557   if (!gtk_widget_get_realized (widget))
10558     {
10559       if (gtk_widget_get_visible (widget))
10560         {
10561           GdkRectangle tmp_rectangle = widget->allocation;
10562           tmp_rectangle.x += scroll_data->dx;
10563           tmp_rectangle.y += scroll_data->dy;
10564           
10565           gtk_widget_size_allocate (widget, &tmp_rectangle);
10566         }
10567     }
10568   else
10569     {
10570       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10571         {
10572           widget->allocation.x += scroll_data->dx;
10573           widget->allocation.y += scroll_data->dy;
10574           
10575           if (GTK_IS_CONTAINER (widget))
10576             gtk_container_forall (GTK_CONTAINER (widget),
10577                                   adjust_allocation_recurse,
10578                                   data);
10579         }
10580     }
10581 }
10582
10583 static void
10584 adjust_allocation (GtkWidget *widget,
10585                    int        dx,
10586                    int        dy)
10587 {
10588   ScrollData scroll_data;
10589
10590   if (gtk_widget_get_realized (widget))
10591     scroll_data.window = ALLOCATION_WINDOW (widget);
10592   else
10593     scroll_data.window = NULL;
10594     
10595   scroll_data.dx = dx;
10596   scroll_data.dy = dy;
10597   
10598   adjust_allocation_recurse (widget, &scroll_data);
10599 }
10600
10601 /* Callbacks */
10602 static void
10603 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10604                                   GtkTreeView   *tree_view)
10605 {
10606   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10607     {
10608       gint dy;
10609         
10610       gdk_window_move (tree_view->priv->bin_window,
10611                        - tree_view->priv->hadjustment->value,
10612                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10613       gdk_window_move (tree_view->priv->header_window,
10614                        - tree_view->priv->hadjustment->value,
10615                        0);
10616       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10617       if (dy)
10618         {
10619           update_prelight (tree_view,
10620                            tree_view->priv->event_last_x,
10621                            tree_view->priv->event_last_y - dy);
10622
10623           if (tree_view->priv->edited_column &&
10624               GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10625             {
10626               GList *list;
10627               GtkWidget *widget;
10628               GtkTreeViewChild *child = NULL;
10629
10630               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10631               adjust_allocation (widget, 0, dy); 
10632               
10633               for (list = tree_view->priv->children; list; list = list->next)
10634                 {
10635                   child = (GtkTreeViewChild *)list->data;
10636                   if (child->widget == widget)
10637                     {
10638                       child->y += dy;
10639                       break;
10640                     }
10641                 }
10642             }
10643         }
10644       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10645
10646       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10647         {
10648           /* update our dy and top_row */
10649           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10650
10651           if (!tree_view->priv->in_top_row_to_dy)
10652             gtk_tree_view_dy_to_top_row (tree_view);
10653         }
10654
10655       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10656       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
10657     }
10658 }
10659
10660 \f
10661
10662 /* Public methods
10663  */
10664
10665 /**
10666  * gtk_tree_view_new:
10667  *
10668  * Creates a new #GtkTreeView widget.
10669  *
10670  * Return value: A newly created #GtkTreeView widget.
10671  **/
10672 GtkWidget *
10673 gtk_tree_view_new (void)
10674 {
10675   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10676 }
10677
10678 /**
10679  * gtk_tree_view_new_with_model:
10680  * @model: the model.
10681  *
10682  * Creates a new #GtkTreeView widget with the model initialized to @model.
10683  *
10684  * Return value: A newly created #GtkTreeView widget.
10685  **/
10686 GtkWidget *
10687 gtk_tree_view_new_with_model (GtkTreeModel *model)
10688 {
10689   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10690 }
10691
10692 /* Public Accessors
10693  */
10694
10695 /**
10696  * gtk_tree_view_get_model:
10697  * @tree_view: a #GtkTreeView
10698  *
10699  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10700  * model is unset.
10701  *
10702  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
10703  **/
10704 GtkTreeModel *
10705 gtk_tree_view_get_model (GtkTreeView *tree_view)
10706 {
10707   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10708
10709   return tree_view->priv->model;
10710 }
10711
10712 /**
10713  * gtk_tree_view_set_model:
10714  * @tree_view: A #GtkTreeNode.
10715  * @model: (allow-none): The model.
10716  *
10717  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10718  * set, it will remove it before setting the new model.  If @model is %NULL,
10719  * then it will unset the old model.
10720  **/
10721 void
10722 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10723                          GtkTreeModel *model)
10724 {
10725   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10726   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10727
10728   if (model == tree_view->priv->model)
10729     return;
10730
10731   if (tree_view->priv->scroll_to_path)
10732     {
10733       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10734       tree_view->priv->scroll_to_path = NULL;
10735     }
10736
10737   if (tree_view->priv->model)
10738     {
10739       GList *tmplist = tree_view->priv->columns;
10740
10741       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10742       gtk_tree_view_stop_editing (tree_view, TRUE);
10743
10744       remove_expand_collapse_timeout (tree_view);
10745
10746       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10747                                             gtk_tree_view_row_changed,
10748                                             tree_view);
10749       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10750                                             gtk_tree_view_row_inserted,
10751                                             tree_view);
10752       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10753                                             gtk_tree_view_row_has_child_toggled,
10754                                             tree_view);
10755       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10756                                             gtk_tree_view_row_deleted,
10757                                             tree_view);
10758       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10759                                             gtk_tree_view_rows_reordered,
10760                                             tree_view);
10761
10762       for (; tmplist; tmplist = tmplist->next)
10763         _gtk_tree_view_column_unset_model (tmplist->data,
10764                                            tree_view->priv->model);
10765
10766       if (tree_view->priv->tree)
10767         gtk_tree_view_free_rbtree (tree_view);
10768
10769       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10770       tree_view->priv->drag_dest_row = NULL;
10771       gtk_tree_row_reference_free (tree_view->priv->cursor);
10772       tree_view->priv->cursor = NULL;
10773       gtk_tree_row_reference_free (tree_view->priv->anchor);
10774       tree_view->priv->anchor = NULL;
10775       gtk_tree_row_reference_free (tree_view->priv->top_row);
10776       tree_view->priv->top_row = NULL;
10777       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10778       tree_view->priv->scroll_to_path = NULL;
10779
10780       tree_view->priv->scroll_to_column = NULL;
10781
10782       g_object_unref (tree_view->priv->model);
10783
10784       tree_view->priv->search_column = -1;
10785       tree_view->priv->fixed_height_check = 0;
10786       tree_view->priv->fixed_height = -1;
10787       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10788       tree_view->priv->last_button_x = -1;
10789       tree_view->priv->last_button_y = -1;
10790     }
10791
10792   tree_view->priv->model = model;
10793
10794   if (tree_view->priv->model)
10795     {
10796       gint i;
10797       GtkTreePath *path;
10798       GtkTreeIter iter;
10799       GtkTreeModelFlags flags;
10800
10801       if (tree_view->priv->search_column == -1)
10802         {
10803           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10804             {
10805               GType type = gtk_tree_model_get_column_type (model, i);
10806
10807               if (g_value_type_transformable (type, G_TYPE_STRING))
10808                 {
10809                   tree_view->priv->search_column = i;
10810                   break;
10811                 }
10812             }
10813         }
10814
10815       g_object_ref (tree_view->priv->model);
10816       g_signal_connect (tree_view->priv->model,
10817                         "row-changed",
10818                         G_CALLBACK (gtk_tree_view_row_changed),
10819                         tree_view);
10820       g_signal_connect (tree_view->priv->model,
10821                         "row-inserted",
10822                         G_CALLBACK (gtk_tree_view_row_inserted),
10823                         tree_view);
10824       g_signal_connect (tree_view->priv->model,
10825                         "row-has-child-toggled",
10826                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10827                         tree_view);
10828       g_signal_connect (tree_view->priv->model,
10829                         "row-deleted",
10830                         G_CALLBACK (gtk_tree_view_row_deleted),
10831                         tree_view);
10832       g_signal_connect (tree_view->priv->model,
10833                         "rows-reordered",
10834                         G_CALLBACK (gtk_tree_view_rows_reordered),
10835                         tree_view);
10836
10837       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10838       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10839         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10840       else
10841         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10842
10843       path = gtk_tree_path_new_first ();
10844       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10845         {
10846           tree_view->priv->tree = _gtk_rbtree_new ();
10847           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10848         }
10849       gtk_tree_path_free (path);
10850
10851       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10852       install_presize_handler (tree_view);
10853     }
10854
10855   g_object_notify (G_OBJECT (tree_view), "model");
10856
10857   if (tree_view->priv->selection)
10858   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10859
10860   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10861     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10862 }
10863
10864 /**
10865  * gtk_tree_view_get_selection:
10866  * @tree_view: A #GtkTreeView.
10867  *
10868  * Gets the #GtkTreeSelection associated with @tree_view.
10869  *
10870  * Return value: (transfer none): A #GtkTreeSelection object.
10871  **/
10872 GtkTreeSelection *
10873 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10874 {
10875   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10876
10877   return tree_view->priv->selection;
10878 }
10879
10880 /**
10881  * gtk_tree_view_get_hadjustment:
10882  * @tree_view: A #GtkTreeView
10883  *
10884  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10885  *
10886  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10887  * used.
10888  **/
10889 GtkAdjustment *
10890 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10891 {
10892   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10893
10894   if (tree_view->priv->hadjustment == NULL)
10895     gtk_tree_view_set_hadjustment (tree_view, NULL);
10896
10897   return tree_view->priv->hadjustment;
10898 }
10899
10900 /**
10901  * gtk_tree_view_set_hadjustment:
10902  * @tree_view: A #GtkTreeView
10903  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10904  *
10905  * Sets the #GtkAdjustment for the current horizontal aspect.
10906  **/
10907 void
10908 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10909                                GtkAdjustment *adjustment)
10910 {
10911   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10912
10913   gtk_tree_view_set_adjustments (tree_view,
10914                                  adjustment,
10915                                  tree_view->priv->vadjustment);
10916
10917   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10918 }
10919
10920 /**
10921  * gtk_tree_view_get_vadjustment:
10922  * @tree_view: A #GtkTreeView
10923  *
10924  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10925  *
10926  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10927  * used.
10928  **/
10929 GtkAdjustment *
10930 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10931 {
10932   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10933
10934   if (tree_view->priv->vadjustment == NULL)
10935     gtk_tree_view_set_vadjustment (tree_view, NULL);
10936
10937   return tree_view->priv->vadjustment;
10938 }
10939
10940 /**
10941  * gtk_tree_view_set_vadjustment:
10942  * @tree_view: A #GtkTreeView
10943  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10944  *
10945  * Sets the #GtkAdjustment for the current vertical aspect.
10946  **/
10947 void
10948 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10949                                GtkAdjustment *adjustment)
10950 {
10951   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10952
10953   gtk_tree_view_set_adjustments (tree_view,
10954                                  tree_view->priv->hadjustment,
10955                                  adjustment);
10956
10957   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10958 }
10959
10960 /* Column and header operations */
10961
10962 /**
10963  * gtk_tree_view_get_headers_visible:
10964  * @tree_view: A #GtkTreeView.
10965  *
10966  * Returns %TRUE if the headers on the @tree_view are visible.
10967  *
10968  * Return value: Whether the headers are visible or not.
10969  **/
10970 gboolean
10971 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10972 {
10973   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10974
10975   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10976 }
10977
10978 /**
10979  * gtk_tree_view_set_headers_visible:
10980  * @tree_view: A #GtkTreeView.
10981  * @headers_visible: %TRUE if the headers are visible
10982  *
10983  * Sets the visibility state of the headers.
10984  **/
10985 void
10986 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
10987                                    gboolean     headers_visible)
10988 {
10989   gint x, y;
10990   GList *list;
10991   GtkTreeViewColumn *column;
10992
10993   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10994
10995   headers_visible = !! headers_visible;
10996
10997   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
10998     return;
10999
11000   if (headers_visible)
11001     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11002   else
11003     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11004
11005   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11006     {
11007       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11008       if (headers_visible)
11009         {
11010           gdk_window_move_resize (tree_view->priv->bin_window, x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view), tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
11011
11012           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11013             gtk_tree_view_map_buttons (tree_view);
11014         }
11015       else
11016         {
11017           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11018
11019           for (list = tree_view->priv->columns; list; list = list->next)
11020             {
11021               column = list->data;
11022               gtk_widget_unmap (column->button);
11023             }
11024           gdk_window_hide (tree_view->priv->header_window);
11025         }
11026     }
11027
11028   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11029   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11030   tree_view->priv->vadjustment->lower = 0;
11031   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11032   gtk_adjustment_changed (tree_view->priv->vadjustment);
11033
11034   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11035
11036   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11037 }
11038
11039 /**
11040  * gtk_tree_view_columns_autosize:
11041  * @tree_view: A #GtkTreeView.
11042  *
11043  * Resizes all columns to their optimal width. Only works after the
11044  * treeview has been realized.
11045  **/
11046 void
11047 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11048 {
11049   gboolean dirty = FALSE;
11050   GList *list;
11051   GtkTreeViewColumn *column;
11052
11053   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11054
11055   for (list = tree_view->priv->columns; list; list = list->next)
11056     {
11057       column = list->data;
11058       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11059         continue;
11060       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11061       dirty = TRUE;
11062     }
11063
11064   if (dirty)
11065     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11066 }
11067
11068 /**
11069  * gtk_tree_view_set_headers_clickable:
11070  * @tree_view: A #GtkTreeView.
11071  * @setting: %TRUE if the columns are clickable.
11072  *
11073  * Allow the column title buttons to be clicked.
11074  **/
11075 void
11076 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11077                                      gboolean   setting)
11078 {
11079   GList *list;
11080
11081   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11082
11083   for (list = tree_view->priv->columns; list; list = list->next)
11084     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11085
11086   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11087 }
11088
11089
11090 /**
11091  * gtk_tree_view_get_headers_clickable:
11092  * @tree_view: A #GtkTreeView.
11093  *
11094  * Returns whether all header columns are clickable.
11095  *
11096  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11097  *
11098  * Since: 2.10
11099  **/
11100 gboolean 
11101 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11102 {
11103   GList *list;
11104   
11105   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11106
11107   for (list = tree_view->priv->columns; list; list = list->next)
11108     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11109       return FALSE;
11110
11111   return TRUE;
11112 }
11113
11114 /**
11115  * gtk_tree_view_set_rules_hint
11116  * @tree_view: a #GtkTreeView
11117  * @setting: %TRUE if the tree requires reading across rows
11118  *
11119  * This function tells GTK+ that the user interface for your
11120  * application requires users to read across tree rows and associate
11121  * cells with one another. By default, GTK+ will then render the tree
11122  * with alternating row colors. Do <emphasis>not</emphasis> use it
11123  * just because you prefer the appearance of the ruled tree; that's a
11124  * question for the theme. Some themes will draw tree rows in
11125  * alternating colors even when rules are turned off, and users who
11126  * prefer that appearance all the time can choose those themes. You
11127  * should call this function only as a <emphasis>semantic</emphasis>
11128  * hint to the theme engine that your tree makes alternating colors
11129  * useful from a functional standpoint (since it has lots of columns,
11130  * generally).
11131  *
11132  **/
11133 void
11134 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11135                               gboolean      setting)
11136 {
11137   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11138
11139   setting = setting != FALSE;
11140
11141   if (tree_view->priv->has_rules != setting)
11142     {
11143       tree_view->priv->has_rules = setting;
11144       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11145     }
11146
11147   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11148 }
11149
11150 /**
11151  * gtk_tree_view_get_rules_hint
11152  * @tree_view: a #GtkTreeView
11153  *
11154  * Gets the setting set by gtk_tree_view_set_rules_hint().
11155  *
11156  * Return value: %TRUE if rules are useful for the user of this tree
11157  **/
11158 gboolean
11159 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11160 {
11161   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11162
11163   return tree_view->priv->has_rules;
11164 }
11165
11166 /* Public Column functions
11167  */
11168
11169 /**
11170  * gtk_tree_view_append_column:
11171  * @tree_view: A #GtkTreeView.
11172  * @column: The #GtkTreeViewColumn to add.
11173  *
11174  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11175  * mode enabled, then @column must have its "sizing" property set to be
11176  * GTK_TREE_VIEW_COLUMN_FIXED.
11177  *
11178  * Return value: The number of columns in @tree_view after appending.
11179  **/
11180 gint
11181 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11182                              GtkTreeViewColumn *column)
11183 {
11184   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11185   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11186   g_return_val_if_fail (column->tree_view == NULL, -1);
11187
11188   return gtk_tree_view_insert_column (tree_view, column, -1);
11189 }
11190
11191
11192 /**
11193  * gtk_tree_view_remove_column:
11194  * @tree_view: A #GtkTreeView.
11195  * @column: The #GtkTreeViewColumn to remove.
11196  *
11197  * Removes @column from @tree_view.
11198  *
11199  * Return value: The number of columns in @tree_view after removing.
11200  **/
11201 gint
11202 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11203                              GtkTreeViewColumn *column)
11204 {
11205   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11206   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11207   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11208
11209   if (tree_view->priv->focus_column == column)
11210     tree_view->priv->focus_column = NULL;
11211
11212   if (tree_view->priv->edited_column == column)
11213     {
11214       gtk_tree_view_stop_editing (tree_view, TRUE);
11215
11216       /* no need to, but just to be sure ... */
11217       tree_view->priv->edited_column = NULL;
11218     }
11219
11220   if (tree_view->priv->expander_column == column)
11221     tree_view->priv->expander_column = NULL;
11222
11223   g_signal_handlers_disconnect_by_func (column,
11224                                         G_CALLBACK (column_sizing_notify),
11225                                         tree_view);
11226
11227   _gtk_tree_view_column_unset_tree_view (column);
11228
11229   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11230   tree_view->priv->n_columns--;
11231
11232   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11233     {
11234       GList *list;
11235
11236       _gtk_tree_view_column_unrealize_button (column);
11237       for (list = tree_view->priv->columns; list; list = list->next)
11238         {
11239           GtkTreeViewColumn *tmp_column;
11240
11241           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11242           if (tmp_column->visible)
11243             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11244         }
11245
11246       if (tree_view->priv->n_columns == 0 &&
11247           gtk_tree_view_get_headers_visible (tree_view))
11248         gdk_window_hide (tree_view->priv->header_window);
11249
11250       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11251     }
11252
11253   g_object_unref (column);
11254   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11255
11256   return tree_view->priv->n_columns;
11257 }
11258
11259 /**
11260  * gtk_tree_view_insert_column:
11261  * @tree_view: A #GtkTreeView.
11262  * @column: The #GtkTreeViewColumn to be inserted.
11263  * @position: The position to insert @column in.
11264  *
11265  * This inserts the @column into the @tree_view at @position.  If @position is
11266  * -1, then the column is inserted at the end. If @tree_view has
11267  * "fixed_height" mode enabled, then @column must have its "sizing" property
11268  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11269  *
11270  * Return value: The number of columns in @tree_view after insertion.
11271  **/
11272 gint
11273 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11274                              GtkTreeViewColumn *column,
11275                              gint               position)
11276 {
11277   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11278   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11279   g_return_val_if_fail (column->tree_view == NULL, -1);
11280
11281   if (tree_view->priv->fixed_height_mode)
11282     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11283                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11284
11285   g_object_ref_sink (column);
11286
11287   if (tree_view->priv->n_columns == 0 &&
11288       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11289       gtk_tree_view_get_headers_visible (tree_view))
11290     {
11291       gdk_window_show (tree_view->priv->header_window);
11292     }
11293
11294   g_signal_connect (column, "notify::sizing",
11295                     G_CALLBACK (column_sizing_notify), tree_view);
11296
11297   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11298                                             column, position);
11299   tree_view->priv->n_columns++;
11300
11301   _gtk_tree_view_column_set_tree_view (column, tree_view);
11302
11303   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11304     {
11305       GList *list;
11306
11307       _gtk_tree_view_column_realize_button (column);
11308
11309       for (list = tree_view->priv->columns; list; list = list->next)
11310         {
11311           column = GTK_TREE_VIEW_COLUMN (list->data);
11312           if (column->visible)
11313             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11314         }
11315       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11316     }
11317
11318   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11319
11320   return tree_view->priv->n_columns;
11321 }
11322
11323 /**
11324  * gtk_tree_view_insert_column_with_attributes:
11325  * @tree_view: A #GtkTreeView
11326  * @position: The position to insert the new column in.
11327  * @title: The title to set the header to.
11328  * @cell: The #GtkCellRenderer.
11329  * @Varargs: A %NULL-terminated list of attributes.
11330  *
11331  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11332  * @position.  If @position is -1, then the newly created column is inserted at
11333  * the end.  The column is initialized with the attributes given. If @tree_view
11334  * has "fixed_height" mode enabled, then the new column will have its sizing
11335  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11336  *
11337  * Return value: The number of columns in @tree_view after insertion.
11338  **/
11339 gint
11340 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11341                                              gint             position,
11342                                              const gchar     *title,
11343                                              GtkCellRenderer *cell,
11344                                              ...)
11345 {
11346   GtkTreeViewColumn *column;
11347   gchar *attribute;
11348   va_list args;
11349   gint column_id;
11350
11351   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11352
11353   column = gtk_tree_view_column_new ();
11354   if (tree_view->priv->fixed_height_mode)
11355     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11356
11357   gtk_tree_view_column_set_title (column, title);
11358   gtk_tree_view_column_pack_start (column, cell, TRUE);
11359
11360   va_start (args, cell);
11361
11362   attribute = va_arg (args, gchar *);
11363
11364   while (attribute != NULL)
11365     {
11366       column_id = va_arg (args, gint);
11367       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11368       attribute = va_arg (args, gchar *);
11369     }
11370
11371   va_end (args);
11372
11373   gtk_tree_view_insert_column (tree_view, column, position);
11374
11375   return tree_view->priv->n_columns;
11376 }
11377
11378 /**
11379  * gtk_tree_view_insert_column_with_data_func:
11380  * @tree_view: a #GtkTreeView
11381  * @position: Position to insert, -1 for append
11382  * @title: column title
11383  * @cell: cell renderer for column
11384  * @func: function to set attributes of cell renderer
11385  * @data: data for @func
11386  * @dnotify: destroy notifier for @data
11387  *
11388  * Convenience function that inserts a new column into the #GtkTreeView
11389  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11390  * attributes (normally using data from the model). See also
11391  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11392  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11393  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11394  *
11395  * Return value: number of columns in the tree view post-insert
11396  **/
11397 gint
11398 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11399                                              gint                       position,
11400                                              const gchar               *title,
11401                                              GtkCellRenderer           *cell,
11402                                              GtkTreeCellDataFunc        func,
11403                                              gpointer                   data,
11404                                              GDestroyNotify             dnotify)
11405 {
11406   GtkTreeViewColumn *column;
11407
11408   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11409
11410   column = gtk_tree_view_column_new ();
11411   if (tree_view->priv->fixed_height_mode)
11412     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11413
11414   gtk_tree_view_column_set_title (column, title);
11415   gtk_tree_view_column_pack_start (column, cell, TRUE);
11416   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11417
11418   gtk_tree_view_insert_column (tree_view, column, position);
11419
11420   return tree_view->priv->n_columns;
11421 }
11422
11423 /**
11424  * gtk_tree_view_get_column:
11425  * @tree_view: A #GtkTreeView.
11426  * @n: The position of the column, counting from 0.
11427  *
11428  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11429  *
11430  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11431  * range of columns.
11432  **/
11433 GtkTreeViewColumn *
11434 gtk_tree_view_get_column (GtkTreeView *tree_view,
11435                           gint         n)
11436 {
11437   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11438
11439   if (n < 0 || n >= tree_view->priv->n_columns)
11440     return NULL;
11441
11442   if (tree_view->priv->columns == NULL)
11443     return NULL;
11444
11445   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11446 }
11447
11448 /**
11449  * gtk_tree_view_get_columns:
11450  * @tree_view: A #GtkTreeView
11451  *
11452  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11453  * The returned list must be freed with g_list_free ().
11454  *
11455  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11456  **/
11457 GList *
11458 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11459 {
11460   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11461
11462   return g_list_copy (tree_view->priv->columns);
11463 }
11464
11465 /**
11466  * gtk_tree_view_move_column_after:
11467  * @tree_view: A #GtkTreeView
11468  * @column: The #GtkTreeViewColumn to be moved.
11469  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11470  *
11471  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11472  * @column is placed in the first position.
11473  **/
11474 void
11475 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11476                                  GtkTreeViewColumn *column,
11477                                  GtkTreeViewColumn *base_column)
11478 {
11479   GList *column_list_el, *base_el = NULL;
11480
11481   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11482
11483   column_list_el = g_list_find (tree_view->priv->columns, column);
11484   g_return_if_fail (column_list_el != NULL);
11485
11486   if (base_column)
11487     {
11488       base_el = g_list_find (tree_view->priv->columns, base_column);
11489       g_return_if_fail (base_el != NULL);
11490     }
11491
11492   if (column_list_el->prev == base_el)
11493     return;
11494
11495   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11496   if (base_el == NULL)
11497     {
11498       column_list_el->prev = NULL;
11499       column_list_el->next = tree_view->priv->columns;
11500       if (column_list_el->next)
11501         column_list_el->next->prev = column_list_el;
11502       tree_view->priv->columns = column_list_el;
11503     }
11504   else
11505     {
11506       column_list_el->prev = base_el;
11507       column_list_el->next = base_el->next;
11508       if (column_list_el->next)
11509         column_list_el->next->prev = column_list_el;
11510       base_el->next = column_list_el;
11511     }
11512
11513   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11514     {
11515       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11516       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11517     }
11518
11519   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11520 }
11521
11522 /**
11523  * gtk_tree_view_set_expander_column:
11524  * @tree_view: A #GtkTreeView
11525  * @column: %NULL, or the column to draw the expander arrow at.
11526  *
11527  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11528  * If @column is %NULL, then the expander arrow is always at the first 
11529  * visible column.
11530  *
11531  * If you do not want expander arrow to appear in your tree, set the 
11532  * expander column to a hidden column.
11533  **/
11534 void
11535 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11536                                    GtkTreeViewColumn *column)
11537 {
11538   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11539   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11540
11541   if (tree_view->priv->expander_column != column)
11542     {
11543       GList *list;
11544
11545       if (column)
11546         {
11547           /* Confirm that column is in tree_view */
11548           for (list = tree_view->priv->columns; list; list = list->next)
11549             if (list->data == column)
11550               break;
11551           g_return_if_fail (list != NULL);
11552         }
11553
11554       tree_view->priv->expander_column = column;
11555       g_object_notify (G_OBJECT (tree_view), "expander-column");
11556     }
11557 }
11558
11559 /**
11560  * gtk_tree_view_get_expander_column:
11561  * @tree_view: A #GtkTreeView
11562  *
11563  * Returns the column that is the current expander column.  This
11564  * column has the expander arrow drawn next to it.
11565  *
11566  * Return value: The expander column.
11567  **/
11568 GtkTreeViewColumn *
11569 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11570 {
11571   GList *list;
11572
11573   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11574
11575   for (list = tree_view->priv->columns; list; list = list->next)
11576     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11577       return (GtkTreeViewColumn *) list->data;
11578   return NULL;
11579 }
11580
11581
11582 /**
11583  * gtk_tree_view_set_column_drag_function:
11584  * @tree_view: A #GtkTreeView.
11585  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
11586  * @user_data: (allow-none): User data to be passed to @func, or %NULL
11587  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
11588  *
11589  * Sets a user function for determining where a column may be dropped when
11590  * dragged.  This function is called on every column pair in turn at the
11591  * beginning of a column drag to determine where a drop can take place.  The
11592  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11593  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11594  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11595  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11596  * @tree_view reverts to the default behavior of allowing all columns to be
11597  * dropped everywhere.
11598  **/
11599 void
11600 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11601                                         GtkTreeViewColumnDropFunc  func,
11602                                         gpointer                   user_data,
11603                                         GDestroyNotify             destroy)
11604 {
11605   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11606
11607   if (tree_view->priv->column_drop_func_data_destroy)
11608     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11609
11610   tree_view->priv->column_drop_func = func;
11611   tree_view->priv->column_drop_func_data = user_data;
11612   tree_view->priv->column_drop_func_data_destroy = destroy;
11613 }
11614
11615 /**
11616  * gtk_tree_view_scroll_to_point:
11617  * @tree_view: a #GtkTreeView
11618  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11619  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11620  *
11621  * Scrolls the tree view such that the top-left corner of the visible
11622  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11623  * in tree coordinates.  The @tree_view must be realized before
11624  * this function is called.  If it isn't, you probably want to be
11625  * using gtk_tree_view_scroll_to_cell().
11626  *
11627  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11628  **/
11629 void
11630 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11631                                gint         tree_x,
11632                                gint         tree_y)
11633 {
11634   GtkAdjustment *hadj;
11635   GtkAdjustment *vadj;
11636
11637   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11638   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
11639
11640   hadj = tree_view->priv->hadjustment;
11641   vadj = tree_view->priv->vadjustment;
11642
11643   if (tree_x != -1)
11644     gtk_adjustment_set_value (hadj, tree_x);
11645   if (tree_y != -1)
11646     gtk_adjustment_set_value (vadj, tree_y);
11647 }
11648
11649 /**
11650  * gtk_tree_view_scroll_to_cell:
11651  * @tree_view: A #GtkTreeView.
11652  * @path: (allow-none): The path of the row to move to, or %NULL.
11653  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11654  * @use_align: whether to use alignment arguments, or %FALSE.
11655  * @row_align: The vertical alignment of the row specified by @path.
11656  * @col_align: The horizontal alignment of the column specified by @column.
11657  *
11658  * Moves the alignments of @tree_view to the position specified by @column and
11659  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11660  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11661  * or @path need to be non-%NULL.  @row_align determines where the row is
11662  * placed, and @col_align determines where @column is placed.  Both are expected
11663  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11664  * right/bottom alignment, 0.5 means center.
11665  *
11666  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11667  * tree does the minimum amount of work to scroll the cell onto the screen.
11668  * This means that the cell will be scrolled to the edge closest to its current
11669  * position.  If the cell is currently visible on the screen, nothing is done.
11670  *
11671  * This function only works if the model is set, and @path is a valid row on the
11672  * model.  If the model changes before the @tree_view is realized, the centered
11673  * path will be modified to reflect this change.
11674  **/
11675 void
11676 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11677                               GtkTreePath       *path,
11678                               GtkTreeViewColumn *column,
11679                               gboolean           use_align,
11680                               gfloat             row_align,
11681                               gfloat             col_align)
11682 {
11683   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11684   g_return_if_fail (tree_view->priv->model != NULL);
11685   g_return_if_fail (tree_view->priv->tree != NULL);
11686   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11687   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11688   g_return_if_fail (path != NULL || column != NULL);
11689
11690 #if 0
11691   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11692            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11693 #endif
11694   row_align = CLAMP (row_align, 0.0, 1.0);
11695   col_align = CLAMP (col_align, 0.0, 1.0);
11696
11697
11698   /* Note: Despite the benefits that come from having one code path for the
11699    * scrolling code, we short-circuit validate_visible_area's immplementation as
11700    * it is much slower than just going to the point.
11701    */
11702   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
11703       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
11704       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11705       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11706     {
11707       if (tree_view->priv->scroll_to_path)
11708         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11709
11710       tree_view->priv->scroll_to_path = NULL;
11711       tree_view->priv->scroll_to_column = NULL;
11712
11713       if (path)
11714         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11715       if (column)
11716         tree_view->priv->scroll_to_column = column;
11717       tree_view->priv->scroll_to_use_align = use_align;
11718       tree_view->priv->scroll_to_row_align = row_align;
11719       tree_view->priv->scroll_to_col_align = col_align;
11720
11721       install_presize_handler (tree_view);
11722     }
11723   else
11724     {
11725       GdkRectangle cell_rect;
11726       GdkRectangle vis_rect;
11727       gint dest_x, dest_y;
11728
11729       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11730       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11731
11732       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11733
11734       dest_x = vis_rect.x;
11735       dest_y = vis_rect.y;
11736
11737       if (column)
11738         {
11739           if (use_align)
11740             {
11741               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11742             }
11743           else
11744             {
11745               if (cell_rect.x < vis_rect.x)
11746                 dest_x = cell_rect.x;
11747               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11748                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11749             }
11750         }
11751
11752       if (path)
11753         {
11754           if (use_align)
11755             {
11756               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11757               dest_y = MAX (dest_y, 0);
11758             }
11759           else
11760             {
11761               if (cell_rect.y < vis_rect.y)
11762                 dest_y = cell_rect.y;
11763               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11764                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11765             }
11766         }
11767
11768       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11769     }
11770 }
11771
11772 /**
11773  * gtk_tree_view_row_activated:
11774  * @tree_view: A #GtkTreeView
11775  * @path: The #GtkTreePath to be activated.
11776  * @column: The #GtkTreeViewColumn to be activated.
11777  *
11778  * Activates the cell determined by @path and @column.
11779  **/
11780 void
11781 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11782                              GtkTreePath       *path,
11783                              GtkTreeViewColumn *column)
11784 {
11785   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11786
11787   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11788 }
11789
11790
11791 static void
11792 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11793                                           GtkRBNode *node,
11794                                           gpointer   data)
11795 {
11796   GtkTreeView *tree_view = data;
11797
11798   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11799       node->children)
11800     {
11801       GtkTreePath *path;
11802       GtkTreeIter iter;
11803
11804       path = _gtk_tree_view_find_path (tree_view, tree, node);
11805       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11806
11807       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11808
11809       gtk_tree_path_free (path);
11810     }
11811
11812   if (node->children)
11813     _gtk_rbtree_traverse (node->children,
11814                           node->children->root,
11815                           G_PRE_ORDER,
11816                           gtk_tree_view_expand_all_emission_helper,
11817                           tree_view);
11818 }
11819
11820 /**
11821  * gtk_tree_view_expand_all:
11822  * @tree_view: A #GtkTreeView.
11823  *
11824  * Recursively expands all nodes in the @tree_view.
11825  **/
11826 void
11827 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11828 {
11829   GtkTreePath *path;
11830   GtkRBTree *tree;
11831   GtkRBNode *node;
11832
11833   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11834
11835   if (tree_view->priv->tree == NULL)
11836     return;
11837
11838   path = gtk_tree_path_new_first ();
11839   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11840
11841   while (node)
11842     {
11843       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11844       node = _gtk_rbtree_next (tree, node);
11845       gtk_tree_path_next (path);
11846   }
11847
11848   gtk_tree_path_free (path);
11849 }
11850
11851 /* Timeout to animate the expander during expands and collapses */
11852 static gboolean
11853 expand_collapse_timeout (gpointer data)
11854 {
11855   return do_expand_collapse (data);
11856 }
11857
11858 static void
11859 add_expand_collapse_timeout (GtkTreeView *tree_view,
11860                              GtkRBTree   *tree,
11861                              GtkRBNode   *node,
11862                              gboolean     expand)
11863 {
11864   if (tree_view->priv->expand_collapse_timeout != 0)
11865     return;
11866
11867   tree_view->priv->expand_collapse_timeout =
11868       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11869   tree_view->priv->expanded_collapsed_tree = tree;
11870   tree_view->priv->expanded_collapsed_node = node;
11871
11872   if (expand)
11873     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11874   else
11875     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11876 }
11877
11878 static void
11879 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11880 {
11881   if (tree_view->priv->expand_collapse_timeout)
11882     {
11883       g_source_remove (tree_view->priv->expand_collapse_timeout);
11884       tree_view->priv->expand_collapse_timeout = 0;
11885     }
11886
11887   if (tree_view->priv->expanded_collapsed_node != NULL)
11888     {
11889       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11890       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11891
11892       tree_view->priv->expanded_collapsed_node = NULL;
11893     }
11894 }
11895
11896 static void
11897 cancel_arrow_animation (GtkTreeView *tree_view)
11898 {
11899   if (tree_view->priv->expand_collapse_timeout)
11900     {
11901       while (do_expand_collapse (tree_view));
11902
11903       remove_expand_collapse_timeout (tree_view);
11904     }
11905 }
11906
11907 static gboolean
11908 do_expand_collapse (GtkTreeView *tree_view)
11909 {
11910   GtkRBNode *node;
11911   GtkRBTree *tree;
11912   gboolean expanding;
11913   gboolean redraw;
11914
11915   redraw = FALSE;
11916   expanding = TRUE;
11917
11918   node = tree_view->priv->expanded_collapsed_node;
11919   tree = tree_view->priv->expanded_collapsed_tree;
11920
11921   if (node->children == NULL)
11922     expanding = FALSE;
11923
11924   if (expanding)
11925     {
11926       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11927         {
11928           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11929           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11930
11931           redraw = TRUE;
11932
11933         }
11934       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11935         {
11936           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11937
11938           redraw = TRUE;
11939         }
11940     }
11941   else
11942     {
11943       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11944         {
11945           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11946           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11947
11948           redraw = TRUE;
11949         }
11950       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11951         {
11952           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11953
11954           redraw = TRUE;
11955
11956         }
11957     }
11958
11959   if (redraw)
11960     {
11961       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
11962
11963       return TRUE;
11964     }
11965
11966   return FALSE;
11967 }
11968
11969 /**
11970  * gtk_tree_view_collapse_all:
11971  * @tree_view: A #GtkTreeView.
11972  *
11973  * Recursively collapses all visible, expanded nodes in @tree_view.
11974  **/
11975 void
11976 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11977 {
11978   GtkRBTree *tree;
11979   GtkRBNode *node;
11980   GtkTreePath *path;
11981   gint *indices;
11982
11983   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11984
11985   if (tree_view->priv->tree == NULL)
11986     return;
11987
11988   path = gtk_tree_path_new ();
11989   gtk_tree_path_down (path);
11990   indices = gtk_tree_path_get_indices (path);
11991
11992   tree = tree_view->priv->tree;
11993   node = tree->root;
11994   while (node && node->left != tree->nil)
11995     node = node->left;
11996
11997   while (node)
11998     {
11999       if (node->children)
12000         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12001       indices[0]++;
12002       node = _gtk_rbtree_next (tree, node);
12003     }
12004
12005   gtk_tree_path_free (path);
12006 }
12007
12008 /**
12009  * gtk_tree_view_expand_to_path:
12010  * @tree_view: A #GtkTreeView.
12011  * @path: path to a row.
12012  *
12013  * Expands the row at @path. This will also expand all parent rows of
12014  * @path as necessary.
12015  *
12016  * Since: 2.2
12017  **/
12018 void
12019 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12020                               GtkTreePath *path)
12021 {
12022   gint i, depth;
12023   gint *indices;
12024   GtkTreePath *tmp;
12025
12026   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12027   g_return_if_fail (path != NULL);
12028
12029   depth = gtk_tree_path_get_depth (path);
12030   indices = gtk_tree_path_get_indices (path);
12031
12032   tmp = gtk_tree_path_new ();
12033   g_return_if_fail (tmp != NULL);
12034
12035   for (i = 0; i < depth; i++)
12036     {
12037       gtk_tree_path_append_index (tmp, indices[i]);
12038       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12039     }
12040
12041   gtk_tree_path_free (tmp);
12042 }
12043
12044 /* FIXME the bool return values for expand_row and collapse_row are
12045  * not analagous; they should be TRUE if the row had children and
12046  * was not already in the requested state.
12047  */
12048
12049
12050 static gboolean
12051 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12052                                GtkTreePath *path,
12053                                GtkRBTree   *tree,
12054                                GtkRBNode   *node,
12055                                gboolean     open_all,
12056                                gboolean     animate)
12057 {
12058   GtkTreeIter iter;
12059   GtkTreeIter temp;
12060   gboolean expand;
12061
12062   if (animate)
12063     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12064                   "gtk-enable-animations", &animate,
12065                   NULL);
12066
12067   remove_auto_expand_timeout (tree_view);
12068
12069   if (node->children && !open_all)
12070     return FALSE;
12071
12072   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12073     return FALSE;
12074
12075   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12076   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12077     return FALSE;
12078
12079
12080    if (node->children && open_all)
12081     {
12082       gboolean retval = FALSE;
12083       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12084
12085       gtk_tree_path_append_index (tmp_path, 0);
12086       tree = node->children;
12087       node = tree->root;
12088       while (node->left != tree->nil)
12089         node = node->left;
12090       /* try to expand the children */
12091       do
12092         {
12093          gboolean t;
12094          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12095                                             TRUE, animate);
12096          if (t)
12097            retval = TRUE;
12098
12099          gtk_tree_path_next (tmp_path);
12100          node = _gtk_rbtree_next (tree, node);
12101        }
12102       while (node != NULL);
12103
12104       gtk_tree_path_free (tmp_path);
12105
12106       return retval;
12107     }
12108
12109   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12110
12111   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12112     return FALSE;
12113
12114   if (expand)
12115     return FALSE;
12116
12117   node->children = _gtk_rbtree_new ();
12118   node->children->parent_tree = tree;
12119   node->children->parent_node = node;
12120
12121   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12122
12123   gtk_tree_view_build_tree (tree_view,
12124                             node->children,
12125                             &temp,
12126                             gtk_tree_path_get_depth (path) + 1,
12127                             open_all);
12128
12129   remove_expand_collapse_timeout (tree_view);
12130
12131   if (animate)
12132     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12133
12134   install_presize_handler (tree_view);
12135
12136   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12137   if (open_all && node->children)
12138     {
12139       _gtk_rbtree_traverse (node->children,
12140                             node->children->root,
12141                             G_PRE_ORDER,
12142                             gtk_tree_view_expand_all_emission_helper,
12143                             tree_view);
12144     }
12145   return TRUE;
12146 }
12147
12148
12149 /**
12150  * gtk_tree_view_expand_row:
12151  * @tree_view: a #GtkTreeView
12152  * @path: path to a row
12153  * @open_all: whether to recursively expand, or just expand immediate children
12154  *
12155  * Opens the row so its children are visible.
12156  *
12157  * Return value: %TRUE if the row existed and had children
12158  **/
12159 gboolean
12160 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12161                           GtkTreePath *path,
12162                           gboolean     open_all)
12163 {
12164   GtkRBTree *tree;
12165   GtkRBNode *node;
12166
12167   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12168   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12169   g_return_val_if_fail (path != NULL, FALSE);
12170
12171   if (_gtk_tree_view_find_node (tree_view,
12172                                 path,
12173                                 &tree,
12174                                 &node))
12175     return FALSE;
12176
12177   if (tree != NULL)
12178     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12179   else
12180     return FALSE;
12181 }
12182
12183 static gboolean
12184 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12185                                  GtkTreePath *path,
12186                                  GtkRBTree   *tree,
12187                                  GtkRBNode   *node,
12188                                  gboolean     animate)
12189 {
12190   GtkTreeIter iter;
12191   GtkTreeIter children;
12192   gboolean collapse;
12193   gint x, y;
12194   GList *list;
12195   GdkWindow *child, *parent;
12196
12197   if (animate)
12198     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12199                   "gtk-enable-animations", &animate,
12200                   NULL);
12201
12202   remove_auto_expand_timeout (tree_view);
12203
12204   if (node->children == NULL)
12205     return FALSE;
12206
12207   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12208
12209   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12210
12211   if (collapse)
12212     return FALSE;
12213
12214   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12215    * a chance to prelight the correct node below */
12216
12217   if (tree_view->priv->prelight_tree)
12218     {
12219       GtkRBTree *parent_tree;
12220       GtkRBNode *parent_node;
12221
12222       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12223       parent_node = tree_view->priv->prelight_tree->parent_node;
12224       while (parent_tree)
12225         {
12226           if (parent_tree == tree && parent_node == node)
12227             {
12228               ensure_unprelighted (tree_view);
12229               break;
12230             }
12231           parent_node = parent_tree->parent_node;
12232           parent_tree = parent_tree->parent_tree;
12233         }
12234     }
12235
12236   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12237
12238   for (list = tree_view->priv->columns; list; list = list->next)
12239     {
12240       GtkTreeViewColumn *column = list->data;
12241
12242       if (column->visible == FALSE)
12243         continue;
12244       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12245         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12246     }
12247
12248   if (tree_view->priv->destroy_count_func)
12249     {
12250       GtkTreePath *child_path;
12251       gint child_count = 0;
12252       child_path = gtk_tree_path_copy (path);
12253       gtk_tree_path_down (child_path);
12254       if (node->children)
12255         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12256       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12257       gtk_tree_path_free (child_path);
12258     }
12259
12260   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12261     {
12262       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12263
12264       if (gtk_tree_path_is_ancestor (path, cursor_path))
12265         {
12266           gtk_tree_row_reference_free (tree_view->priv->cursor);
12267           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12268                                                                       tree_view->priv->model,
12269                                                                       path);
12270         }
12271       gtk_tree_path_free (cursor_path);
12272     }
12273
12274   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12275     {
12276       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12277       if (gtk_tree_path_is_ancestor (path, anchor_path))
12278         {
12279           gtk_tree_row_reference_free (tree_view->priv->anchor);
12280           tree_view->priv->anchor = NULL;
12281         }
12282       gtk_tree_path_free (anchor_path);
12283     }
12284
12285   /* Stop a pending double click */
12286   tree_view->priv->last_button_x = -1;
12287   tree_view->priv->last_button_y = -1;
12288
12289   remove_expand_collapse_timeout (tree_view);
12290
12291   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12292     {
12293       _gtk_rbtree_remove (node->children);
12294       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12295     }
12296   else
12297     _gtk_rbtree_remove (node->children);
12298   
12299   if (animate)
12300     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12301   
12302   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12303     {
12304       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12305     }
12306
12307   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12308
12309   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12310     {
12311       /* now that we've collapsed all rows, we want to try to set the prelight
12312        * again. To do this, we fake a motion event and send it to ourselves. */
12313
12314       child = tree_view->priv->bin_window;
12315       parent = gdk_window_get_parent (child);
12316
12317       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12318         {
12319           GdkEventMotion event;
12320           gint child_x, child_y;
12321
12322           gdk_window_get_position (child, &child_x, &child_y);
12323
12324           event.window = tree_view->priv->bin_window;
12325           event.x = x - child_x;
12326           event.y = y - child_y;
12327
12328           /* despite the fact this isn't a real event, I'm almost positive it will
12329            * never trigger a drag event.  maybe_drag is the only function that uses
12330            * more than just event.x and event.y. */
12331           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12332         }
12333     }
12334
12335   return TRUE;
12336 }
12337
12338 /**
12339  * gtk_tree_view_collapse_row:
12340  * @tree_view: a #GtkTreeView
12341  * @path: path to a row in the @tree_view
12342  *
12343  * Collapses a row (hides its child rows, if they exist).
12344  *
12345  * Return value: %TRUE if the row was collapsed.
12346  **/
12347 gboolean
12348 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12349                             GtkTreePath *path)
12350 {
12351   GtkRBTree *tree;
12352   GtkRBNode *node;
12353
12354   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12355   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12356   g_return_val_if_fail (path != NULL, FALSE);
12357
12358   if (_gtk_tree_view_find_node (tree_view,
12359                                 path,
12360                                 &tree,
12361                                 &node))
12362     return FALSE;
12363
12364   if (tree == NULL || node->children == NULL)
12365     return FALSE;
12366
12367   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12368 }
12369
12370 static void
12371 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12372                                         GtkRBTree              *tree,
12373                                         GtkTreePath            *path,
12374                                         GtkTreeViewMappingFunc  func,
12375                                         gpointer                user_data)
12376 {
12377   GtkRBNode *node;
12378
12379   if (tree == NULL || tree->root == NULL)
12380     return;
12381
12382   node = tree->root;
12383
12384   while (node && node->left != tree->nil)
12385     node = node->left;
12386
12387   while (node)
12388     {
12389       if (node->children)
12390         {
12391           (* func) (tree_view, path, user_data);
12392           gtk_tree_path_down (path);
12393           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12394           gtk_tree_path_up (path);
12395         }
12396       gtk_tree_path_next (path);
12397       node = _gtk_rbtree_next (tree, node);
12398     }
12399 }
12400
12401 /**
12402  * gtk_tree_view_map_expanded_rows:
12403  * @tree_view: A #GtkTreeView
12404  * @func: A function to be called
12405  * @data: User data to be passed to the function.
12406  *
12407  * Calls @func on all expanded rows.
12408  **/
12409 void
12410 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12411                                  GtkTreeViewMappingFunc  func,
12412                                  gpointer                user_data)
12413 {
12414   GtkTreePath *path;
12415
12416   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12417   g_return_if_fail (func != NULL);
12418
12419   path = gtk_tree_path_new_first ();
12420
12421   gtk_tree_view_map_expanded_rows_helper (tree_view,
12422                                           tree_view->priv->tree,
12423                                           path, func, user_data);
12424
12425   gtk_tree_path_free (path);
12426 }
12427
12428 /**
12429  * gtk_tree_view_row_expanded:
12430  * @tree_view: A #GtkTreeView.
12431  * @path: A #GtkTreePath to test expansion state.
12432  *
12433  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12434  *
12435  * Return value: %TRUE if #path is expanded.
12436  **/
12437 gboolean
12438 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12439                             GtkTreePath *path)
12440 {
12441   GtkRBTree *tree;
12442   GtkRBNode *node;
12443
12444   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12445   g_return_val_if_fail (path != NULL, FALSE);
12446
12447   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12448
12449   if (node == NULL)
12450     return FALSE;
12451
12452   return (node->children != NULL);
12453 }
12454
12455 /**
12456  * gtk_tree_view_get_reorderable:
12457  * @tree_view: a #GtkTreeView
12458  *
12459  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12460  * gtk_tree_view_set_reorderable().
12461  *
12462  * Return value: %TRUE if the tree can be reordered.
12463  **/
12464 gboolean
12465 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12466 {
12467   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12468
12469   return tree_view->priv->reorderable;
12470 }
12471
12472 /**
12473  * gtk_tree_view_set_reorderable:
12474  * @tree_view: A #GtkTreeView.
12475  * @reorderable: %TRUE, if the tree can be reordered.
12476  *
12477  * This function is a convenience function to allow you to reorder
12478  * models that support the #GtkDragSourceIface and the
12479  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12480  * these.  If @reorderable is %TRUE, then the user can reorder the
12481  * model by dragging and dropping rows. The developer can listen to
12482  * these changes by connecting to the model's row_inserted and
12483  * row_deleted signals. The reordering is implemented by setting up
12484  * the tree view as a drag source and destination. Therefore, drag and
12485  * drop can not be used in a reorderable view for any other purpose.
12486  *
12487  * This function does not give you any degree of control over the order -- any
12488  * reordering is allowed.  If more control is needed, you should probably
12489  * handle drag and drop manually.
12490  **/
12491 void
12492 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12493                                gboolean     reorderable)
12494 {
12495   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12496
12497   reorderable = reorderable != FALSE;
12498
12499   if (tree_view->priv->reorderable == reorderable)
12500     return;
12501
12502   if (reorderable)
12503     {
12504       const GtkTargetEntry row_targets[] = {
12505         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12506       };
12507
12508       gtk_tree_view_enable_model_drag_source (tree_view,
12509                                               GDK_BUTTON1_MASK,
12510                                               row_targets,
12511                                               G_N_ELEMENTS (row_targets),
12512                                               GDK_ACTION_MOVE);
12513       gtk_tree_view_enable_model_drag_dest (tree_view,
12514                                             row_targets,
12515                                             G_N_ELEMENTS (row_targets),
12516                                             GDK_ACTION_MOVE);
12517     }
12518   else
12519     {
12520       gtk_tree_view_unset_rows_drag_source (tree_view);
12521       gtk_tree_view_unset_rows_drag_dest (tree_view);
12522     }
12523
12524   tree_view->priv->reorderable = reorderable;
12525
12526   g_object_notify (G_OBJECT (tree_view), "reorderable");
12527 }
12528
12529 static void
12530 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12531                                GtkTreePath     *path,
12532                                gboolean         clear_and_select,
12533                                gboolean         clamp_node)
12534 {
12535   GtkRBTree *tree = NULL;
12536   GtkRBNode *node = NULL;
12537
12538   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12539     {
12540       GtkTreePath *cursor_path;
12541       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12542       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12543       gtk_tree_path_free (cursor_path);
12544     }
12545
12546   gtk_tree_row_reference_free (tree_view->priv->cursor);
12547   tree_view->priv->cursor = NULL;
12548
12549   /* One cannot set the cursor on a separator.   Also, if
12550    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12551    * before finding the tree and node belonging to path.  The
12552    * path maps to a non-existing path and we will silently bail out.
12553    * We unset tree and node to avoid further processing.
12554    */
12555   if (!row_is_separator (tree_view, NULL, path)
12556       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12557     {
12558       tree_view->priv->cursor =
12559           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12560                                             tree_view->priv->model,
12561                                             path);
12562     }
12563   else
12564     {
12565       tree = NULL;
12566       node = NULL;
12567     }
12568
12569   if (tree != NULL)
12570     {
12571       GtkRBTree *new_tree = NULL;
12572       GtkRBNode *new_node = NULL;
12573
12574       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12575         {
12576           GtkTreeSelectMode mode = 0;
12577
12578           if (tree_view->priv->ctrl_pressed)
12579             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12580           if (tree_view->priv->shift_pressed)
12581             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12582
12583           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12584                                                     node, tree, path, mode,
12585                                                     FALSE);
12586         }
12587
12588       /* We have to re-find tree and node here again, somebody might have
12589        * cleared the node or the whole tree in the GtkTreeSelection::changed
12590        * callback. If the nodes differ we bail out here.
12591        */
12592       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12593
12594       if (tree != new_tree || node != new_node)
12595         return;
12596
12597       if (clamp_node)
12598         {
12599           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12600           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12601         }
12602     }
12603
12604   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12605 }
12606
12607 /**
12608  * gtk_tree_view_get_cursor:
12609  * @tree_view: A #GtkTreeView
12610  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
12611  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
12612  *
12613  * Fills in @path and @focus_column with the current path and focus column.  If
12614  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12615  * currently has focus, then *@focus_column will be %NULL.
12616  *
12617  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12618  * you are done with it.
12619  **/
12620 void
12621 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12622                           GtkTreePath       **path,
12623                           GtkTreeViewColumn **focus_column)
12624 {
12625   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12626
12627   if (path)
12628     {
12629       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12630         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12631       else
12632         *path = NULL;
12633     }
12634
12635   if (focus_column)
12636     {
12637       *focus_column = tree_view->priv->focus_column;
12638     }
12639 }
12640
12641 /**
12642  * gtk_tree_view_set_cursor:
12643  * @tree_view: A #GtkTreeView
12644  * @path: A #GtkTreePath
12645  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12646  * @start_editing: %TRUE if the specified cell should start being edited.
12647  *
12648  * Sets the current keyboard focus to be at @path, and selects it.  This is
12649  * useful when you want to focus the user's attention on a particular row.  If
12650  * @focus_column is not %NULL, then focus is given to the column specified by 
12651  * it. Additionally, if @focus_column is specified, and @start_editing is 
12652  * %TRUE, then editing should be started in the specified cell.  
12653  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12654  * in order to give keyboard focus to the widget.  Please note that editing 
12655  * can only happen when the widget is realized.
12656  *
12657  * If @path is invalid for @model, the current cursor (if any) will be unset
12658  * and the function will return without failing.
12659  **/
12660 void
12661 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12662                           GtkTreePath       *path,
12663                           GtkTreeViewColumn *focus_column,
12664                           gboolean           start_editing)
12665 {
12666   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12667                                     NULL, start_editing);
12668 }
12669
12670 /**
12671  * gtk_tree_view_set_cursor_on_cell:
12672  * @tree_view: A #GtkTreeView
12673  * @path: A #GtkTreePath
12674  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12675  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12676  * @start_editing: %TRUE if the specified cell should start being edited.
12677  *
12678  * Sets the current keyboard focus to be at @path, and selects it.  This is
12679  * useful when you want to focus the user's attention on a particular row.  If
12680  * @focus_column is not %NULL, then focus is given to the column specified by
12681  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12682  * contains 2 or more editable or activatable cells, then focus is given to
12683  * the cell specified by @focus_cell. Additionally, if @focus_column is
12684  * specified, and @start_editing is %TRUE, then editing should be started in
12685  * the specified cell.  This function is often followed by
12686  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12687  * widget.  Please note that editing can only happen when the widget is
12688  * realized.
12689  *
12690  * If @path is invalid for @model, the current cursor (if any) will be unset
12691  * and the function will return without failing.
12692  *
12693  * Since: 2.2
12694  **/
12695 void
12696 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12697                                   GtkTreePath       *path,
12698                                   GtkTreeViewColumn *focus_column,
12699                                   GtkCellRenderer   *focus_cell,
12700                                   gboolean           start_editing)
12701 {
12702   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12703   g_return_if_fail (path != NULL);
12704   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12705
12706   if (!tree_view->priv->model)
12707     return;
12708
12709   if (focus_cell)
12710     {
12711       g_return_if_fail (focus_column);
12712       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12713     }
12714
12715   /* cancel the current editing, if it exists */
12716   if (tree_view->priv->edited_column &&
12717       tree_view->priv->edited_column->editable_widget)
12718     gtk_tree_view_stop_editing (tree_view, TRUE);
12719
12720   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12721
12722   if (focus_column && focus_column->visible)
12723     {
12724       GList *list;
12725       gboolean column_in_tree = FALSE;
12726
12727       for (list = tree_view->priv->columns; list; list = list->next)
12728         if (list->data == focus_column)
12729           {
12730             column_in_tree = TRUE;
12731             break;
12732           }
12733       g_return_if_fail (column_in_tree);
12734       tree_view->priv->focus_column = focus_column;
12735       if (focus_cell)
12736         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12737       if (start_editing)
12738         gtk_tree_view_start_editing (tree_view, path);
12739     }
12740 }
12741
12742 /**
12743  * gtk_tree_view_get_bin_window:
12744  * @tree_view: A #GtkTreeView
12745  * 
12746  * Returns the window that @tree_view renders to.  This is used primarily to
12747  * compare to <literal>event->window</literal> to confirm that the event on
12748  * @tree_view is on the right window.
12749  * 
12750  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12751  **/
12752 GdkWindow *
12753 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12754 {
12755   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12756
12757   return tree_view->priv->bin_window;
12758 }
12759
12760 /**
12761  * gtk_tree_view_get_path_at_pos:
12762  * @tree_view: A #GtkTreeView.
12763  * @x: The x position to be identified (relative to bin_window).
12764  * @y: The y position to be identified (relative to bin_window).
12765  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12766  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12767  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
12768  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12769  *
12770  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12771  * (please see gtk_tree_view_get_bin_window()).
12772  * That is, @x and @y are relative to an events coordinates. @x and @y must
12773  * come from an event on the @tree_view only where <literal>event->window ==
12774  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12775  * things like popup menus. If @path is non-%NULL, then it will be filled
12776  * with the #GtkTreePath at that point.  This path should be freed with
12777  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12778  * with the column at that point.  @cell_x and @cell_y return the coordinates
12779  * relative to the cell background (i.e. the @background_area passed to
12780  * gtk_cell_renderer_render()).  This function is only meaningful if
12781  * @tree_view is realized.  Therefore this function will always return %FALSE
12782  * if @tree_view is not realized or does not have a model.
12783  *
12784  * For converting widget coordinates (eg. the ones you get from
12785  * GtkWidget::query-tooltip), please see
12786  * gtk_tree_view_convert_widget_to_bin_window_coords().
12787  *
12788  * Return value: %TRUE if a row exists at that coordinate.
12789  **/
12790 gboolean
12791 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12792                                gint                x,
12793                                gint                y,
12794                                GtkTreePath       **path,
12795                                GtkTreeViewColumn **column,
12796                                gint               *cell_x,
12797                                gint               *cell_y)
12798 {
12799   GtkRBTree *tree;
12800   GtkRBNode *node;
12801   gint y_offset;
12802
12803   g_return_val_if_fail (tree_view != NULL, FALSE);
12804
12805   if (path)
12806     *path = NULL;
12807   if (column)
12808     *column = NULL;
12809
12810   if (tree_view->priv->bin_window == NULL)
12811     return FALSE;
12812
12813   if (tree_view->priv->tree == NULL)
12814     return FALSE;
12815
12816   if (x > tree_view->priv->hadjustment->upper)
12817     return FALSE;
12818
12819   if (x < 0 || y < 0)
12820     return FALSE;
12821
12822   if (column || cell_x)
12823     {
12824       GtkTreeViewColumn *tmp_column;
12825       GtkTreeViewColumn *last_column = NULL;
12826       GList *list;
12827       gint remaining_x = x;
12828       gboolean found = FALSE;
12829       gboolean rtl;
12830
12831       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12832       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12833            list;
12834            list = (rtl ? list->prev : list->next))
12835         {
12836           tmp_column = list->data;
12837
12838           if (tmp_column->visible == FALSE)
12839             continue;
12840
12841           last_column = tmp_column;
12842           if (remaining_x <= tmp_column->width)
12843             {
12844               found = TRUE;
12845
12846               if (column)
12847                 *column = tmp_column;
12848
12849               if (cell_x)
12850                 *cell_x = remaining_x;
12851
12852               break;
12853             }
12854           remaining_x -= tmp_column->width;
12855         }
12856
12857       /* If found is FALSE and there is a last_column, then it the remainder
12858        * space is in that area
12859        */
12860       if (!found)
12861         {
12862           if (last_column)
12863             {
12864               if (column)
12865                 *column = last_column;
12866               
12867               if (cell_x)
12868                 *cell_x = last_column->width + remaining_x;
12869             }
12870           else
12871             {
12872               return FALSE;
12873             }
12874         }
12875     }
12876
12877   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12878                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12879                                       &tree, &node);
12880
12881   if (tree == NULL)
12882     return FALSE;
12883
12884   if (cell_y)
12885     *cell_y = y_offset;
12886
12887   if (path)
12888     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12889
12890   return TRUE;
12891 }
12892
12893
12894 /**
12895  * gtk_tree_view_get_cell_area:
12896  * @tree_view: a #GtkTreeView
12897  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12898  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12899  * @rect: rectangle to fill with cell rect
12900  *
12901  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12902  * row specified by @path and the column specified by @column.  If @path is
12903  * %NULL, or points to a path not currently displayed, the @y and @height fields
12904  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12905  * fields will be filled with 0.  The sum of all cell rects does not cover the
12906  * entire tree; there are extra pixels in between rows, for example. The
12907  * returned rectangle is equivalent to the @cell_area passed to
12908  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12909  * realized.
12910  **/
12911 void
12912 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12913                              GtkTreePath        *path,
12914                              GtkTreeViewColumn  *column,
12915                              GdkRectangle       *rect)
12916 {
12917   GtkRBTree *tree = NULL;
12918   GtkRBNode *node = NULL;
12919   gint vertical_separator;
12920   gint horizontal_separator;
12921
12922   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12923   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12924   g_return_if_fail (rect != NULL);
12925   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12926   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12927
12928   gtk_widget_style_get (GTK_WIDGET (tree_view),
12929                         "vertical-separator", &vertical_separator,
12930                         "horizontal-separator", &horizontal_separator,
12931                         NULL);
12932
12933   rect->x = 0;
12934   rect->y = 0;
12935   rect->width = 0;
12936   rect->height = 0;
12937
12938   if (column)
12939     {
12940       rect->x = column->button->allocation.x + horizontal_separator/2;
12941       rect->width = column->button->allocation.width - horizontal_separator;
12942     }
12943
12944   if (path)
12945     {
12946       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12947
12948       /* Get vertical coords */
12949       if ((!ret && tree == NULL) || ret)
12950         return;
12951
12952       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12953       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12954
12955       if (column &&
12956           gtk_tree_view_is_expander_column (tree_view, column))
12957         {
12958           gint depth = gtk_tree_path_get_depth (path);
12959           gboolean rtl;
12960
12961           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12962
12963           if (!rtl)
12964             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12965           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12966
12967           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12968             {
12969               if (!rtl)
12970                 rect->x += depth * tree_view->priv->expander_size;
12971               rect->width -= depth * tree_view->priv->expander_size;
12972             }
12973
12974           rect->width = MAX (rect->width, 0);
12975         }
12976     }
12977 }
12978
12979 /**
12980  * gtk_tree_view_get_background_area:
12981  * @tree_view: a #GtkTreeView
12982  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12983  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
12984  * @rect: rectangle to fill with cell background rect
12985  *
12986  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12987  * row specified by @path and the column specified by @column.  If @path is
12988  * %NULL, or points to a node not found in the tree, the @y and @height fields of
12989  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12990  * fields will be filled with 0.  The returned rectangle is equivalent to the
12991  * @background_area passed to gtk_cell_renderer_render().  These background
12992  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
12993  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
12994  * itself, excluding surrounding borders and the tree expander area.
12995  *
12996  **/
12997 void
12998 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
12999                                    GtkTreePath        *path,
13000                                    GtkTreeViewColumn  *column,
13001                                    GdkRectangle       *rect)
13002 {
13003   GtkRBTree *tree = NULL;
13004   GtkRBNode *node = NULL;
13005
13006   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13007   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13008   g_return_if_fail (rect != NULL);
13009
13010   rect->x = 0;
13011   rect->y = 0;
13012   rect->width = 0;
13013   rect->height = 0;
13014
13015   if (path)
13016     {
13017       /* Get vertical coords */
13018
13019       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13020           tree == NULL)
13021         return;
13022
13023       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13024
13025       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13026     }
13027
13028   if (column)
13029     {
13030       gint x2 = 0;
13031
13032       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13033       rect->width = x2 - rect->x;
13034     }
13035 }
13036
13037 /**
13038  * gtk_tree_view_get_visible_rect:
13039  * @tree_view: a #GtkTreeView
13040  * @visible_rect: rectangle to fill
13041  *
13042  * Fills @visible_rect with the currently-visible region of the
13043  * buffer, in tree coordinates. Convert to bin_window coordinates with
13044  * gtk_tree_view_convert_tree_to_bin_window_coords().
13045  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13046  * scrollable area of the tree.
13047  **/
13048 void
13049 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13050                                 GdkRectangle *visible_rect)
13051 {
13052   GtkWidget *widget;
13053
13054   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13055
13056   widget = GTK_WIDGET (tree_view);
13057
13058   if (visible_rect)
13059     {
13060       visible_rect->x = tree_view->priv->hadjustment->value;
13061       visible_rect->y = tree_view->priv->vadjustment->value;
13062       visible_rect->width = widget->allocation.width;
13063       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13064     }
13065 }
13066
13067 /**
13068  * gtk_tree_view_convert_widget_to_tree_coords:
13069  * @tree_view: a #GtkTreeView
13070  * @wx: X coordinate relative to the widget
13071  * @wy: Y coordinate relative to the widget
13072  * @tx: return location for tree X coordinate
13073  * @ty: return location for tree Y coordinate
13074  *
13075  * Converts widget coordinates to coordinates for the
13076  * tree (the full scrollable area of the tree).
13077  *
13078  * Since: 2.12
13079  **/
13080 void
13081 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13082                                              gint         wx,
13083                                              gint         wy,
13084                                              gint        *tx,
13085                                              gint        *ty)
13086 {
13087   gint x, y;
13088
13089   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13090
13091   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13092                                                      wx, wy,
13093                                                      &x, &y);
13094   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13095                                                    x, y,
13096                                                    tx, ty);
13097 }
13098
13099 /**
13100  * gtk_tree_view_convert_tree_to_widget_coords:
13101  * @tree_view: a #GtkTreeView
13102  * @tx: X coordinate relative to the tree
13103  * @ty: Y coordinate relative to the tree
13104  * @wx: return location for widget X coordinate
13105  * @wy: return location for widget Y coordinate
13106  *
13107  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13108  * to widget coordinates.
13109  *
13110  * Since: 2.12
13111  **/
13112 void
13113 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13114                                              gint         tx,
13115                                              gint         ty,
13116                                              gint        *wx,
13117                                              gint        *wy)
13118 {
13119   gint x, y;
13120
13121   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13122
13123   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13124                                                    tx, ty,
13125                                                    &x, &y);
13126   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13127                                                      x, y,
13128                                                      wx, wy);
13129 }
13130
13131 /**
13132  * gtk_tree_view_convert_widget_to_bin_window_coords:
13133  * @tree_view: a #GtkTreeView
13134  * @wx: X coordinate relative to the widget
13135  * @wy: Y coordinate relative to the widget
13136  * @bx: return location for bin_window X coordinate
13137  * @by: return location for bin_window Y coordinate
13138  *
13139  * Converts widget coordinates to coordinates for the bin_window
13140  * (see gtk_tree_view_get_bin_window()).
13141  *
13142  * Since: 2.12
13143  **/
13144 void
13145 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13146                                                    gint         wx,
13147                                                    gint         wy,
13148                                                    gint        *bx,
13149                                                    gint        *by)
13150 {
13151   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13152
13153   if (bx)
13154     *bx = wx + tree_view->priv->hadjustment->value;
13155   if (by)
13156     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13157 }
13158
13159 /**
13160  * gtk_tree_view_convert_bin_window_to_widget_coords:
13161  * @tree_view: a #GtkTreeView
13162  * @bx: bin_window X coordinate
13163  * @by: bin_window Y coordinate
13164  * @wx: return location for widget X coordinate
13165  * @wy: return location for widget Y coordinate
13166  *
13167  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13168  * to widget relative coordinates.
13169  *
13170  * Since: 2.12
13171  **/
13172 void
13173 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13174                                                    gint         bx,
13175                                                    gint         by,
13176                                                    gint        *wx,
13177                                                    gint        *wy)
13178 {
13179   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13180
13181   if (wx)
13182     *wx = bx - tree_view->priv->hadjustment->value;
13183   if (wy)
13184     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13185 }
13186
13187 /**
13188  * gtk_tree_view_convert_tree_to_bin_window_coords:
13189  * @tree_view: a #GtkTreeView
13190  * @tx: tree X coordinate
13191  * @ty: tree Y coordinate
13192  * @bx: return location for X coordinate relative to bin_window
13193  * @by: return location for Y coordinate relative to bin_window
13194  *
13195  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13196  * to bin_window coordinates.
13197  *
13198  * Since: 2.12
13199  **/
13200 void
13201 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13202                                                  gint         tx,
13203                                                  gint         ty,
13204                                                  gint        *bx,
13205                                                  gint        *by)
13206 {
13207   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13208
13209   if (bx)
13210     *bx = tx;
13211   if (by)
13212     *by = ty - tree_view->priv->dy;
13213 }
13214
13215 /**
13216  * gtk_tree_view_convert_bin_window_to_tree_coords:
13217  * @tree_view: a #GtkTreeView
13218  * @bx: X coordinate relative to bin_window
13219  * @by: Y coordinate relative to bin_window
13220  * @tx: return location for tree X coordinate
13221  * @ty: return location for tree Y coordinate
13222  *
13223  * Converts bin_window coordinates to coordinates for the
13224  * tree (the full scrollable area of the tree).
13225  *
13226  * Since: 2.12
13227  **/
13228 void
13229 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13230                                                  gint         bx,
13231                                                  gint         by,
13232                                                  gint        *tx,
13233                                                  gint        *ty)
13234 {
13235   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13236
13237   if (tx)
13238     *tx = bx;
13239   if (ty)
13240     *ty = by + tree_view->priv->dy;
13241 }
13242
13243
13244
13245 /**
13246  * gtk_tree_view_get_visible_range:
13247  * @tree_view: A #GtkTreeView
13248  * @start_path: (allow-none): Return location for start of region, or %NULL.
13249  * @end_path: (allow-none): Return location for end of region, or %NULL.
13250  *
13251  * Sets @start_path and @end_path to be the first and last visible path.
13252  * Note that there may be invisible paths in between.
13253  *
13254  * The paths should be freed with gtk_tree_path_free() after use.
13255  *
13256  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13257  *
13258  * Since: 2.8
13259  **/
13260 gboolean
13261 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13262                                  GtkTreePath **start_path,
13263                                  GtkTreePath **end_path)
13264 {
13265   GtkRBTree *tree;
13266   GtkRBNode *node;
13267   gboolean retval;
13268   
13269   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13270
13271   if (!tree_view->priv->tree)
13272     return FALSE;
13273
13274   retval = TRUE;
13275
13276   if (start_path)
13277     {
13278       _gtk_rbtree_find_offset (tree_view->priv->tree,
13279                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13280                                &tree, &node);
13281       if (node)
13282         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13283       else
13284         retval = FALSE;
13285     }
13286
13287   if (end_path)
13288     {
13289       gint y;
13290
13291       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13292         y = tree_view->priv->height - 1;
13293       else
13294         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13295
13296       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13297       if (node)
13298         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13299       else
13300         retval = FALSE;
13301     }
13302
13303   return retval;
13304 }
13305
13306 static void
13307 unset_reorderable (GtkTreeView *tree_view)
13308 {
13309   if (tree_view->priv->reorderable)
13310     {
13311       tree_view->priv->reorderable = FALSE;
13312       g_object_notify (G_OBJECT (tree_view), "reorderable");
13313     }
13314 }
13315
13316 /**
13317  * gtk_tree_view_enable_model_drag_source:
13318  * @tree_view: a #GtkTreeView
13319  * @start_button_mask: Mask of allowed buttons to start drag
13320  * @targets: the table of targets that the drag will support
13321  * @n_targets: the number of items in @targets
13322  * @actions: the bitmask of possible actions for a drag from this
13323  *    widget
13324  *
13325  * Turns @tree_view into a drag source for automatic DND. Calling this
13326  * method sets #GtkTreeView:reorderable to %FALSE.
13327  **/
13328 void
13329 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13330                                         GdkModifierType           start_button_mask,
13331                                         const GtkTargetEntry     *targets,
13332                                         gint                      n_targets,
13333                                         GdkDragAction             actions)
13334 {
13335   TreeViewDragInfo *di;
13336
13337   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13338
13339   gtk_drag_source_set (GTK_WIDGET (tree_view),
13340                        0,
13341                        targets,
13342                        n_targets,
13343                        actions);
13344
13345   di = ensure_info (tree_view);
13346
13347   di->start_button_mask = start_button_mask;
13348   di->source_actions = actions;
13349   di->source_set = TRUE;
13350
13351   unset_reorderable (tree_view);
13352 }
13353
13354 /**
13355  * gtk_tree_view_enable_model_drag_dest:
13356  * @tree_view: a #GtkTreeView
13357  * @targets: the table of targets that the drag will support
13358  * @n_targets: the number of items in @targets
13359  * @actions: the bitmask of possible actions for a drag from this
13360  *    widget
13361  * 
13362  * Turns @tree_view into a drop destination for automatic DND. Calling
13363  * this method sets #GtkTreeView:reorderable to %FALSE.
13364  **/
13365 void
13366 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13367                                       const GtkTargetEntry     *targets,
13368                                       gint                      n_targets,
13369                                       GdkDragAction             actions)
13370 {
13371   TreeViewDragInfo *di;
13372
13373   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13374
13375   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13376                      0,
13377                      targets,
13378                      n_targets,
13379                      actions);
13380
13381   di = ensure_info (tree_view);
13382   di->dest_set = TRUE;
13383
13384   unset_reorderable (tree_view);
13385 }
13386
13387 /**
13388  * gtk_tree_view_unset_rows_drag_source:
13389  * @tree_view: a #GtkTreeView
13390  *
13391  * Undoes the effect of
13392  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13393  * #GtkTreeView:reorderable to %FALSE.
13394  **/
13395 void
13396 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13397 {
13398   TreeViewDragInfo *di;
13399
13400   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13401
13402   di = get_info (tree_view);
13403
13404   if (di)
13405     {
13406       if (di->source_set)
13407         {
13408           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13409           di->source_set = FALSE;
13410         }
13411
13412       if (!di->dest_set && !di->source_set)
13413         remove_info (tree_view);
13414     }
13415   
13416   unset_reorderable (tree_view);
13417 }
13418
13419 /**
13420  * gtk_tree_view_unset_rows_drag_dest:
13421  * @tree_view: a #GtkTreeView
13422  *
13423  * Undoes the effect of
13424  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13425  * #GtkTreeView:reorderable to %FALSE.
13426  **/
13427 void
13428 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13429 {
13430   TreeViewDragInfo *di;
13431
13432   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13433
13434   di = get_info (tree_view);
13435
13436   if (di)
13437     {
13438       if (di->dest_set)
13439         {
13440           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13441           di->dest_set = FALSE;
13442         }
13443
13444       if (!di->dest_set && !di->source_set)
13445         remove_info (tree_view);
13446     }
13447
13448   unset_reorderable (tree_view);
13449 }
13450
13451 /**
13452  * gtk_tree_view_set_drag_dest_row:
13453  * @tree_view: a #GtkTreeView
13454  * @path: (allow-none): The path of the row to highlight, or %NULL.
13455  * @pos: Specifies whether to drop before, after or into the row
13456  * 
13457  * Sets the row that is highlighted for feedback.
13458  **/
13459 void
13460 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13461                                  GtkTreePath            *path,
13462                                  GtkTreeViewDropPosition pos)
13463 {
13464   GtkTreePath *current_dest;
13465
13466   /* Note; this function is exported to allow a custom DND
13467    * implementation, so it can't touch TreeViewDragInfo
13468    */
13469
13470   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13471
13472   current_dest = NULL;
13473
13474   if (tree_view->priv->drag_dest_row)
13475     {
13476       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13477       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13478     }
13479
13480   /* special case a drop on an empty model */
13481   tree_view->priv->empty_view_drop = 0;
13482
13483   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13484       && gtk_tree_path_get_depth (path) == 1
13485       && gtk_tree_path_get_indices (path)[0] == 0)
13486     {
13487       gint n_children;
13488
13489       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13490                                                    NULL);
13491
13492       if (!n_children)
13493         tree_view->priv->empty_view_drop = 1;
13494     }
13495
13496   tree_view->priv->drag_dest_pos = pos;
13497
13498   if (path)
13499     {
13500       tree_view->priv->drag_dest_row =
13501         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13502       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13503     }
13504   else
13505     tree_view->priv->drag_dest_row = NULL;
13506
13507   if (current_dest)
13508     {
13509       GtkRBTree *tree, *new_tree;
13510       GtkRBNode *node, *new_node;
13511
13512       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13513       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13514
13515       if (tree && node)
13516         {
13517           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13518           if (new_tree && new_node)
13519             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13520
13521           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13522           if (new_tree && new_node)
13523             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13524         }
13525       gtk_tree_path_free (current_dest);
13526     }
13527 }
13528
13529 /**
13530  * gtk_tree_view_get_drag_dest_row:
13531  * @tree_view: a #GtkTreeView
13532  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13533  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13534  * 
13535  * Gets information about the row that is highlighted for feedback.
13536  **/
13537 void
13538 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13539                                  GtkTreePath             **path,
13540                                  GtkTreeViewDropPosition  *pos)
13541 {
13542   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13543
13544   if (path)
13545     {
13546       if (tree_view->priv->drag_dest_row)
13547         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13548       else
13549         {
13550           if (tree_view->priv->empty_view_drop)
13551             *path = gtk_tree_path_new_from_indices (0, -1);
13552           else
13553             *path = NULL;
13554         }
13555     }
13556
13557   if (pos)
13558     *pos = tree_view->priv->drag_dest_pos;
13559 }
13560
13561 /**
13562  * gtk_tree_view_get_dest_row_at_pos:
13563  * @tree_view: a #GtkTreeView
13564  * @drag_x: the position to determine the destination row for
13565  * @drag_y: the position to determine the destination row for
13566  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13567  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13568  * 
13569  * Determines the destination row for a given position.  @drag_x and
13570  * @drag_y are expected to be in widget coordinates.  This function is only
13571  * meaningful if @tree_view is realized.  Therefore this function will always
13572  * return %FALSE if @tree_view is not realized or does not have a model.
13573  * 
13574  * Return value: whether there is a row at the given position, %TRUE if this
13575  * is indeed the case.
13576  **/
13577 gboolean
13578 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13579                                    gint                     drag_x,
13580                                    gint                     drag_y,
13581                                    GtkTreePath            **path,
13582                                    GtkTreeViewDropPosition *pos)
13583 {
13584   gint cell_y;
13585   gint bin_x, bin_y;
13586   gdouble offset_into_row;
13587   gdouble third;
13588   GdkRectangle cell;
13589   GtkTreeViewColumn *column = NULL;
13590   GtkTreePath *tmp_path = NULL;
13591
13592   /* Note; this function is exported to allow a custom DND
13593    * implementation, so it can't touch TreeViewDragInfo
13594    */
13595
13596   g_return_val_if_fail (tree_view != NULL, FALSE);
13597   g_return_val_if_fail (drag_x >= 0, FALSE);
13598   g_return_val_if_fail (drag_y >= 0, FALSE);
13599
13600   if (path)
13601     *path = NULL;
13602
13603   if (tree_view->priv->bin_window == NULL)
13604     return FALSE;
13605
13606   if (tree_view->priv->tree == NULL)
13607     return FALSE;
13608
13609   /* If in the top third of a row, we drop before that row; if
13610    * in the bottom third, drop after that row; if in the middle,
13611    * and the row has children, drop into the row.
13612    */
13613   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13614                                                      &bin_x, &bin_y);
13615
13616   if (!gtk_tree_view_get_path_at_pos (tree_view,
13617                                       bin_x,
13618                                       bin_y,
13619                                       &tmp_path,
13620                                       &column,
13621                                       NULL,
13622                                       &cell_y))
13623     return FALSE;
13624
13625   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13626                                      &cell);
13627
13628   offset_into_row = cell_y;
13629
13630   if (path)
13631     *path = tmp_path;
13632   else
13633     gtk_tree_path_free (tmp_path);
13634
13635   tmp_path = NULL;
13636
13637   third = cell.height / 3.0;
13638
13639   if (pos)
13640     {
13641       if (offset_into_row < third)
13642         {
13643           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13644         }
13645       else if (offset_into_row < (cell.height / 2.0))
13646         {
13647           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13648         }
13649       else if (offset_into_row < third * 2.0)
13650         {
13651           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13652         }
13653       else
13654         {
13655           *pos = GTK_TREE_VIEW_DROP_AFTER;
13656         }
13657     }
13658
13659   return TRUE;
13660 }
13661
13662
13663
13664 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13665 /**
13666  * gtk_tree_view_create_row_drag_icon:
13667  * @tree_view: a #GtkTreeView
13668  * @path: a #GtkTreePath in @tree_view
13669  *
13670  * Creates a #GdkPixmap representation of the row at @path.  
13671  * This image is used for a drag icon.
13672  *
13673  * Return value: a newly-allocated pixmap of the drag icon.
13674  **/
13675 GdkPixmap *
13676 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13677                                     GtkTreePath  *path)
13678 {
13679   GtkTreeIter   iter;
13680   GtkRBTree    *tree;
13681   GtkRBNode    *node;
13682   gint cell_offset;
13683   GList *list;
13684   GdkRectangle background_area;
13685   GdkRectangle expose_area;
13686   GtkWidget *widget;
13687   gint depth;
13688   /* start drawing inside the black outline */
13689   gint x = 1, y = 1;
13690   GdkDrawable *drawable;
13691   gint bin_window_width;
13692   gboolean is_separator = FALSE;
13693   gboolean rtl;
13694
13695   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13696   g_return_val_if_fail (path != NULL, NULL);
13697
13698   widget = GTK_WIDGET (tree_view);
13699
13700   if (!gtk_widget_get_realized (widget))
13701     return NULL;
13702
13703   depth = gtk_tree_path_get_depth (path);
13704
13705   _gtk_tree_view_find_node (tree_view,
13706                             path,
13707                             &tree,
13708                             &node);
13709
13710   if (tree == NULL)
13711     return NULL;
13712
13713   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13714                                 &iter,
13715                                 path))
13716     return NULL;
13717   
13718   is_separator = row_is_separator (tree_view, &iter, NULL);
13719
13720   cell_offset = x;
13721
13722   background_area.y = y;
13723   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13724
13725   gdk_drawable_get_size (tree_view->priv->bin_window,
13726                          &bin_window_width, NULL);
13727
13728   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13729                              bin_window_width + 2,
13730                              background_area.height + 2,
13731                              -1);
13732
13733   expose_area.x = 0;
13734   expose_area.y = 0;
13735   expose_area.width = bin_window_width + 2;
13736   expose_area.height = background_area.height + 2;
13737
13738   gdk_draw_rectangle (drawable,
13739                       widget->style->base_gc [gtk_widget_get_state (widget)],
13740                       TRUE,
13741                       0, 0,
13742                       bin_window_width + 2,
13743                       background_area.height + 2);
13744
13745   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13746
13747   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13748       list;
13749       list = (rtl ? list->prev : list->next))
13750     {
13751       GtkTreeViewColumn *column = list->data;
13752       GdkRectangle cell_area;
13753       gint vertical_separator;
13754
13755       if (!column->visible)
13756         continue;
13757
13758       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13759                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13760                                                node->children?TRUE:FALSE);
13761
13762       background_area.x = cell_offset;
13763       background_area.width = column->width;
13764
13765       gtk_widget_style_get (widget,
13766                             "vertical-separator", &vertical_separator,
13767                             NULL);
13768
13769       cell_area = background_area;
13770
13771       cell_area.y += vertical_separator / 2;
13772       cell_area.height -= vertical_separator;
13773
13774       if (gtk_tree_view_is_expander_column (tree_view, column))
13775         {
13776           if (!rtl)
13777             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13778           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13779
13780           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13781             {
13782               if (!rtl)
13783                 cell_area.x += depth * tree_view->priv->expander_size;
13784               cell_area.width -= depth * tree_view->priv->expander_size;
13785             }
13786         }
13787
13788       if (gtk_tree_view_column_cell_is_visible (column))
13789         {
13790           if (is_separator)
13791             gtk_paint_hline (widget->style,
13792                              drawable,
13793                              GTK_STATE_NORMAL,
13794                              &cell_area,
13795                              widget,
13796                              NULL,
13797                              cell_area.x,
13798                              cell_area.x + cell_area.width,
13799                              cell_area.y + cell_area.height / 2);
13800           else
13801             _gtk_tree_view_column_cell_render (column,
13802                                                drawable,
13803                                                &background_area,
13804                                                &cell_area,
13805                                                &expose_area,
13806                                                0);
13807         }
13808       cell_offset += column->width;
13809     }
13810
13811   gdk_draw_rectangle (drawable,
13812                       widget->style->black_gc,
13813                       FALSE,
13814                       0, 0,
13815                       bin_window_width + 1,
13816                       background_area.height + 1);
13817
13818   return drawable;
13819 }
13820
13821
13822 /**
13823  * gtk_tree_view_set_destroy_count_func:
13824  * @tree_view: A #GtkTreeView
13825  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
13826  * @data: (allow-none): User data to be passed to @func, or %NULL
13827  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
13828  *
13829  * This function should almost never be used.  It is meant for private use by
13830  * ATK for determining the number of visible children that are removed when the
13831  * user collapses a row, or a row is deleted.
13832  **/
13833 void
13834 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13835                                       GtkTreeDestroyCountFunc  func,
13836                                       gpointer                 data,
13837                                       GDestroyNotify           destroy)
13838 {
13839   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13840
13841   if (tree_view->priv->destroy_count_destroy)
13842     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13843
13844   tree_view->priv->destroy_count_func = func;
13845   tree_view->priv->destroy_count_data = data;
13846   tree_view->priv->destroy_count_destroy = destroy;
13847 }
13848
13849
13850 /*
13851  * Interactive search
13852  */
13853
13854 /**
13855  * gtk_tree_view_set_enable_search:
13856  * @tree_view: A #GtkTreeView
13857  * @enable_search: %TRUE, if the user can search interactively
13858  *
13859  * If @enable_search is set, then the user can type in text to search through
13860  * the tree interactively (this is sometimes called "typeahead find").
13861  * 
13862  * Note that even if this is %FALSE, the user can still initiate a search 
13863  * using the "start-interactive-search" key binding.
13864  */
13865 void
13866 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13867                                  gboolean     enable_search)
13868 {
13869   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13870
13871   enable_search = !!enable_search;
13872   
13873   if (tree_view->priv->enable_search != enable_search)
13874     {
13875        tree_view->priv->enable_search = enable_search;
13876        g_object_notify (G_OBJECT (tree_view), "enable-search");
13877     }
13878 }
13879
13880 /**
13881  * gtk_tree_view_get_enable_search:
13882  * @tree_view: A #GtkTreeView
13883  *
13884  * Returns whether or not the tree allows to start interactive searching 
13885  * by typing in text.
13886  *
13887  * Return value: whether or not to let the user search interactively
13888  */
13889 gboolean
13890 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13891 {
13892   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13893
13894   return tree_view->priv->enable_search;
13895 }
13896
13897
13898 /**
13899  * gtk_tree_view_get_search_column:
13900  * @tree_view: A #GtkTreeView
13901  *
13902  * Gets the column searched on by the interactive search code.
13903  *
13904  * Return value: the column the interactive search code searches in.
13905  */
13906 gint
13907 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13908 {
13909   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13910
13911   return (tree_view->priv->search_column);
13912 }
13913
13914 /**
13915  * gtk_tree_view_set_search_column:
13916  * @tree_view: A #GtkTreeView
13917  * @column: the column of the model to search in, or -1 to disable searching
13918  *
13919  * Sets @column as the column where the interactive search code should
13920  * search in for the current model. 
13921  * 
13922  * If the search column is set, users can use the "start-interactive-search"
13923  * key binding to bring up search popup. The enable-search property controls
13924  * whether simply typing text will also start an interactive search.
13925  *
13926  * Note that @column refers to a column of the current model. The search 
13927  * column is reset to -1 when the model is changed.
13928  */
13929 void
13930 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13931                                  gint         column)
13932 {
13933   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13934   g_return_if_fail (column >= -1);
13935
13936   if (tree_view->priv->search_column == column)
13937     return;
13938
13939   tree_view->priv->search_column = column;
13940   g_object_notify (G_OBJECT (tree_view), "search-column");
13941 }
13942
13943 /**
13944  * gtk_tree_view_get_search_equal_func:
13945  * @tree_view: A #GtkTreeView
13946  *
13947  * Returns the compare function currently in use.
13948  *
13949  * Return value: the currently used compare function for the search code.
13950  */
13951
13952 GtkTreeViewSearchEqualFunc
13953 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
13954 {
13955   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13956
13957   return tree_view->priv->search_equal_func;
13958 }
13959
13960 /**
13961  * gtk_tree_view_set_search_equal_func:
13962  * @tree_view: A #GtkTreeView
13963  * @search_equal_func: the compare function to use during the search
13964  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
13965  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
13966  *
13967  * Sets the compare function for the interactive search capabilities; note
13968  * that somewhat like strcmp() returning 0 for equality
13969  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
13970  **/
13971 void
13972 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
13973                                      GtkTreeViewSearchEqualFunc  search_equal_func,
13974                                      gpointer                    search_user_data,
13975                                      GDestroyNotify              search_destroy)
13976 {
13977   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13978   g_return_if_fail (search_equal_func != NULL);
13979
13980   if (tree_view->priv->search_destroy)
13981     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
13982
13983   tree_view->priv->search_equal_func = search_equal_func;
13984   tree_view->priv->search_user_data = search_user_data;
13985   tree_view->priv->search_destroy = search_destroy;
13986   if (tree_view->priv->search_equal_func == NULL)
13987     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
13988 }
13989
13990 /**
13991  * gtk_tree_view_get_search_entry:
13992  * @tree_view: A #GtkTreeView
13993  *
13994  * Returns the #GtkEntry which is currently in use as interactive search
13995  * entry for @tree_view.  In case the built-in entry is being used, %NULL
13996  * will be returned.
13997  *
13998  * Return value: the entry currently in use as search entry.
13999  *
14000  * Since: 2.10
14001  */
14002 GtkEntry *
14003 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14004 {
14005   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14006
14007   if (tree_view->priv->search_custom_entry_set)
14008     return GTK_ENTRY (tree_view->priv->search_entry);
14009
14010   return NULL;
14011 }
14012
14013 /**
14014  * gtk_tree_view_set_search_entry:
14015  * @tree_view: A #GtkTreeView
14016  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14017  *
14018  * Sets the entry which the interactive search code will use for this
14019  * @tree_view.  This is useful when you want to provide a search entry
14020  * in our interface at all time at a fixed position.  Passing %NULL for
14021  * @entry will make the interactive search code use the built-in popup
14022  * entry again.
14023  *
14024  * Since: 2.10
14025  */
14026 void
14027 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14028                                 GtkEntry    *entry)
14029 {
14030   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14031   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14032
14033   if (tree_view->priv->search_custom_entry_set)
14034     {
14035       if (tree_view->priv->search_entry_changed_id)
14036         {
14037           g_signal_handler_disconnect (tree_view->priv->search_entry,
14038                                        tree_view->priv->search_entry_changed_id);
14039           tree_view->priv->search_entry_changed_id = 0;
14040         }
14041       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14042                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14043                                             tree_view);
14044
14045       g_object_unref (tree_view->priv->search_entry);
14046     }
14047   else if (tree_view->priv->search_window)
14048     {
14049       gtk_widget_destroy (tree_view->priv->search_window);
14050
14051       tree_view->priv->search_window = NULL;
14052     }
14053
14054   if (entry)
14055     {
14056       tree_view->priv->search_entry = g_object_ref (entry);
14057       tree_view->priv->search_custom_entry_set = TRUE;
14058
14059       if (tree_view->priv->search_entry_changed_id == 0)
14060         {
14061           tree_view->priv->search_entry_changed_id =
14062             g_signal_connect (tree_view->priv->search_entry, "changed",
14063                               G_CALLBACK (gtk_tree_view_search_init),
14064                               tree_view);
14065         }
14066       
14067         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14068                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14069                           tree_view);
14070
14071         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14072     }
14073   else
14074     {
14075       tree_view->priv->search_entry = NULL;
14076       tree_view->priv->search_custom_entry_set = FALSE;
14077     }
14078 }
14079
14080 /**
14081  * gtk_tree_view_set_search_position_func:
14082  * @tree_view: A #GtkTreeView
14083  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14084  *    to use the default search position function
14085  * @data: (allow-none): user data to pass to @func, or %NULL
14086  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14087  *
14088  * Sets the function to use when positioning the search dialog.
14089  *
14090  * Since: 2.10
14091  **/
14092 void
14093 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14094                                         GtkTreeViewSearchPositionFunc  func,
14095                                         gpointer                       user_data,
14096                                         GDestroyNotify                 destroy)
14097 {
14098   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14099
14100   if (tree_view->priv->search_position_destroy)
14101     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14102
14103   tree_view->priv->search_position_func = func;
14104   tree_view->priv->search_position_user_data = user_data;
14105   tree_view->priv->search_position_destroy = destroy;
14106   if (tree_view->priv->search_position_func == NULL)
14107     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14108 }
14109
14110 /**
14111  * gtk_tree_view_get_search_position_func:
14112  * @tree_view: A #GtkTreeView
14113  *
14114  * Returns the positioning function currently in use.
14115  *
14116  * Return value: the currently used function for positioning the search dialog.
14117  *
14118  * Since: 2.10
14119  */
14120 GtkTreeViewSearchPositionFunc
14121 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14122 {
14123   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14124
14125   return tree_view->priv->search_position_func;
14126 }
14127
14128
14129 static void
14130 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14131                                   GtkTreeView *tree_view,
14132                                   GdkDevice   *device)
14133 {
14134   if (tree_view->priv->disable_popdown)
14135     return;
14136
14137   if (tree_view->priv->search_entry_changed_id)
14138     {
14139       g_signal_handler_disconnect (tree_view->priv->search_entry,
14140                                    tree_view->priv->search_entry_changed_id);
14141       tree_view->priv->search_entry_changed_id = 0;
14142     }
14143   if (tree_view->priv->typeselect_flush_timeout)
14144     {
14145       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14146       tree_view->priv->typeselect_flush_timeout = 0;
14147     }
14148         
14149   if (gtk_widget_get_visible (search_dialog))
14150     {
14151       /* send focus-in event */
14152       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14153       gtk_widget_hide (search_dialog);
14154       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14155       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14156     }
14157 }
14158
14159 static void
14160 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14161                                     GtkWidget   *search_dialog,
14162                                     gpointer     user_data)
14163 {
14164   gint x, y;
14165   gint tree_x, tree_y;
14166   gint tree_width, tree_height;
14167   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
14168   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14169   GtkRequisition requisition;
14170   gint monitor_num;
14171   GdkRectangle monitor;
14172
14173   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14174   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14175
14176   gtk_widget_realize (search_dialog);
14177
14178   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14179   gdk_drawable_get_size (tree_window,
14180                          &tree_width,
14181                          &tree_height);
14182   gtk_widget_size_request (search_dialog, &requisition);
14183
14184   if (tree_x + tree_width > gdk_screen_get_width (screen))
14185     x = gdk_screen_get_width (screen) - requisition.width;
14186   else if (tree_x + tree_width - requisition.width < 0)
14187     x = 0;
14188   else
14189     x = tree_x + tree_width - requisition.width;
14190
14191   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14192     y = gdk_screen_get_height (screen) - requisition.height;
14193   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14194     y = 0;
14195   else
14196     y = tree_y + tree_height;
14197
14198   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14199 }
14200
14201 static void
14202 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14203                                       GtkMenu  *menu,
14204                                       gpointer  data)
14205 {
14206   GtkTreeView *tree_view = (GtkTreeView *)data;
14207
14208   tree_view->priv->disable_popdown = 1;
14209   g_signal_connect (menu, "hide",
14210                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14211 }
14212
14213 /* Because we're visible but offscreen, we just set a flag in the preedit
14214  * callback.
14215  */
14216 static void
14217 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14218                                       GtkTreeView  *tree_view)
14219 {
14220   tree_view->priv->imcontext_changed = 1;
14221   if (tree_view->priv->typeselect_flush_timeout)
14222     {
14223       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14224       tree_view->priv->typeselect_flush_timeout =
14225         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14226                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14227                        tree_view);
14228     }
14229
14230 }
14231
14232 static void
14233 gtk_tree_view_search_activate (GtkEntry    *entry,
14234                                GtkTreeView *tree_view)
14235 {
14236   GtkTreePath *path;
14237   GtkRBNode *node;
14238   GtkRBTree *tree;
14239
14240   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14241                                     tree_view,
14242                                     gtk_get_current_event_device ());
14243
14244   /* If we have a row selected and it's the cursor row, we activate
14245    * the row XXX */
14246   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14247     {
14248       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14249       
14250       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14251       
14252       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14253         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14254       
14255       gtk_tree_path_free (path);
14256     }
14257 }
14258
14259 static gboolean
14260 gtk_tree_view_real_search_enable_popdown (gpointer data)
14261 {
14262   GtkTreeView *tree_view = (GtkTreeView *)data;
14263
14264   tree_view->priv->disable_popdown = 0;
14265
14266   return FALSE;
14267 }
14268
14269 static void
14270 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14271                                      gpointer   data)
14272 {
14273   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14274 }
14275
14276 static gboolean
14277 gtk_tree_view_search_delete_event (GtkWidget *widget,
14278                                    GdkEventAny *event,
14279                                    GtkTreeView *tree_view)
14280 {
14281   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14282
14283   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14284
14285   return TRUE;
14286 }
14287
14288 static gboolean
14289 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14290                                          GdkEventButton *event,
14291                                          GtkTreeView *tree_view)
14292 {
14293   GdkDevice *keyb_device;
14294
14295   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14296
14297   keyb_device = gdk_device_get_associated_device (event->device);
14298   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14299
14300   if (event->window == tree_view->priv->bin_window)
14301     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14302
14303   return TRUE;
14304 }
14305
14306 static gboolean
14307 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14308                                    GdkEventScroll *event,
14309                                    GtkTreeView *tree_view)
14310 {
14311   gboolean retval = FALSE;
14312
14313   if (event->direction == GDK_SCROLL_UP)
14314     {
14315       gtk_tree_view_search_move (widget, tree_view, TRUE);
14316       retval = TRUE;
14317     }
14318   else if (event->direction == GDK_SCROLL_DOWN)
14319     {
14320       gtk_tree_view_search_move (widget, tree_view, FALSE);
14321       retval = TRUE;
14322     }
14323
14324   /* renew the flush timeout */
14325   if (retval && tree_view->priv->typeselect_flush_timeout
14326       && !tree_view->priv->search_custom_entry_set)
14327     {
14328       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14329       tree_view->priv->typeselect_flush_timeout =
14330         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14331                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14332                        tree_view);
14333     }
14334
14335   return retval;
14336 }
14337
14338 static gboolean
14339 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14340                                       GdkEventKey *event,
14341                                       GtkTreeView *tree_view)
14342 {
14343   gboolean retval = FALSE;
14344
14345   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14346   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14347
14348   /* close window and cancel the search */
14349   if (!tree_view->priv->search_custom_entry_set
14350       && (event->keyval == GDK_Escape ||
14351           event->keyval == GDK_Tab ||
14352             event->keyval == GDK_KP_Tab ||
14353             event->keyval == GDK_ISO_Left_Tab))
14354     {
14355       gtk_tree_view_search_dialog_hide (widget, tree_view,
14356                                         gdk_event_get_device ((GdkEvent *) event));
14357       return TRUE;
14358     }
14359
14360   /* select previous matching iter */
14361   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
14362     {
14363       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14364         gtk_widget_error_bell (widget);
14365
14366       retval = TRUE;
14367     }
14368
14369   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14370       && (event->keyval == GDK_g || event->keyval == GDK_G))
14371     {
14372       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14373         gtk_widget_error_bell (widget);
14374
14375       retval = TRUE;
14376     }
14377
14378   /* select next matching iter */
14379   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
14380     {
14381       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14382         gtk_widget_error_bell (widget);
14383
14384       retval = TRUE;
14385     }
14386
14387   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14388       && (event->keyval == GDK_g || event->keyval == GDK_G))
14389     {
14390       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14391         gtk_widget_error_bell (widget);
14392
14393       retval = TRUE;
14394     }
14395
14396   /* renew the flush timeout */
14397   if (retval && tree_view->priv->typeselect_flush_timeout
14398       && !tree_view->priv->search_custom_entry_set)
14399     {
14400       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14401       tree_view->priv->typeselect_flush_timeout =
14402         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14403                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14404                        tree_view);
14405     }
14406
14407   return retval;
14408 }
14409
14410 /*  this function returns FALSE if there is a search string but
14411  *  nothing was found, and TRUE otherwise.
14412  */
14413 static gboolean
14414 gtk_tree_view_search_move (GtkWidget   *window,
14415                            GtkTreeView *tree_view,
14416                            gboolean     up)
14417 {
14418   gboolean ret;
14419   gint len;
14420   gint count = 0;
14421   const gchar *text;
14422   GtkTreeIter iter;
14423   GtkTreeModel *model;
14424   GtkTreeSelection *selection;
14425
14426   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14427
14428   g_return_val_if_fail (text != NULL, FALSE);
14429
14430   len = strlen (text);
14431
14432   if (up && tree_view->priv->selected_iter == 1)
14433     return strlen (text) < 1;
14434
14435   len = strlen (text);
14436
14437   if (len < 1)
14438     return TRUE;
14439
14440   model = gtk_tree_view_get_model (tree_view);
14441   selection = gtk_tree_view_get_selection (tree_view);
14442
14443   /* search */
14444   gtk_tree_selection_unselect_all (selection);
14445   if (!gtk_tree_model_get_iter_first (model, &iter))
14446     return TRUE;
14447
14448   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14449                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14450
14451   if (ret)
14452     {
14453       /* found */
14454       tree_view->priv->selected_iter += up?(-1):(1);
14455       return TRUE;
14456     }
14457   else
14458     {
14459       /* return to old iter */
14460       count = 0;
14461       gtk_tree_model_get_iter_first (model, &iter);
14462       gtk_tree_view_search_iter (model, selection,
14463                                  &iter, text,
14464                                  &count, tree_view->priv->selected_iter);
14465       return FALSE;
14466     }
14467 }
14468
14469 static gboolean
14470 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14471                                  gint          column,
14472                                  const gchar  *key,
14473                                  GtkTreeIter  *iter,
14474                                  gpointer      search_data)
14475 {
14476   gboolean retval = TRUE;
14477   const gchar *str;
14478   gchar *normalized_string;
14479   gchar *normalized_key;
14480   gchar *case_normalized_string = NULL;
14481   gchar *case_normalized_key = NULL;
14482   GValue value = {0,};
14483   GValue transformed = {0,};
14484
14485   gtk_tree_model_get_value (model, iter, column, &value);
14486
14487   g_value_init (&transformed, G_TYPE_STRING);
14488
14489   if (!g_value_transform (&value, &transformed))
14490     {
14491       g_value_unset (&value);
14492       return TRUE;
14493     }
14494
14495   g_value_unset (&value);
14496
14497   str = g_value_get_string (&transformed);
14498   if (!str)
14499     {
14500       g_value_unset (&transformed);
14501       return TRUE;
14502     }
14503
14504   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14505   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14506
14507   if (normalized_string && normalized_key)
14508     {
14509       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14510       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14511
14512       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14513         retval = FALSE;
14514     }
14515
14516   g_value_unset (&transformed);
14517   g_free (normalized_key);
14518   g_free (normalized_string);
14519   g_free (case_normalized_key);
14520   g_free (case_normalized_string);
14521
14522   return retval;
14523 }
14524
14525 static gboolean
14526 gtk_tree_view_search_iter (GtkTreeModel     *model,
14527                            GtkTreeSelection *selection,
14528                            GtkTreeIter      *iter,
14529                            const gchar      *text,
14530                            gint             *count,
14531                            gint              n)
14532 {
14533   GtkRBTree *tree = NULL;
14534   GtkRBNode *node = NULL;
14535   GtkTreePath *path;
14536
14537   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14538
14539   path = gtk_tree_model_get_path (model, iter);
14540   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14541
14542   do
14543     {
14544       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14545         {
14546           (*count)++;
14547           if (*count == n)
14548             {
14549               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14550                                             TRUE, 0.5, 0.0);
14551               gtk_tree_selection_select_iter (selection, iter);
14552               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14553
14554               if (path)
14555                 gtk_tree_path_free (path);
14556
14557               return TRUE;
14558             }
14559         }
14560
14561       if (node->children)
14562         {
14563           gboolean has_child;
14564           GtkTreeIter tmp;
14565
14566           tree = node->children;
14567           node = tree->root;
14568
14569           while (node->left != tree->nil)
14570             node = node->left;
14571
14572           tmp = *iter;
14573           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14574           gtk_tree_path_down (path);
14575
14576           /* sanity check */
14577           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14578         }
14579       else
14580         {
14581           gboolean done = FALSE;
14582
14583           do
14584             {
14585               node = _gtk_rbtree_next (tree, node);
14586
14587               if (node)
14588                 {
14589                   gboolean has_next;
14590
14591                   has_next = gtk_tree_model_iter_next (model, iter);
14592
14593                   done = TRUE;
14594                   gtk_tree_path_next (path);
14595
14596                   /* sanity check */
14597                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14598                 }
14599               else
14600                 {
14601                   gboolean has_parent;
14602                   GtkTreeIter tmp_iter = *iter;
14603
14604                   node = tree->parent_node;
14605                   tree = tree->parent_tree;
14606
14607                   if (!tree)
14608                     {
14609                       if (path)
14610                         gtk_tree_path_free (path);
14611
14612                       /* we've run out of tree, done with this func */
14613                       return FALSE;
14614                     }
14615
14616                   has_parent = gtk_tree_model_iter_parent (model,
14617                                                            iter,
14618                                                            &tmp_iter);
14619                   gtk_tree_path_up (path);
14620
14621                   /* sanity check */
14622                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14623                 }
14624             }
14625           while (!done);
14626         }
14627     }
14628   while (1);
14629
14630   return FALSE;
14631 }
14632
14633 static void
14634 gtk_tree_view_search_init (GtkWidget   *entry,
14635                            GtkTreeView *tree_view)
14636 {
14637   gint ret;
14638   gint count = 0;
14639   const gchar *text;
14640   GtkTreeIter iter;
14641   GtkTreeModel *model;
14642   GtkTreeSelection *selection;
14643
14644   g_return_if_fail (GTK_IS_ENTRY (entry));
14645   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14646
14647   text = gtk_entry_get_text (GTK_ENTRY (entry));
14648
14649   model = gtk_tree_view_get_model (tree_view);
14650   selection = gtk_tree_view_get_selection (tree_view);
14651
14652   /* search */
14653   gtk_tree_selection_unselect_all (selection);
14654   if (tree_view->priv->typeselect_flush_timeout
14655       && !tree_view->priv->search_custom_entry_set)
14656     {
14657       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14658       tree_view->priv->typeselect_flush_timeout =
14659         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14660                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14661                        tree_view);
14662     }
14663
14664   if (*text == '\0')
14665     return;
14666
14667   if (!gtk_tree_model_get_iter_first (model, &iter))
14668     return;
14669
14670   ret = gtk_tree_view_search_iter (model, selection,
14671                                    &iter, text,
14672                                    &count, 1);
14673
14674   if (ret)
14675     tree_view->priv->selected_iter = 1;
14676 }
14677
14678 static void
14679 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14680                              GtkTreeView     *tree_view)
14681 {
14682   if (tree_view->priv->edited_column == NULL)
14683     return;
14684
14685   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14686   tree_view->priv->edited_column = NULL;
14687
14688   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
14689     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14690
14691   g_signal_handlers_disconnect_by_func (cell_editable,
14692                                         gtk_tree_view_remove_widget,
14693                                         tree_view);
14694
14695   gtk_container_remove (GTK_CONTAINER (tree_view),
14696                         GTK_WIDGET (cell_editable));  
14697
14698   /* FIXME should only redraw a single node */
14699   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14700 }
14701
14702 static gboolean
14703 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14704                              GtkTreePath *cursor_path)
14705 {
14706   GtkTreeIter iter;
14707   GdkRectangle background_area;
14708   GdkRectangle cell_area;
14709   GtkCellEditable *editable_widget = NULL;
14710   gchar *path_string;
14711   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14712   gint retval = FALSE;
14713   GtkRBTree *cursor_tree;
14714   GtkRBNode *cursor_node;
14715
14716   g_assert (tree_view->priv->focus_column);
14717
14718   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
14719     return FALSE;
14720
14721   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14722       cursor_node == NULL)
14723     return FALSE;
14724
14725   path_string = gtk_tree_path_to_string (cursor_path);
14726   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14727
14728   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14729
14730   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14731                                            tree_view->priv->model,
14732                                            &iter,
14733                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14734                                            cursor_node->children?TRUE:FALSE);
14735   gtk_tree_view_get_background_area (tree_view,
14736                                      cursor_path,
14737                                      tree_view->priv->focus_column,
14738                                      &background_area);
14739   gtk_tree_view_get_cell_area (tree_view,
14740                                cursor_path,
14741                                tree_view->priv->focus_column,
14742                                &cell_area);
14743
14744   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14745                                         &editable_widget,
14746                                         NULL,
14747                                         path_string,
14748                                         &background_area,
14749                                         &cell_area,
14750                                         flags))
14751     {
14752       retval = TRUE;
14753       if (editable_widget != NULL)
14754         {
14755           gint left, right;
14756           GdkRectangle area;
14757           GtkCellRenderer *cell;
14758
14759           area = cell_area;
14760           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14761
14762           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14763
14764           area.x += left;
14765           area.width -= right + left;
14766
14767           gtk_tree_view_real_start_editing (tree_view,
14768                                             tree_view->priv->focus_column,
14769                                             cursor_path,
14770                                             editable_widget,
14771                                             &area,
14772                                             NULL,
14773                                             flags);
14774         }
14775
14776     }
14777   g_free (path_string);
14778   return retval;
14779 }
14780
14781 static void
14782 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14783                                   GtkTreeViewColumn *column,
14784                                   GtkTreePath       *path,
14785                                   GtkCellEditable   *cell_editable,
14786                                   GdkRectangle      *cell_area,
14787                                   GdkEvent          *event,
14788                                   guint              flags)
14789 {
14790   gint pre_val = tree_view->priv->vadjustment->value;
14791   GtkRequisition requisition;
14792
14793   tree_view->priv->edited_column = column;
14794   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14795
14796   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14797   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14798
14799   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
14800
14801   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14802
14803   if (requisition.height < cell_area->height)
14804     {
14805       gint diff = cell_area->height - requisition.height;
14806       gtk_tree_view_put (tree_view,
14807                          GTK_WIDGET (cell_editable),
14808                          cell_area->x, cell_area->y + diff/2,
14809                          cell_area->width, requisition.height);
14810     }
14811   else
14812     {
14813       gtk_tree_view_put (tree_view,
14814                          GTK_WIDGET (cell_editable),
14815                          cell_area->x, cell_area->y,
14816                          cell_area->width, cell_area->height);
14817     }
14818
14819   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14820                                    (GdkEvent *)event);
14821
14822   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14823   g_signal_connect (cell_editable, "remove-widget",
14824                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14825 }
14826
14827 static void
14828 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14829                             gboolean     cancel_editing)
14830 {
14831   GtkTreeViewColumn *column;
14832   GtkCellRenderer *cell;
14833
14834   if (tree_view->priv->edited_column == NULL)
14835     return;
14836
14837   /*
14838    * This is very evil. We need to do this, because
14839    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14840    * later on. If gtk_tree_view_row_changed notices
14841    * tree_view->priv->edited_column != NULL, it'll call
14842    * gtk_tree_view_stop_editing again. Bad things will happen then.
14843    *
14844    * Please read that again if you intend to modify anything here.
14845    */
14846
14847   column = tree_view->priv->edited_column;
14848   tree_view->priv->edited_column = NULL;
14849
14850   cell = _gtk_tree_view_column_get_edited_cell (column);
14851   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14852
14853   if (!cancel_editing)
14854     gtk_cell_editable_editing_done (column->editable_widget);
14855
14856   tree_view->priv->edited_column = column;
14857
14858   gtk_cell_editable_remove_widget (column->editable_widget);
14859 }
14860
14861
14862 /**
14863  * gtk_tree_view_set_hover_selection:
14864  * @tree_view: a #GtkTreeView
14865  * @hover: %TRUE to enable hover selection mode
14866  *
14867  * Enables of disables the hover selection mode of @tree_view.
14868  * Hover selection makes the selected row follow the pointer.
14869  * Currently, this works only for the selection modes 
14870  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14871  * 
14872  * Since: 2.6
14873  **/
14874 void     
14875 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14876                                    gboolean     hover)
14877 {
14878   hover = hover != FALSE;
14879
14880   if (hover != tree_view->priv->hover_selection)
14881     {
14882       tree_view->priv->hover_selection = hover;
14883
14884       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14885     }
14886 }
14887
14888 /**
14889  * gtk_tree_view_get_hover_selection:
14890  * @tree_view: a #GtkTreeView
14891  * 
14892  * Returns whether hover selection mode is turned on for @tree_view.
14893  * 
14894  * Return value: %TRUE if @tree_view is in hover selection mode
14895  *
14896  * Since: 2.6 
14897  **/
14898 gboolean 
14899 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14900 {
14901   return tree_view->priv->hover_selection;
14902 }
14903
14904 /**
14905  * gtk_tree_view_set_hover_expand:
14906  * @tree_view: a #GtkTreeView
14907  * @expand: %TRUE to enable hover selection mode
14908  *
14909  * Enables of disables the hover expansion mode of @tree_view.
14910  * Hover expansion makes rows expand or collapse if the pointer 
14911  * moves over them.
14912  * 
14913  * Since: 2.6
14914  **/
14915 void     
14916 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14917                                 gboolean     expand)
14918 {
14919   expand = expand != FALSE;
14920
14921   if (expand != tree_view->priv->hover_expand)
14922     {
14923       tree_view->priv->hover_expand = expand;
14924
14925       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14926     }
14927 }
14928
14929 /**
14930  * gtk_tree_view_get_hover_expand:
14931  * @tree_view: a #GtkTreeView
14932  * 
14933  * Returns whether hover expansion mode is turned on for @tree_view.
14934  * 
14935  * Return value: %TRUE if @tree_view is in hover expansion mode
14936  *
14937  * Since: 2.6 
14938  **/
14939 gboolean 
14940 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14941 {
14942   return tree_view->priv->hover_expand;
14943 }
14944
14945 /**
14946  * gtk_tree_view_set_rubber_banding:
14947  * @tree_view: a #GtkTreeView
14948  * @enable: %TRUE to enable rubber banding
14949  *
14950  * Enables or disables rubber banding in @tree_view.  If the selection mode
14951  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14952  * multiple rows by dragging the mouse.
14953  * 
14954  * Since: 2.10
14955  **/
14956 void
14957 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
14958                                   gboolean     enable)
14959 {
14960   enable = enable != FALSE;
14961
14962   if (enable != tree_view->priv->rubber_banding_enable)
14963     {
14964       tree_view->priv->rubber_banding_enable = enable;
14965
14966       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
14967     }
14968 }
14969
14970 /**
14971  * gtk_tree_view_get_rubber_banding:
14972  * @tree_view: a #GtkTreeView
14973  * 
14974  * Returns whether rubber banding is turned on for @tree_view.  If the
14975  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
14976  * user to select multiple rows by dragging the mouse.
14977  * 
14978  * Return value: %TRUE if rubber banding in @tree_view is enabled.
14979  *
14980  * Since: 2.10
14981  **/
14982 gboolean
14983 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
14984 {
14985   return tree_view->priv->rubber_banding_enable;
14986 }
14987
14988 /**
14989  * gtk_tree_view_is_rubber_banding_active:
14990  * @tree_view: a #GtkTreeView
14991  * 
14992  * Returns whether a rubber banding operation is currently being done
14993  * in @tree_view.
14994  *
14995  * Return value: %TRUE if a rubber banding operation is currently being
14996  * done in @tree_view.
14997  *
14998  * Since: 2.12
14999  **/
15000 gboolean
15001 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15002 {
15003   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15004
15005   if (tree_view->priv->rubber_banding_enable
15006       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15007     return TRUE;
15008
15009   return FALSE;
15010 }
15011
15012 /**
15013  * gtk_tree_view_get_row_separator_func:
15014  * @tree_view: a #GtkTreeView
15015  * 
15016  * Returns the current row separator function.
15017  * 
15018  * Return value: the current row separator function.
15019  *
15020  * Since: 2.6
15021  **/
15022 GtkTreeViewRowSeparatorFunc 
15023 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15024 {
15025   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15026
15027   return tree_view->priv->row_separator_func;
15028 }
15029
15030 /**
15031  * gtk_tree_view_set_row_separator_func:
15032  * @tree_view: a #GtkTreeView
15033  * @func: a #GtkTreeViewRowSeparatorFunc
15034  * @data: (allow-none): user data to pass to @func, or %NULL
15035  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15036  * 
15037  * Sets the row separator function, which is used to determine
15038  * whether a row should be drawn as a separator. If the row separator
15039  * function is %NULL, no separators are drawn. This is the default value.
15040  *
15041  * Since: 2.6
15042  **/
15043 void
15044 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15045                                       GtkTreeViewRowSeparatorFunc  func,
15046                                       gpointer                     data,
15047                                       GDestroyNotify               destroy)
15048 {
15049   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15050
15051   if (tree_view->priv->row_separator_destroy)
15052     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15053
15054   tree_view->priv->row_separator_func = func;
15055   tree_view->priv->row_separator_data = data;
15056   tree_view->priv->row_separator_destroy = destroy;
15057
15058   /* Have the tree recalculate heights */
15059   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15060   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15061 }
15062
15063   
15064 static void
15065 gtk_tree_view_grab_notify (GtkWidget *widget,
15066                            gboolean   was_grabbed)
15067 {
15068   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15069
15070   tree_view->priv->in_grab = !was_grabbed;
15071
15072   if (!was_grabbed)
15073     {
15074       tree_view->priv->pressed_button = -1;
15075
15076       if (tree_view->priv->rubber_band_status)
15077         gtk_tree_view_stop_rubber_band (tree_view);
15078     }
15079 }
15080
15081 static void
15082 gtk_tree_view_state_changed (GtkWidget      *widget,
15083                              GtkStateType    previous_state)
15084 {
15085   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15086
15087   if (gtk_widget_get_realized (widget))
15088     {
15089       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
15090       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
15091     }
15092
15093   gtk_widget_queue_draw (widget);
15094 }
15095
15096 /**
15097  * gtk_tree_view_get_grid_lines:
15098  * @tree_view: a #GtkTreeView
15099  *
15100  * Returns which grid lines are enabled in @tree_view.
15101  *
15102  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15103  * are enabled.
15104  *
15105  * Since: 2.10
15106  */
15107 GtkTreeViewGridLines
15108 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15109 {
15110   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15111
15112   return tree_view->priv->grid_lines;
15113 }
15114
15115 /**
15116  * gtk_tree_view_set_grid_lines:
15117  * @tree_view: a #GtkTreeView
15118  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15119  * enable.
15120  *
15121  * Sets which grid lines to draw in @tree_view.
15122  *
15123  * Since: 2.10
15124  */
15125 void
15126 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15127                               GtkTreeViewGridLines   grid_lines)
15128 {
15129   GtkTreeViewPrivate *priv;
15130   GtkWidget *widget;
15131   GtkTreeViewGridLines old_grid_lines;
15132
15133   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15134
15135   priv = tree_view->priv;
15136   widget = GTK_WIDGET (tree_view);
15137
15138   old_grid_lines = priv->grid_lines;
15139   priv->grid_lines = grid_lines;
15140   
15141   if (gtk_widget_get_realized (widget))
15142     {
15143       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15144           priv->grid_line_gc)
15145         {
15146           g_object_unref (priv->grid_line_gc);
15147           priv->grid_line_gc = NULL;
15148         }
15149       
15150       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15151           !priv->grid_line_gc)
15152         {
15153           gint line_width;
15154           gint8 *dash_list;
15155
15156           gtk_widget_style_get (widget,
15157                                 "grid-line-width", &line_width,
15158                                 "grid-line-pattern", (gchar *)&dash_list,
15159                                 NULL);
15160       
15161           priv->grid_line_gc = gdk_gc_new (widget->window);
15162           gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
15163           
15164           gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
15165                                       GDK_LINE_ON_OFF_DASH,
15166                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15167           gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
15168
15169           g_free (dash_list);
15170         }      
15171     }
15172
15173   if (old_grid_lines != grid_lines)
15174     {
15175       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15176       
15177       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15178     }
15179 }
15180
15181 /**
15182  * gtk_tree_view_get_enable_tree_lines:
15183  * @tree_view: a #GtkTreeView.
15184  *
15185  * Returns whether or not tree lines are drawn in @tree_view.
15186  *
15187  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15188  * otherwise.
15189  *
15190  * Since: 2.10
15191  */
15192 gboolean
15193 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15194 {
15195   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15196
15197   return tree_view->priv->tree_lines_enabled;
15198 }
15199
15200 /**
15201  * gtk_tree_view_set_enable_tree_lines:
15202  * @tree_view: a #GtkTreeView
15203  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15204  *
15205  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15206  * This does not have any visible effects for lists.
15207  *
15208  * Since: 2.10
15209  */
15210 void
15211 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15212                                      gboolean     enabled)
15213 {
15214   GtkTreeViewPrivate *priv;
15215   GtkWidget *widget;
15216   gboolean was_enabled;
15217
15218   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15219
15220   enabled = enabled != FALSE;
15221
15222   priv = tree_view->priv;
15223   widget = GTK_WIDGET (tree_view);
15224
15225   was_enabled = priv->tree_lines_enabled;
15226
15227   priv->tree_lines_enabled = enabled;
15228
15229   if (gtk_widget_get_realized (widget))
15230     {
15231       if (!enabled && priv->tree_line_gc)
15232         {
15233           g_object_unref (priv->tree_line_gc);
15234           priv->tree_line_gc = NULL;
15235         }
15236       
15237       if (enabled && !priv->tree_line_gc)
15238         {
15239           gint line_width;
15240           gint8 *dash_list;
15241           gtk_widget_style_get (widget,
15242                                 "tree-line-width", &line_width,
15243                                 "tree-line-pattern", (gchar *)&dash_list,
15244                                 NULL);
15245           
15246           priv->tree_line_gc = gdk_gc_new (widget->window);
15247           gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc);
15248           
15249           gdk_gc_set_line_attributes (priv->tree_line_gc, line_width,
15250                                       GDK_LINE_ON_OFF_DASH,
15251                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15252           gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2);
15253
15254           g_free (dash_list);
15255         }
15256     }
15257
15258   if (was_enabled != enabled)
15259     {
15260       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15261
15262       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15263     }
15264 }
15265
15266
15267 /**
15268  * gtk_tree_view_set_show_expanders:
15269  * @tree_view: a #GtkTreeView
15270  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15271  *
15272  * Sets whether to draw and enable expanders and indent child rows in
15273  * @tree_view.  When disabled there will be no expanders visible in trees
15274  * and there will be no way to expand and collapse rows by default.  Also
15275  * note that hiding the expanders will disable the default indentation.  You
15276  * can set a custom indentation in this case using
15277  * gtk_tree_view_set_level_indentation().
15278  * This does not have any visible effects for lists.
15279  *
15280  * Since: 2.12
15281  */
15282 void
15283 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15284                                   gboolean     enabled)
15285 {
15286   gboolean was_enabled;
15287
15288   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15289
15290   enabled = enabled != FALSE;
15291   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15292
15293   if (enabled)
15294     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15295   else
15296     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15297
15298   if (enabled != was_enabled)
15299     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15300 }
15301
15302 /**
15303  * gtk_tree_view_get_show_expanders:
15304  * @tree_view: a #GtkTreeView.
15305  *
15306  * Returns whether or not expanders are drawn in @tree_view.
15307  *
15308  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15309  * otherwise.
15310  *
15311  * Since: 2.12
15312  */
15313 gboolean
15314 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15315 {
15316   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15317
15318   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15319 }
15320
15321 /**
15322  * gtk_tree_view_set_level_indentation:
15323  * @tree_view: a #GtkTreeView
15324  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15325  *
15326  * Sets the amount of extra indentation for child levels to use in @tree_view
15327  * in addition to the default indentation.  The value should be specified in
15328  * pixels, a value of 0 disables this feature and in this case only the default
15329  * indentation will be used.
15330  * This does not have any visible effects for lists.
15331  *
15332  * Since: 2.12
15333  */
15334 void
15335 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15336                                      gint         indentation)
15337 {
15338   tree_view->priv->level_indentation = indentation;
15339
15340   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15341 }
15342
15343 /**
15344  * gtk_tree_view_get_level_indentation:
15345  * @tree_view: a #GtkTreeView.
15346  *
15347  * Returns the amount, in pixels, of extra indentation for child levels
15348  * in @tree_view.
15349  *
15350  * Return value: the amount of extra indentation for child levels in
15351  * @tree_view.  A return value of 0 means that this feature is disabled.
15352  *
15353  * Since: 2.12
15354  */
15355 gint
15356 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15357 {
15358   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15359
15360   return tree_view->priv->level_indentation;
15361 }
15362
15363 /**
15364  * gtk_tree_view_set_tooltip_row:
15365  * @tree_view: a #GtkTreeView
15366  * @tooltip: a #GtkTooltip
15367  * @path: a #GtkTreePath
15368  *
15369  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15370  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15371  * See also gtk_tooltip_set_tip_area().
15372  *
15373  * Since: 2.12
15374  */
15375 void
15376 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15377                                GtkTooltip  *tooltip,
15378                                GtkTreePath *path)
15379 {
15380   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15381   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15382
15383   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15384 }
15385
15386 /**
15387  * gtk_tree_view_set_tooltip_cell:
15388  * @tree_view: a #GtkTreeView
15389  * @tooltip: a #GtkTooltip
15390  * @path: (allow-none): a #GtkTreePath or %NULL
15391  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
15392  * @cell: (allow-none): a #GtkCellRenderer or %NULL
15393  *
15394  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15395  * in common.  For example if @path is %NULL and @column is set, the tip
15396  * area will be set to the full area covered by @column.  See also
15397  * gtk_tooltip_set_tip_area().
15398  *
15399  * Note that if @path is not specified and @cell is set and part of a column
15400  * containing the expander, the tooltip might not show and hide at the correct
15401  * position.  In such cases @path must be set to the current node under the
15402  * mouse cursor for this function to operate correctly.
15403  *
15404  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15405  *
15406  * Since: 2.12
15407  */
15408 void
15409 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15410                                 GtkTooltip        *tooltip,
15411                                 GtkTreePath       *path,
15412                                 GtkTreeViewColumn *column,
15413                                 GtkCellRenderer   *cell)
15414 {
15415   GdkRectangle rect;
15416
15417   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15418   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15419   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15420   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15421
15422   /* Determine x values. */
15423   if (column && cell)
15424     {
15425       GdkRectangle tmp;
15426       gint start, width;
15427
15428       /* We always pass in path here, whether it is NULL or not.
15429        * For cells in expander columns path must be specified so that
15430        * we can correctly account for the indentation.  This also means
15431        * that the tooltip is constrained vertically by the "Determine y
15432        * values" code below; this is not a real problem since cells actually
15433        * don't stretch vertically in constrast to columns.
15434        */
15435       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15436       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15437
15438       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15439                                                          tmp.x + start, 0,
15440                                                          &rect.x, NULL);
15441       rect.width = width;
15442     }
15443   else if (column)
15444     {
15445       GdkRectangle tmp;
15446
15447       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15448       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15449                                                          tmp.x, 0,
15450                                                          &rect.x, NULL);
15451       rect.width = tmp.width;
15452     }
15453   else
15454     {
15455       rect.x = 0;
15456       rect.width = GTK_WIDGET (tree_view)->allocation.width;
15457     }
15458
15459   /* Determine y values. */
15460   if (path)
15461     {
15462       GdkRectangle tmp;
15463
15464       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15465       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15466                                                          0, tmp.y,
15467                                                          NULL, &rect.y);
15468       rect.height = tmp.height;
15469     }
15470   else
15471     {
15472       rect.y = 0;
15473       rect.height = tree_view->priv->vadjustment->page_size;
15474     }
15475
15476   gtk_tooltip_set_tip_area (tooltip, &rect);
15477 }
15478
15479 /**
15480  * gtk_tree_view_get_tooltip_context:
15481  * @tree_view: a #GtkTreeView
15482  * @x: the x coordinate (relative to widget coordinates)
15483  * @y: the y coordinate (relative to widget coordinates)
15484  * @keyboard_tip: whether this is a keyboard tooltip or not
15485  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
15486  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
15487  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
15488  *
15489  * This function is supposed to be used in a #GtkWidget::query-tooltip
15490  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15491  * which are received in the signal handler, should be passed to this
15492  * function without modification.
15493  *
15494  * The return value indicates whether there is a tree view row at the given
15495  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15496  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15497  * @model, @path and @iter which have been provided will be set to point to
15498  * that row and the corresponding model.  @x and @y will always be converted
15499  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15500  *
15501  * Return value: whether or not the given tooltip context points to a row.
15502  *
15503  * Since: 2.12
15504  */
15505 gboolean
15506 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15507                                    gint          *x,
15508                                    gint          *y,
15509                                    gboolean       keyboard_tip,
15510                                    GtkTreeModel **model,
15511                                    GtkTreePath  **path,
15512                                    GtkTreeIter   *iter)
15513 {
15514   GtkTreePath *tmppath = NULL;
15515
15516   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15517   g_return_val_if_fail (x != NULL, FALSE);
15518   g_return_val_if_fail (y != NULL, FALSE);
15519
15520   if (keyboard_tip)
15521     {
15522       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15523
15524       if (!tmppath)
15525         return FALSE;
15526     }
15527   else
15528     {
15529       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15530                                                          x, y);
15531
15532       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15533                                           &tmppath, NULL, NULL, NULL))
15534         return FALSE;
15535     }
15536
15537   if (model)
15538     *model = gtk_tree_view_get_model (tree_view);
15539
15540   if (iter)
15541     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15542                              iter, tmppath);
15543
15544   if (path)
15545     *path = tmppath;
15546   else
15547     gtk_tree_path_free (tmppath);
15548
15549   return TRUE;
15550 }
15551
15552 static gboolean
15553 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15554                                     gint        x,
15555                                     gint        y,
15556                                     gboolean    keyboard_tip,
15557                                     GtkTooltip *tooltip,
15558                                     gpointer    data)
15559 {
15560   GValue value = { 0, };
15561   GValue transformed = { 0, };
15562   GtkTreeIter iter;
15563   GtkTreePath *path;
15564   GtkTreeModel *model;
15565   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15566
15567   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15568                                           &x, &y,
15569                                           keyboard_tip,
15570                                           &model, &path, &iter))
15571     return FALSE;
15572
15573   gtk_tree_model_get_value (model, &iter,
15574                             tree_view->priv->tooltip_column, &value);
15575
15576   g_value_init (&transformed, G_TYPE_STRING);
15577
15578   if (!g_value_transform (&value, &transformed))
15579     {
15580       g_value_unset (&value);
15581       gtk_tree_path_free (path);
15582
15583       return FALSE;
15584     }
15585
15586   g_value_unset (&value);
15587
15588   if (!g_value_get_string (&transformed))
15589     {
15590       g_value_unset (&transformed);
15591       gtk_tree_path_free (path);
15592
15593       return FALSE;
15594     }
15595
15596   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15597   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15598
15599   gtk_tree_path_free (path);
15600   g_value_unset (&transformed);
15601
15602   return TRUE;
15603 }
15604
15605 /**
15606  * gtk_tree_view_set_tooltip_column:
15607  * @tree_view: a #GtkTreeView
15608  * @column: an integer, which is a valid column number for @tree_view's model
15609  *
15610  * If you only plan to have simple (text-only) tooltips on full rows, you
15611  * can use this function to have #GtkTreeView handle these automatically
15612  * for you. @column should be set to the column in @tree_view's model
15613  * containing the tooltip texts, or -1 to disable this feature.
15614  *
15615  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15616  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15617  *
15618  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15619  * so &amp;, &lt;, etc have to be escaped in the text.
15620  *
15621  * Since: 2.12
15622  */
15623 void
15624 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15625                                   gint         column)
15626 {
15627   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15628
15629   if (column == tree_view->priv->tooltip_column)
15630     return;
15631
15632   if (column == -1)
15633     {
15634       g_signal_handlers_disconnect_by_func (tree_view,
15635                                             gtk_tree_view_set_tooltip_query_cb,
15636                                             NULL);
15637       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15638     }
15639   else
15640     {
15641       if (tree_view->priv->tooltip_column == -1)
15642         {
15643           g_signal_connect (tree_view, "query-tooltip",
15644                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15645           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15646         }
15647     }
15648
15649   tree_view->priv->tooltip_column = column;
15650   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15651 }
15652
15653 /**
15654  * gtk_tree_view_get_tooltip_column:
15655  * @tree_view: a #GtkTreeView
15656  *
15657  * Returns the column of @tree_view's model which is being used for
15658  * displaying tooltips on @tree_view's rows.
15659  *
15660  * Return value: the index of the tooltip column that is currently being
15661  * used, or -1 if this is disabled.
15662  *
15663  * Since: 2.12
15664  */
15665 gint
15666 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15667 {
15668   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15669
15670   return tree_view->priv->tooltip_column;
15671 }