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