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