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