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