]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeselection.c
Fix many sparse warnings.
[~andy/gtk] / gtk / gtktreeselection.c
1 /* gtktreeselection.h
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 #include <config.h>
21 #include <string.h>
22 #include "gtkalias.h"
23 #include "gtktreeselection.h"
24 #include "gtktreeprivate.h"
25 #include "gtkrbtree.h"
26 #include "gtkmarshalers.h"
27
28 static void gtk_tree_selection_init              (GtkTreeSelection      *selection);
29 static void gtk_tree_selection_class_init        (GtkTreeSelectionClass *class);
30
31 static void gtk_tree_selection_finalize          (GObject               *object);
32 static gint gtk_tree_selection_real_select_all   (GtkTreeSelection      *selection);
33 static gint gtk_tree_selection_real_unselect_all (GtkTreeSelection      *selection);
34 static gint gtk_tree_selection_real_select_node  (GtkTreeSelection      *selection,
35                                                   GtkRBTree             *tree,
36                                                   GtkRBNode             *node,
37                                                   gboolean               select);
38
39 enum
40 {
41   CHANGED,
42   LAST_SIGNAL
43 };
44
45 static GObjectClass *parent_class = NULL;
46 static guint tree_selection_signals [LAST_SIGNAL] = { 0 };
47
48 GType
49 gtk_tree_selection_get_type (void)
50 {
51   static GType selection_type = 0;
52
53   if (!selection_type)
54     {
55       static const GTypeInfo selection_info =
56       {
57         sizeof (GtkTreeSelectionClass),
58         NULL,           /* base_init */
59         NULL,           /* base_finalize */
60         (GClassInitFunc) gtk_tree_selection_class_init,
61         NULL,           /* class_finalize */
62         NULL,           /* class_data */
63         sizeof (GtkTreeSelection),
64         0,              /* n_preallocs */
65         (GInstanceInitFunc) gtk_tree_selection_init
66       };
67
68       selection_type =
69         g_type_register_static (G_TYPE_OBJECT, "GtkTreeSelection",
70                                 &selection_info, 0);
71     }
72
73   return selection_type;
74 }
75
76 static void
77 gtk_tree_selection_class_init (GtkTreeSelectionClass *class)
78 {
79   GObjectClass *object_class;
80
81   object_class = (GObjectClass*) class;
82   parent_class = g_type_class_peek_parent (class);
83
84   object_class->finalize = gtk_tree_selection_finalize;
85   class->changed = NULL;
86
87   tree_selection_signals[CHANGED] =
88     g_signal_new ("changed",
89                   G_OBJECT_CLASS_TYPE (object_class),
90                   G_SIGNAL_RUN_FIRST,
91                   G_STRUCT_OFFSET (GtkTreeSelectionClass, changed),
92                   NULL, NULL,
93                   _gtk_marshal_VOID__VOID,
94                   G_TYPE_NONE, 0);
95 }
96
97 static void
98 gtk_tree_selection_init (GtkTreeSelection *selection)
99 {
100   selection->type = GTK_SELECTION_SINGLE;
101 }
102
103 static void
104 gtk_tree_selection_finalize (GObject *object)
105 {
106   GtkTreeSelection *selection = GTK_TREE_SELECTION (object);
107
108   if (selection->destroy)
109     {
110       GtkDestroyNotify d = selection->destroy;
111
112       selection->destroy = NULL;
113       d (selection->user_data);
114     }
115
116   /* chain parent_class' handler */
117   G_OBJECT_CLASS (parent_class)->finalize (object);
118 }
119
120 /**
121  * _gtk_tree_selection_new:
122  *
123  * Creates a new #GtkTreeSelection object.  This function should not be invoked,
124  * as each #GtkTreeView will create its own #GtkTreeSelection.
125  *
126  * Return value: A newly created #GtkTreeSelection object.
127  **/
128 GtkTreeSelection*
129 _gtk_tree_selection_new (void)
130 {
131   GtkTreeSelection *selection;
132
133   selection = g_object_new (GTK_TYPE_TREE_SELECTION, NULL);
134
135   return selection;
136 }
137
138 /**
139  * _gtk_tree_selection_new_with_tree_view:
140  * @tree_view: The #GtkTreeView.
141  *
142  * Creates a new #GtkTreeSelection object.  This function should not be invoked,
143  * as each #GtkTreeView will create its own #GtkTreeSelection.
144  *
145  * Return value: A newly created #GtkTreeSelection object.
146  **/
147 GtkTreeSelection*
148 _gtk_tree_selection_new_with_tree_view (GtkTreeView *tree_view)
149 {
150   GtkTreeSelection *selection;
151
152   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
153
154   selection = _gtk_tree_selection_new ();
155   _gtk_tree_selection_set_tree_view (selection, tree_view);
156
157   return selection;
158 }
159
160 /**
161  * _gtk_tree_selection_set_tree_view:
162  * @selection: A #GtkTreeSelection.
163  * @tree_view: The #GtkTreeView.
164  *
165  * Sets the #GtkTreeView of @selection.  This function should not be invoked, as
166  * it is used internally by #GtkTreeView.
167  **/
168 void
169 _gtk_tree_selection_set_tree_view (GtkTreeSelection *selection,
170                                    GtkTreeView      *tree_view)
171 {
172   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
173   if (tree_view != NULL)
174     g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
175
176   selection->tree_view = tree_view;
177 }
178
179 /**
180  * gtk_tree_selection_set_mode:
181  * @selection: A #GtkTreeSelection.
182  * @type: The selection mode
183  *
184  * Sets the selection mode of the @selection.  If the previous type was
185  * #GTK_SELECTION_MULTIPLE, then the anchor is kept selected, if it was
186  * previously selected.
187  **/
188 void
189 gtk_tree_selection_set_mode (GtkTreeSelection *selection,
190                              GtkSelectionMode  type)
191 {
192   GtkTreeSelectionFunc tmp_func;
193   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
194
195   if (selection->type == type)
196     return;
197
198   
199   if (type == GTK_SELECTION_NONE)
200     {
201       /* We do this so that we unconditionally unset all rows
202        */
203       tmp_func = selection->user_func;
204       selection->user_func = NULL;
205       gtk_tree_selection_unselect_all (selection);
206       selection->user_func = tmp_func;
207
208       gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
209       selection->tree_view->priv->anchor = NULL;
210     }
211   else if (type == GTK_SELECTION_SINGLE ||
212            type == GTK_SELECTION_BROWSE)
213     {
214       GtkRBTree *tree = NULL;
215       GtkRBNode *node = NULL;
216       gint selected = FALSE;
217       GtkTreePath *anchor_path = NULL;
218
219       if (selection->tree_view->priv->anchor)
220         {
221           anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
222
223           if (anchor_path)
224             {
225               _gtk_tree_view_find_node (selection->tree_view,
226                                         anchor_path,
227                                         &tree,
228                                         &node);
229
230               if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
231                 selected = TRUE;
232             }
233         }
234
235       /* We do this so that we unconditionally unset all rows
236        */
237       tmp_func = selection->user_func;
238       selection->user_func = NULL;
239       gtk_tree_selection_unselect_all (selection);
240       selection->user_func = tmp_func;
241
242       if (node && selected)
243         _gtk_tree_selection_internal_select_node (selection,
244                                                   node,
245                                                   tree,
246                                                   anchor_path,
247                                                   0,
248                                                   FALSE);
249       if (anchor_path)
250         gtk_tree_path_free (anchor_path);
251     }
252
253   selection->type = type;
254 }
255
256 /**
257  * gtk_tree_selection_get_mode:
258  * @selection: a #GtkTreeSelection
259  *
260  * Gets the selection mode for @selection. See
261  * gtk_tree_selection_set_mode().
262  *
263  * Return value: the current selection mode
264  **/
265 GtkSelectionMode
266 gtk_tree_selection_get_mode (GtkTreeSelection *selection)
267 {
268   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), GTK_SELECTION_SINGLE);
269
270   return selection->type;
271 }
272
273 /**
274  * gtk_tree_selection_set_select_function:
275  * @selection: A #GtkTreeSelection.
276  * @func: The selection function.
277  * @data: The selection function's data.
278  * @destroy: The destroy function for user data.  May be NULL.
279  *
280  * Sets the selection function.  If set, this function is called before any node
281  * is selected or unselected, giving some control over which nodes are selected.
282  * The select function should return %TRUE if the state of the node may be toggled,
283  * and %FALSE if the state of the node should be left unchanged.
284  **/
285 void
286 gtk_tree_selection_set_select_function (GtkTreeSelection     *selection,
287                                         GtkTreeSelectionFunc  func,
288                                         gpointer              data,
289                                         GtkDestroyNotify      destroy)
290 {
291   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
292   g_return_if_fail (func != NULL);
293
294   if (selection->destroy)
295     {
296       GtkDestroyNotify d = selection->destroy;
297
298       selection->destroy = NULL;
299       d (selection->user_data);
300     }
301
302   selection->user_func = func;
303   selection->user_data = data;
304   selection->destroy = destroy;
305 }
306
307 /**
308  * gtk_tree_selection_get_user_data:
309  * @selection: A #GtkTreeSelection.
310  *
311  * Returns the user data for the selection function.
312  *
313  * Return value: The user data.
314  **/
315 gpointer
316 gtk_tree_selection_get_user_data (GtkTreeSelection *selection)
317 {
318   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
319
320   return selection->user_data;
321 }
322
323 /**
324  * gtk_tree_selection_get_tree_view:
325  * @selection: A #GtkTreeSelection
326  * 
327  * Returns the tree view associated with @selection.
328  * 
329  * Return value: A #GtkTreeView
330  **/
331 GtkTreeView *
332 gtk_tree_selection_get_tree_view (GtkTreeSelection *selection)
333 {
334   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
335
336   return selection->tree_view;
337 }
338
339 /**
340  * gtk_tree_selection_get_selected:
341  * @selection: A #GtkTreeSelection.
342  * @model: A pointer to set to the #GtkTreeModel, or NULL.
343  * @iter: The #GtkTreeIter, or NULL.
344  *
345  * Sets @iter to the currently selected node if @selection is set to
346  * #GTK_SELECTION_SINGLE or #GTK_SELECTION_BROWSE.  @iter may be NULL if you
347  * just want to test if @selection has any selected nodes.  @model is filled
348  * with the current model as a convenience.  This function will not work if you
349  * use @selection is #GTK_SELECTION_MULTIPLE.
350  *
351  * Return value: TRUE, if there is a selected node.
352  **/
353 gboolean
354 gtk_tree_selection_get_selected (GtkTreeSelection  *selection,
355                                  GtkTreeModel     **model,
356                                  GtkTreeIter       *iter)
357 {
358   GtkRBTree *tree;
359   GtkRBNode *node;
360   GtkTreePath *anchor_path;
361   gboolean retval;
362   gboolean found_node;
363
364   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
365   g_return_val_if_fail (selection->type != GTK_SELECTION_MULTIPLE, FALSE);
366   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
367
368   /* Clear the iter */
369   if (iter)
370     memset (iter, 0, sizeof (GtkTreeIter));
371
372   if (model)
373     *model = selection->tree_view->priv->model;
374
375   if (selection->tree_view->priv->anchor == NULL)
376     return FALSE;
377
378   anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
379
380   if (anchor_path == NULL)
381     return FALSE;
382
383   retval = FALSE;
384
385   found_node = !_gtk_tree_view_find_node (selection->tree_view,
386                                           anchor_path,
387                                           &tree,
388                                           &node);
389
390   if (found_node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
391     {
392       /* we only want to return the anchor if it exists in the rbtree and
393        * is selected.
394        */
395       if (iter == NULL)
396         retval = TRUE;
397       else
398         retval = gtk_tree_model_get_iter (selection->tree_view->priv->model,
399                                           iter,
400                                           anchor_path);
401     }
402   else
403     {
404       /* We don't want to return the anchor if it isn't actually selected.
405        */
406       retval = FALSE;
407     }
408
409   gtk_tree_path_free (anchor_path);
410
411   return retval;
412 }
413
414 /**
415  * gtk_tree_selection_get_selected_rows:
416  * @selection: A #GtkTreeSelection.
417  * @model: A pointer to set to the #GtkTreeModel, or NULL.
418  *
419  * Creates a list of path of all selected rows. Additionally, if you are
420  * planning on modifying the model after calling this function, you may
421  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
422  * To do this, you can use gtk_tree_row_reference_new().
423  *
424  * To free the return value, use:
425  * <informalexample><programlisting>
426  * g_list_foreach (list, gtk_tree_path_free, NULL);
427  * g_list_free (list);
428  * </programlisting></informalexample>
429  *
430  * Return value: A #GList containing a #GtkTreePath for each selected row.
431  *
432  * Since: 2.2
433  **/
434 GList *
435 gtk_tree_selection_get_selected_rows (GtkTreeSelection   *selection,
436                                       GtkTreeModel      **model)
437 {
438   GList *list = NULL;
439   GtkRBTree *tree = NULL;
440   GtkRBNode *node = NULL;
441   GtkTreePath *path;
442
443   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
444   g_return_val_if_fail (selection->tree_view != NULL, NULL);
445
446   if (selection->tree_view->priv->tree == NULL ||
447       selection->tree_view->priv->tree->root == NULL)
448     return NULL;
449
450   if (model)
451     *model = selection->tree_view->priv->model;
452
453   if (selection->type == GTK_SELECTION_NONE)
454     return NULL;
455   else if (selection->type != GTK_SELECTION_MULTIPLE)
456     {
457       GtkTreeIter iter;
458
459       if (gtk_tree_selection_get_selected (selection, NULL, &iter))
460         {
461           GtkTreePath *path;
462
463           path = gtk_tree_model_get_path (selection->tree_view->priv->model, &iter);
464           list = g_list_append (list, path);
465
466           return list;
467         }
468
469       return NULL;
470     }
471
472   tree = selection->tree_view->priv->tree;
473   node = selection->tree_view->priv->tree->root;
474
475   while (node->left != tree->nil)
476     node = node->left;
477   path = gtk_tree_path_new_first ();
478
479   do
480     {
481       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
482         list = g_list_prepend (list, gtk_tree_path_copy (path));
483
484       if (node->children)
485         {
486           tree = node->children;
487           node = tree->root;
488
489           while (node->left != tree->nil)
490             node = node->left;
491
492           gtk_tree_path_append_index (path, 0);
493         }
494       else
495         {
496           gboolean done = FALSE;
497
498           do
499             {
500               node = _gtk_rbtree_next (tree, node);
501               if (node != NULL)
502                 {
503                   done = TRUE;
504                   gtk_tree_path_next (path);
505                 }
506               else
507                 {
508                   node = tree->parent_node;
509                   tree = tree->parent_tree;
510
511                   if (!tree)
512                     {
513                       gtk_tree_path_free (path);
514
515                       goto done; 
516                     }
517
518                   gtk_tree_path_up (path);
519                 }
520             }
521           while (!done);
522         }
523     }
524   while (TRUE);
525
526   gtk_tree_path_free (path);
527
528  done:
529   return g_list_reverse (list);
530 }
531
532 static void
533 gtk_tree_selection_count_selected_rows_helper (GtkRBTree *tree,
534                                                GtkRBNode *node,
535                                                gpointer   data)
536 {
537   gint *count = (gint *)data;
538
539   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
540     (*count)++;
541
542   if (node->children)
543     _gtk_rbtree_traverse (node->children, node->children->root,
544                           G_PRE_ORDER,
545                           gtk_tree_selection_count_selected_rows_helper, data);
546 }
547
548 /**
549  * gtk_tree_selection_count_selected_rows:
550  * @selection: A #GtkTreeSelection.
551  *
552  * Returns the number of rows that have been selected in @tree.
553  *
554  * Return value: The number of rows selected.
555  * 
556  * Since: 2.2
557  **/
558 gint
559 gtk_tree_selection_count_selected_rows (GtkTreeSelection *selection)
560 {
561   gint count = 0;
562   GtkRBTree *tree;
563   GtkRBNode *node;
564
565   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), 0);
566   g_return_val_if_fail (selection->tree_view != NULL, 0);
567
568   if (selection->tree_view->priv->tree == NULL ||
569       selection->tree_view->priv->tree->root == NULL)
570     return 0;
571
572   if (selection->type == GTK_SELECTION_SINGLE ||
573       selection->type == GTK_SELECTION_BROWSE)
574     {
575       if (gtk_tree_selection_get_selected (selection, NULL, NULL))
576         return 1;
577       else
578         return 0;
579     }
580
581   tree = selection->tree_view->priv->tree;
582   node = selection->tree_view->priv->tree->root;
583
584   _gtk_rbtree_traverse (selection->tree_view->priv->tree,
585                         selection->tree_view->priv->tree->root,
586                         G_PRE_ORDER,
587                         gtk_tree_selection_count_selected_rows_helper,
588                         &count);
589
590   return count;
591 }
592
593 /* gtk_tree_selection_selected_foreach helper */
594 static void
595 model_changed (gpointer data)
596 {
597   gboolean *stop = (gboolean *)data;
598
599   *stop = TRUE;
600 }
601
602 /**
603  * gtk_tree_selection_selected_foreach:
604  * @selection: A #GtkTreeSelection.
605  * @func: The function to call for each selected node.
606  * @data: user data to pass to the function.
607  *
608  * Calls a function for each selected node. Note that you cannot modify
609  * the tree or selection from within this function. As a result,
610  * gtk_tree_selection_get_selected_rows() might be more useful.
611  **/
612 void
613 gtk_tree_selection_selected_foreach (GtkTreeSelection            *selection,
614                                      GtkTreeSelectionForeachFunc  func,
615                                      gpointer                     data)
616 {
617   GtkTreePath *path;
618   GtkRBTree *tree;
619   GtkRBNode *node;
620   GtkTreeIter iter;
621
622   guint inserted_id, deleted_id, reordered_id;
623   gboolean stop = FALSE, has_next = TRUE, has_parent = TRUE;
624
625   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
626   g_return_if_fail (selection->tree_view != NULL);
627
628   if (func == NULL ||
629       selection->tree_view->priv->tree == NULL ||
630       selection->tree_view->priv->tree->root == NULL)
631     return;
632
633   if (selection->type == GTK_SELECTION_SINGLE ||
634       selection->type == GTK_SELECTION_BROWSE)
635     {
636       if (gtk_tree_row_reference_valid (selection->tree_view->priv->anchor))
637         {
638           path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
639           gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path);
640           (* func) (selection->tree_view->priv->model, path, &iter, data);
641           gtk_tree_path_free (path);
642         }
643       return;
644     }
645
646   tree = selection->tree_view->priv->tree;
647   node = selection->tree_view->priv->tree->root;
648   
649   while (node->left != tree->nil)
650     node = node->left;
651
652   /* connect to signals to monitor changes in treemodel */
653   inserted_id = g_signal_connect_swapped (selection->tree_view->priv->model,
654                                           "row_inserted",
655                                           G_CALLBACK (model_changed),
656                                           &stop);
657   deleted_id = g_signal_connect_swapped (selection->tree_view->priv->model,
658                                          "row_deleted",
659                                          G_CALLBACK (model_changed),
660                                          &stop);
661   reordered_id = g_signal_connect_swapped (selection->tree_view->priv->model,
662                                            "rows_reordered",
663                                            G_CALLBACK (model_changed),
664                                            &stop);
665
666   /* find the node internally */
667   path = gtk_tree_path_new_first ();
668   gtk_tree_model_get_iter (selection->tree_view->priv->model,
669                            &iter, path);
670
671   do
672     {
673       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
674         (* func) (selection->tree_view->priv->model, path, &iter, data);
675
676       if (stop)
677         goto out;
678
679       if (node->children)
680         {
681           gboolean has_child;
682           GtkTreeIter tmp;
683
684           tree = node->children;
685           node = tree->root;
686           while (node->left != tree->nil)
687             node = node->left;
688           tmp = iter;
689           has_child = gtk_tree_model_iter_children (selection->tree_view->priv->model, &iter, &tmp);
690           gtk_tree_path_append_index (path, 0);
691
692           /* we do the sanity check at the bottom of this function */
693           if (!has_child)
694             goto out;
695         }
696       else
697         {
698           gboolean done = FALSE;
699           do
700             {
701               node = _gtk_rbtree_next (tree, node);
702               if (node != NULL)
703                 {
704                   gboolean has_next;
705
706                   has_next = gtk_tree_model_iter_next (selection->tree_view->priv->model, &iter);
707                   done = TRUE;
708                   gtk_tree_path_next (path);
709
710                   /* we do the sanity check at the bottom of this function */
711                   if (!has_next)
712                     goto out;
713                 }
714               else
715                 {
716                   gboolean has_parent;
717                   GtkTreeIter tmp_iter = iter;
718
719                   node = tree->parent_node;
720                   tree = tree->parent_tree;
721                   if (tree == NULL)
722                     {
723                       /* we've run out of tree */
724                       /* We're done with this function */
725
726                       goto out;
727                     }
728
729                   has_parent = gtk_tree_model_iter_parent (selection->tree_view->priv->model, &iter, &tmp_iter);
730                   gtk_tree_path_up (path);
731
732                   /* we do the sanity check at the bottom of this function */
733                   if (!has_parent)
734                     goto out;
735                 }
736             }
737           while (!done);
738         }
739     }
740   while (TRUE);
741
742 out:
743   if (path)
744     gtk_tree_path_free (path);
745
746   g_signal_handler_disconnect (selection->tree_view->priv->model,
747                                inserted_id);
748   g_signal_handler_disconnect (selection->tree_view->priv->model,
749                                deleted_id);
750   g_signal_handler_disconnect (selection->tree_view->priv->model,
751                                reordered_id);
752
753   /* check if we have to spew a scary message */
754   if (!has_next)
755     TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
756   if (!has_parent)
757     TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
758   if (stop)
759     g_warning
760       ("The model has been modified from within gtk_tree_selection_selected_foreach.\n"
761        "This function is for observing the selections of the tree only.  If\n"
762        "you are trying to get all selected items from the tree, try using\n"
763        "gtk_tree_selection_get_selected_rows instead.\n");
764 }
765
766 /**
767  * gtk_tree_selection_select_path:
768  * @selection: A #GtkTreeSelection.
769  * @path: The #GtkTreePath to be selected.
770  *
771  * Select the row at @path.
772  **/
773 void
774 gtk_tree_selection_select_path (GtkTreeSelection *selection,
775                                 GtkTreePath      *path)
776 {
777   GtkRBNode *node;
778   GtkRBTree *tree;
779   gboolean ret;
780   GtkTreeSelectMode mode = 0;
781
782   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
783   g_return_if_fail (selection->tree_view != NULL);
784   g_return_if_fail (path != NULL);
785
786   ret = _gtk_tree_view_find_node (selection->tree_view,
787                                   path,
788                                   &tree,
789                                   &node);
790
791   if (node == NULL || GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
792       ret == TRUE)
793     return;
794
795   if (selection->type == GTK_SELECTION_MULTIPLE)
796     mode = GTK_TREE_SELECT_MODE_TOGGLE;
797
798   _gtk_tree_selection_internal_select_node (selection,
799                                             node,
800                                             tree,
801                                             path,
802                                             mode,
803                                             FALSE);
804 }
805
806 /**
807  * gtk_tree_selection_unselect_path:
808  * @selection: A #GtkTreeSelection.
809  * @path: The #GtkTreePath to be unselected.
810  *
811  * Unselects the row at @path.
812  **/
813 void
814 gtk_tree_selection_unselect_path (GtkTreeSelection *selection,
815                                   GtkTreePath      *path)
816 {
817   GtkRBNode *node;
818   GtkRBTree *tree;
819   gboolean ret;
820
821   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
822   g_return_if_fail (selection->tree_view != NULL);
823   g_return_if_fail (path != NULL);
824
825   ret = _gtk_tree_view_find_node (selection->tree_view,
826                                   path,
827                                   &tree,
828                                   &node);
829
830   if (node == NULL || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
831       ret == TRUE)
832     return;
833
834   _gtk_tree_selection_internal_select_node (selection,
835                                             node,
836                                             tree,
837                                             path,
838                                             GTK_TREE_SELECT_MODE_TOGGLE,
839                                             TRUE);
840 }
841
842 /**
843  * gtk_tree_selection_select_iter:
844  * @selection: A #GtkTreeSelection.
845  * @iter: The #GtkTreeIter to be selected.
846  *
847  * Selects the specified iterator.
848  **/
849 void
850 gtk_tree_selection_select_iter (GtkTreeSelection *selection,
851                                 GtkTreeIter      *iter)
852 {
853   GtkTreePath *path;
854
855   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
856   g_return_if_fail (selection->tree_view != NULL);
857   g_return_if_fail (selection->tree_view->priv->model != NULL);
858   g_return_if_fail (iter != NULL);
859
860   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
861                                   iter);
862
863   if (path == NULL)
864     return;
865
866   gtk_tree_selection_select_path (selection, path);
867   gtk_tree_path_free (path);
868 }
869
870
871 /**
872  * gtk_tree_selection_unselect_iter:
873  * @selection: A #GtkTreeSelection.
874  * @iter: The #GtkTreeIter to be unselected.
875  *
876  * Unselects the specified iterator.
877  **/
878 void
879 gtk_tree_selection_unselect_iter (GtkTreeSelection *selection,
880                                   GtkTreeIter      *iter)
881 {
882   GtkTreePath *path;
883
884   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
885   g_return_if_fail (selection->tree_view != NULL);
886   g_return_if_fail (selection->tree_view->priv->model != NULL);
887   g_return_if_fail (iter != NULL);
888
889   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
890                                   iter);
891
892   if (path == NULL)
893     return;
894
895   gtk_tree_selection_unselect_path (selection, path);
896   gtk_tree_path_free (path);
897 }
898
899 /**
900  * gtk_tree_selection_path_is_selected:
901  * @selection: A #GtkTreeSelection.
902  * @path: A #GtkTreePath to check selection on.
903  * 
904  * Returns %TRUE if the row pointed to by @path is currently selected.  If @path
905  * does not point to a valid location, %FALSE is returned
906  * 
907  * Return value: %TRUE if @path is selected.
908  **/
909 gboolean
910 gtk_tree_selection_path_is_selected (GtkTreeSelection *selection,
911                                      GtkTreePath      *path)
912 {
913   GtkRBNode *node;
914   GtkRBTree *tree;
915   gboolean ret;
916
917   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
918   g_return_val_if_fail (path != NULL, FALSE);
919   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
920
921   if (selection->tree_view->priv->model == NULL)
922     return FALSE;
923
924   ret = _gtk_tree_view_find_node (selection->tree_view,
925                                   path,
926                                   &tree,
927                                   &node);
928
929   if ((node == NULL) || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
930       ret == TRUE)
931     return FALSE;
932
933   return TRUE;
934 }
935
936 /**
937  * gtk_tree_selection_iter_is_selected:
938  * @selection: A #GtkTreeSelection
939  * @iter: A valid #GtkTreeIter
940  * 
941  * Returns %TRUE if the row at @iter is currently selected.
942  * 
943  * Return value: %TRUE, if @iter is selected
944  **/
945 gboolean
946 gtk_tree_selection_iter_is_selected (GtkTreeSelection *selection,
947                                      GtkTreeIter      *iter)
948 {
949   GtkTreePath *path;
950   gboolean retval;
951
952   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
953   g_return_val_if_fail (iter != NULL, FALSE);
954   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
955   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
956
957   path = gtk_tree_model_get_path (selection->tree_view->priv->model, iter);
958   if (path == NULL)
959     return FALSE;
960
961   retval = gtk_tree_selection_path_is_selected (selection, path);
962   gtk_tree_path_free (path);
963
964   return retval;
965 }
966
967
968 /* Wish I was in python, right now... */
969 struct _TempTuple {
970   GtkTreeSelection *selection;
971   gint dirty;
972 };
973
974 static void
975 select_all_helper (GtkRBTree  *tree,
976                    GtkRBNode  *node,
977                    gpointer    data)
978 {
979   struct _TempTuple *tuple = data;
980
981   if (node->children)
982     _gtk_rbtree_traverse (node->children,
983                           node->children->root,
984                           G_PRE_ORDER,
985                           select_all_helper,
986                           data);
987   if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
988     {
989       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, TRUE) || tuple->dirty;
990     }
991 }
992
993
994 /* We have a real_{un,}select_all function that doesn't emit the signal, so we
995  * can use it in other places without fear of the signal being emitted.
996  */
997 static gint
998 gtk_tree_selection_real_select_all (GtkTreeSelection *selection)
999 {
1000   struct _TempTuple *tuple;
1001
1002   if (selection->tree_view->priv->tree == NULL)
1003     return FALSE;
1004
1005   /* Mark all nodes selected */
1006   tuple = g_new (struct _TempTuple, 1);
1007   tuple->selection = selection;
1008   tuple->dirty = FALSE;
1009
1010   _gtk_rbtree_traverse (selection->tree_view->priv->tree,
1011                         selection->tree_view->priv->tree->root,
1012                         G_PRE_ORDER,
1013                         select_all_helper,
1014                         tuple);
1015   if (tuple->dirty)
1016     {
1017       g_free (tuple);
1018       return TRUE;
1019     }
1020   g_free (tuple);
1021   return FALSE;
1022 }
1023
1024 /**
1025  * gtk_tree_selection_select_all:
1026  * @selection: A #GtkTreeSelection.
1027  *
1028  * Selects all the nodes. @selection must be set to #GTK_SELECTION_MULTIPLE
1029  * mode.
1030  **/
1031 void
1032 gtk_tree_selection_select_all (GtkTreeSelection *selection)
1033 {
1034   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1035   g_return_if_fail (selection->tree_view != NULL);
1036
1037   if (selection->tree_view->priv->tree == NULL || selection->tree_view->priv->model == NULL)
1038     return;
1039
1040   g_return_if_fail (selection->type == GTK_SELECTION_MULTIPLE);
1041
1042   if (gtk_tree_selection_real_select_all (selection))
1043     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1044 }
1045
1046 static void
1047 unselect_all_helper (GtkRBTree  *tree,
1048                      GtkRBNode  *node,
1049                      gpointer    data)
1050 {
1051   struct _TempTuple *tuple = data;
1052
1053   if (node->children)
1054     _gtk_rbtree_traverse (node->children,
1055                           node->children->root,
1056                           G_PRE_ORDER,
1057                           unselect_all_helper,
1058                           data);
1059   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1060     {
1061       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, FALSE) || tuple->dirty;
1062     }
1063 }
1064
1065 static gint
1066 gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection)
1067 {
1068   struct _TempTuple *tuple;
1069
1070   if (selection->type == GTK_SELECTION_SINGLE ||
1071       selection->type == GTK_SELECTION_BROWSE)
1072     {
1073       GtkRBTree *tree = NULL;
1074       GtkRBNode *node = NULL;
1075       GtkTreePath *anchor_path;
1076
1077       if (selection->tree_view->priv->anchor == NULL)
1078         return FALSE;
1079
1080       anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
1081
1082       if (anchor_path == NULL)
1083         return FALSE;
1084
1085       _gtk_tree_view_find_node (selection->tree_view,
1086                                 anchor_path,
1087                                 &tree,
1088                                 &node);
1089
1090       gtk_tree_path_free (anchor_path);
1091
1092       if (tree == NULL)
1093         return FALSE;
1094
1095       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1096         {
1097           if (gtk_tree_selection_real_select_node (selection, tree, node, FALSE))
1098             {
1099               gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1100               selection->tree_view->priv->anchor = NULL;
1101               return TRUE;
1102             }
1103         }
1104       return FALSE;
1105     }
1106   else
1107     {
1108       tuple = g_new (struct _TempTuple, 1);
1109       tuple->selection = selection;
1110       tuple->dirty = FALSE;
1111
1112       _gtk_rbtree_traverse (selection->tree_view->priv->tree,
1113                             selection->tree_view->priv->tree->root,
1114                             G_PRE_ORDER,
1115                             unselect_all_helper,
1116                             tuple);
1117
1118       if (tuple->dirty)
1119         {
1120           g_free (tuple);
1121           return TRUE;
1122         }
1123       g_free (tuple);
1124       return FALSE;
1125     }
1126 }
1127
1128 /**
1129  * gtk_tree_selection_unselect_all:
1130  * @selection: A #GtkTreeSelection.
1131  *
1132  * Unselects all the nodes.
1133  **/
1134 void
1135 gtk_tree_selection_unselect_all (GtkTreeSelection *selection)
1136 {
1137   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1138   g_return_if_fail (selection->tree_view != NULL);
1139
1140   if (selection->tree_view->priv->tree == NULL || selection->tree_view->priv->model == NULL)
1141     return;
1142   
1143   if (gtk_tree_selection_real_unselect_all (selection))
1144     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1145 }
1146
1147 enum
1148 {
1149   RANGE_SELECT,
1150   RANGE_UNSELECT
1151 };
1152
1153 static gint
1154 gtk_tree_selection_real_modify_range (GtkTreeSelection *selection,
1155                                       gint              mode,
1156                                       GtkTreePath      *start_path,
1157                                       GtkTreePath      *end_path)
1158 {
1159   GtkRBNode *start_node, *end_node;
1160   GtkRBTree *start_tree, *end_tree;
1161   GtkTreePath *anchor_path = NULL;
1162   gboolean dirty = FALSE;
1163
1164   switch (gtk_tree_path_compare (start_path, end_path))
1165     {
1166     case 1:
1167       _gtk_tree_view_find_node (selection->tree_view,
1168                                 end_path,
1169                                 &start_tree,
1170                                 &start_node);
1171       _gtk_tree_view_find_node (selection->tree_view,
1172                                 start_path,
1173                                 &end_tree,
1174                                 &end_node);
1175       anchor_path = start_path;
1176       break;
1177     case 0:
1178       _gtk_tree_view_find_node (selection->tree_view,
1179                                 start_path,
1180                                 &start_tree,
1181                                 &start_node);
1182       end_tree = start_tree;
1183       end_node = start_node;
1184       anchor_path = start_path;
1185       break;
1186     case -1:
1187       _gtk_tree_view_find_node (selection->tree_view,
1188                                 start_path,
1189                                 &start_tree,
1190                                 &start_node);
1191       _gtk_tree_view_find_node (selection->tree_view,
1192                                 end_path,
1193                                 &end_tree,
1194                                 &end_node);
1195       anchor_path = start_path;
1196       break;
1197     }
1198
1199   g_return_val_if_fail (start_node != NULL, FALSE);
1200   g_return_val_if_fail (end_node != NULL, FALSE);
1201
1202   if (anchor_path)
1203     {
1204       if (selection->tree_view->priv->anchor)
1205         gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1206
1207       selection->tree_view->priv->anchor =
1208         gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view),
1209                                           selection->tree_view->priv->model,
1210                                           anchor_path);
1211     }
1212
1213   do
1214     {
1215       dirty |= gtk_tree_selection_real_select_node (selection, start_tree, start_node, (mode == RANGE_SELECT)?TRUE:FALSE);
1216
1217       if (start_node == end_node)
1218         break;
1219
1220       if (start_node->children)
1221         {
1222           start_tree = start_node->children;
1223           start_node = start_tree->root;
1224           while (start_node->left != start_tree->nil)
1225             start_node = start_node->left;
1226         }
1227       else
1228         {
1229           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
1230           if (start_tree == NULL)
1231             {
1232               /* we just ran out of tree.  That means someone passed in bogus values.
1233                */
1234               return dirty;
1235             }
1236         }
1237     }
1238   while (TRUE);
1239
1240   return dirty;
1241 }
1242
1243 /**
1244  * gtk_tree_selection_select_range:
1245  * @selection: A #GtkTreeSelection.
1246  * @start_path: The initial node of the range.
1247  * @end_path: The final node of the range.
1248  *
1249  * Selects a range of nodes, determined by @start_path and @end_path inclusive.
1250  * @selection must be set to #GTK_SELECTION_MULTIPLE mode. 
1251  **/
1252 void
1253 gtk_tree_selection_select_range (GtkTreeSelection *selection,
1254                                  GtkTreePath      *start_path,
1255                                  GtkTreePath      *end_path)
1256 {
1257   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1258   g_return_if_fail (selection->tree_view != NULL);
1259   g_return_if_fail (selection->type == GTK_SELECTION_MULTIPLE);
1260   g_return_if_fail (selection->tree_view->priv->model != NULL);
1261
1262   if (gtk_tree_selection_real_modify_range (selection, RANGE_SELECT, start_path, end_path))
1263     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1264 }
1265
1266 /**
1267  * gtk_tree_selection_unselect_range:
1268  * @selection: A #GtkTreeSelection.
1269  * @start_path: The initial node of the range.
1270  * @end_path: The initial node of the range.
1271  *
1272  * Unselects a range of nodes, determined by @start_path and @end_path
1273  * inclusive.
1274  *
1275  * Since: 2.2
1276  **/
1277 void
1278 gtk_tree_selection_unselect_range (GtkTreeSelection *selection,
1279                                    GtkTreePath      *start_path,
1280                                    GtkTreePath      *end_path)
1281 {
1282   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1283   g_return_if_fail (selection->tree_view != NULL);
1284   g_return_if_fail (selection->tree_view->priv->model != NULL);
1285
1286   if (gtk_tree_selection_real_modify_range (selection, RANGE_UNSELECT, start_path, end_path))
1287     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1288 }
1289
1290 static gboolean
1291 tree_column_is_sensitive (GtkTreeViewColumn *column,
1292                           GtkTreeModel      *model,
1293                           GtkTreeIter       *iter)
1294 {
1295   GList *cells, *list;
1296   gboolean sensitive;
1297   gboolean visible;
1298
1299   gtk_tree_view_column_cell_set_cell_data (column, model,
1300                                            iter, FALSE, FALSE);
1301
1302   cells = gtk_tree_view_column_get_cell_renderers (column);
1303
1304   list = cells;
1305   while (list)
1306     {
1307       g_object_get (G_OBJECT (list->data), 
1308                     "sensitive", &sensitive, 
1309                     "visible", &visible,
1310                     NULL);
1311       
1312       if (visible && sensitive)
1313         break;
1314
1315       list = list->next;
1316     }
1317   g_list_free (cells);
1318
1319   return sensitive;
1320 }
1321
1322 static gboolean
1323 row_is_selectable (GtkTreeSelection *selection,
1324                    GtkRBNode        *node,
1325                    GtkTreePath      *path)
1326 {
1327   GList *list;
1328   GtkTreeIter iter;
1329   gboolean sensitive = FALSE;
1330
1331   if (!gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path))
1332     sensitive = TRUE;
1333
1334   if (!sensitive && selection->tree_view->priv->row_separator_func)
1335     {
1336       /* never allow separators to be selected */
1337       if ((* selection->tree_view->priv->row_separator_func) (selection->tree_view->priv->model,
1338                                                               &iter,
1339                                                               selection->tree_view->priv->row_separator_data))
1340         return FALSE;
1341     }
1342
1343   for (list = selection->tree_view->priv->columns; list && !sensitive; list = list->next)
1344     {
1345       GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
1346
1347       if (!column->visible)
1348         continue;
1349
1350       sensitive = tree_column_is_sensitive (column, selection->tree_view->priv->model, &iter);
1351     }
1352
1353   if (!sensitive)
1354     return FALSE;
1355
1356   if (selection->user_func)
1357     return (*selection->user_func) (selection, selection->tree_view->priv->model, path,
1358                                     GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
1359                                     selection->user_data);
1360   else
1361     return TRUE;
1362 }
1363
1364
1365 /* Called internally by gtktreeview.c It handles actually selecting the tree.
1366  */
1367
1368 /*
1369  * docs about the 'override_browse_mode', we set this flag when we want to
1370  * unset select the node and override the select browse mode behaviour (that is
1371  * 'one node should *always* be selected').
1372  */
1373 void
1374 _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
1375                                           GtkRBNode        *node,
1376                                           GtkRBTree        *tree,
1377                                           GtkTreePath      *path,
1378                                           GtkTreeSelectMode mode,
1379                                           gboolean          override_browse_mode)
1380 {
1381   gint flags;
1382   gint dirty = FALSE;
1383   GtkTreePath *anchor_path = NULL;
1384
1385   if (selection->type == GTK_SELECTION_NONE)
1386     return;
1387
1388   if (selection->tree_view->priv->anchor)
1389     anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
1390
1391   if (selection->type == GTK_SELECTION_SINGLE ||
1392       selection->type == GTK_SELECTION_BROWSE)
1393     {
1394       /* just unselect */
1395       if (selection->type == GTK_SELECTION_BROWSE && override_browse_mode)
1396         {
1397           dirty = gtk_tree_selection_real_unselect_all (selection);
1398         }
1399       /* Did we try to select the same node again? */
1400       else if (selection->type == GTK_SELECTION_SINGLE &&
1401                anchor_path && gtk_tree_path_compare (path, anchor_path) == 0)
1402         {
1403           if ((mode & GTK_TREE_SELECT_MODE_TOGGLE) == GTK_TREE_SELECT_MODE_TOGGLE)
1404             {
1405               dirty = gtk_tree_selection_real_unselect_all (selection);
1406             }
1407         }
1408       else
1409         {
1410           if (anchor_path)
1411             {
1412               /* We only want to select the new node if we can unselect the old one,
1413                * and we can select the new one. */
1414               dirty = row_is_selectable (selection, node, path);
1415
1416               /* if dirty is FALSE, we weren't able to select the new one, otherwise, we try to
1417                * unselect the new one
1418                */
1419               if (dirty)
1420                 dirty = gtk_tree_selection_real_unselect_all (selection);
1421
1422               /* if dirty is TRUE at this point, we successfully unselected the
1423                * old one, and can then select the new one */
1424               if (dirty)
1425                 {
1426                   if (selection->tree_view->priv->anchor)
1427                     {
1428                       gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1429                       selection->tree_view->priv->anchor = NULL;
1430                     }
1431
1432                   if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1433                     {
1434                       selection->tree_view->priv->anchor =
1435                         gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1436                     }
1437                 }
1438             }
1439           else
1440             {
1441               if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1442                 {
1443                   dirty = TRUE;
1444                   if (selection->tree_view->priv->anchor)
1445                     gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1446
1447                   selection->tree_view->priv->anchor =
1448                     gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1449                 }
1450             }
1451         }
1452     }
1453   else if (selection->type == GTK_SELECTION_MULTIPLE)
1454     {
1455       if ((mode & GTK_TREE_SELECT_MODE_EXTEND) == GTK_TREE_SELECT_MODE_EXTEND
1456           && (anchor_path == NULL))
1457         {
1458           if (selection->tree_view->priv->anchor)
1459             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1460
1461           selection->tree_view->priv->anchor =
1462             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1463           dirty = gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1464         }
1465       else if ((mode & (GTK_TREE_SELECT_MODE_EXTEND | GTK_TREE_SELECT_MODE_TOGGLE)) == (GTK_TREE_SELECT_MODE_EXTEND | GTK_TREE_SELECT_MODE_TOGGLE))
1466         {
1467           gtk_tree_selection_select_range (selection,
1468                                            anchor_path,
1469                                            path);
1470         }
1471       else if ((mode & GTK_TREE_SELECT_MODE_TOGGLE) == GTK_TREE_SELECT_MODE_TOGGLE)
1472         {
1473           flags = node->flags;
1474           if (selection->tree_view->priv->anchor)
1475             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1476
1477           selection->tree_view->priv->anchor =
1478             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1479
1480           if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED)
1481             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
1482           else
1483             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1484         }
1485       else if ((mode & GTK_TREE_SELECT_MODE_EXTEND) == GTK_TREE_SELECT_MODE_EXTEND)
1486         {
1487           dirty = gtk_tree_selection_real_unselect_all (selection);
1488           dirty |= gtk_tree_selection_real_modify_range (selection,
1489                                                          RANGE_SELECT,
1490                                                          anchor_path,
1491                                                          path);
1492         }
1493       else
1494         {
1495           dirty = gtk_tree_selection_real_unselect_all (selection);
1496
1497           if (selection->tree_view->priv->anchor)
1498             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1499
1500           selection->tree_view->priv->anchor =
1501             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1502
1503           dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1504         }
1505     }
1506
1507   if (anchor_path)
1508     gtk_tree_path_free (anchor_path);
1509
1510   if (dirty)
1511     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1512 }
1513
1514 /* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
1515  */
1516
1517 static gint
1518 gtk_tree_selection_real_select_node (GtkTreeSelection *selection,
1519                                      GtkRBTree        *tree,
1520                                      GtkRBNode        *node,
1521                                      gboolean          select)
1522 {
1523   gboolean selected = FALSE;
1524   GtkTreePath *path = NULL;
1525
1526   select = !! select;
1527
1528   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select)
1529     {
1530       path = _gtk_tree_view_find_path (selection->tree_view, tree, node);
1531       selected = row_is_selectable (selection, node, path);
1532       gtk_tree_path_free (path);
1533     }
1534
1535   if (selected == TRUE)
1536     {
1537       node->flags ^= GTK_RBNODE_IS_SELECTED;
1538
1539       _gtk_tree_view_queue_draw_node (selection->tree_view, tree, node, NULL);
1540       
1541       return TRUE;
1542     }
1543
1544   return FALSE;
1545 }