]> Pileus Git - ~andy/gtk/blob - gtk/gtktree.c
Enforce the widget/child realization/mapping invariants.
[~andy/gtk] / gtk / gtktree.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtkmain.h"
28 #include "gtksignal.h"
29 #include "gtklist.h"
30
31 #define GTK_ENABLE_BROKEN
32 #include "gtktree.h"
33 #include "gtktreeitem.h"
34
35 enum {
36   SELECTION_CHANGED,
37   SELECT_CHILD,
38   UNSELECT_CHILD,
39   LAST_SIGNAL
40 };
41
42 static void gtk_tree_class_init      (GtkTreeClass   *klass);
43 static void gtk_tree_init            (GtkTree        *tree);
44 static void gtk_tree_destroy         (GtkObject      *object);
45 static void gtk_tree_map             (GtkWidget      *widget);
46 static void gtk_tree_parent_set      (GtkWidget      *widget,
47                                       GtkWidget      *previous_parent);
48 static void gtk_tree_unmap           (GtkWidget      *widget);
49 static void gtk_tree_realize         (GtkWidget      *widget);
50 static gint gtk_tree_motion_notify   (GtkWidget      *widget,
51                                       GdkEventMotion *event);
52 static gint gtk_tree_button_press    (GtkWidget      *widget,
53                                       GdkEventButton *event);
54 static gint gtk_tree_button_release  (GtkWidget      *widget,
55                                       GdkEventButton *event);
56 static void gtk_tree_size_request    (GtkWidget      *widget,
57                                       GtkRequisition *requisition);
58 static void gtk_tree_size_allocate   (GtkWidget      *widget,
59                                       GtkAllocation  *allocation);
60 static void gtk_tree_add             (GtkContainer   *container,
61                                       GtkWidget      *widget);
62 static void gtk_tree_forall          (GtkContainer   *container,
63                                       gboolean        include_internals,
64                                       GtkCallback     callback,
65                                       gpointer        callback_data);
66
67 static void gtk_real_tree_select_child   (GtkTree       *tree,
68                                           GtkWidget     *child);
69 static void gtk_real_tree_unselect_child (GtkTree       *tree,
70                                           GtkWidget     *child);
71
72 static GtkType gtk_tree_child_type  (GtkContainer   *container);
73
74 static GtkContainerClass *parent_class = NULL;
75 static guint tree_signals[LAST_SIGNAL] = { 0 };
76
77 GtkType
78 gtk_tree_get_type (void)
79 {
80   static GtkType tree_type = 0;
81   
82   if (!tree_type)
83     {
84       static const GtkTypeInfo tree_info =
85       {
86         "GtkTree",
87         sizeof (GtkTree),
88         sizeof (GtkTreeClass),
89         (GtkClassInitFunc) gtk_tree_class_init,
90         (GtkObjectInitFunc) gtk_tree_init,
91         /* reserved_1 */ NULL,
92         /* reserved_2 */ NULL,
93         (GtkClassInitFunc) NULL,
94       };
95       
96       tree_type = gtk_type_unique (gtk_container_get_type (), &tree_info);
97     }
98   
99   return tree_type;
100 }
101
102 static void
103 gtk_tree_class_init (GtkTreeClass *class)
104 {
105   GtkObjectClass *object_class;
106   GtkWidgetClass *widget_class;
107   GtkContainerClass *container_class;
108   
109   object_class = (GtkObjectClass*) class;
110   widget_class = (GtkWidgetClass*) class;
111   container_class = (GtkContainerClass*) class;
112   
113   parent_class = gtk_type_class (gtk_container_get_type ());
114   
115   
116   object_class->destroy = gtk_tree_destroy;
117   
118   widget_class->map = gtk_tree_map;
119   widget_class->unmap = gtk_tree_unmap;
120   widget_class->parent_set = gtk_tree_parent_set;
121   widget_class->realize = gtk_tree_realize;
122   widget_class->motion_notify_event = gtk_tree_motion_notify;
123   widget_class->button_press_event = gtk_tree_button_press;
124   widget_class->button_release_event = gtk_tree_button_release;
125   widget_class->size_request = gtk_tree_size_request;
126   widget_class->size_allocate = gtk_tree_size_allocate;
127   
128   container_class->add = gtk_tree_add;
129   container_class->remove = 
130     (void (*)(GtkContainer *, GtkWidget *)) gtk_tree_remove_item;
131   container_class->forall = gtk_tree_forall;
132   container_class->child_type = gtk_tree_child_type;
133   
134   class->selection_changed = NULL;
135   class->select_child = gtk_real_tree_select_child;
136   class->unselect_child = gtk_real_tree_unselect_child;
137
138   tree_signals[SELECTION_CHANGED] =
139     gtk_signal_new ("selection_changed",
140                     GTK_RUN_FIRST,
141                     GTK_CLASS_TYPE (object_class),
142                     GTK_SIGNAL_OFFSET (GtkTreeClass, selection_changed),
143                     gtk_marshal_VOID__VOID,
144                     GTK_TYPE_NONE, 0);
145   tree_signals[SELECT_CHILD] =
146     gtk_signal_new ("select_child",
147                     GTK_RUN_FIRST,
148                     GTK_CLASS_TYPE (object_class),
149                     GTK_SIGNAL_OFFSET (GtkTreeClass, select_child),
150                     gtk_marshal_VOID__OBJECT,
151                     GTK_TYPE_NONE, 1,
152                     GTK_TYPE_WIDGET);
153   tree_signals[UNSELECT_CHILD] =
154     gtk_signal_new ("unselect_child",
155                     GTK_RUN_FIRST,
156                     GTK_CLASS_TYPE (object_class),
157                     GTK_SIGNAL_OFFSET (GtkTreeClass, unselect_child),
158                     gtk_marshal_VOID__OBJECT,
159                     GTK_TYPE_NONE, 1,
160                     GTK_TYPE_WIDGET);
161 }
162
163 static GtkType
164 gtk_tree_child_type (GtkContainer     *container)
165 {
166   return GTK_TYPE_TREE_ITEM;
167 }
168
169 static void
170 gtk_tree_init (GtkTree *tree)
171 {
172   tree->children = NULL;
173   tree->root_tree = tree;
174   tree->selection = NULL;
175   tree->tree_owner = NULL;
176   tree->selection_mode = GTK_SELECTION_SINGLE;
177   tree->indent_value = 9;
178   tree->current_indent = 0;
179   tree->level = 0;
180   tree->view_mode = GTK_TREE_VIEW_LINE;
181   tree->view_line = TRUE;
182 }
183
184 GtkWidget*
185 gtk_tree_new (void)
186 {
187   return GTK_WIDGET (gtk_type_new (gtk_tree_get_type ()));
188 }
189
190 void
191 gtk_tree_append (GtkTree   *tree,
192                  GtkWidget *tree_item)
193 {
194   g_return_if_fail (GTK_IS_TREE (tree));
195   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
196   
197   gtk_tree_insert (tree, tree_item, -1);
198 }
199
200 void
201 gtk_tree_prepend (GtkTree   *tree,
202                   GtkWidget *tree_item)
203 {
204   g_return_if_fail (GTK_IS_TREE (tree));
205   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
206   
207   gtk_tree_insert (tree, tree_item, 0);
208 }
209
210 void
211 gtk_tree_insert (GtkTree   *tree,
212                  GtkWidget *tree_item,
213                  gint       position)
214 {
215   gint nchildren;
216   
217   g_return_if_fail (GTK_IS_TREE (tree));
218   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
219   
220   nchildren = g_list_length (tree->children);
221   
222   if ((position < 0) || (position > nchildren))
223     position = nchildren;
224   
225   if (position == nchildren)
226     tree->children = g_list_append (tree->children, tree_item);
227   else
228     tree->children = g_list_insert (tree->children, tree_item, position);
229   
230   gtk_widget_set_parent (tree_item, GTK_WIDGET (tree));
231 }
232
233 static void
234 gtk_tree_add (GtkContainer *container,
235               GtkWidget    *child)
236 {
237   GtkTree *tree;
238   
239   g_return_if_fail (GTK_IS_TREE (container));
240   g_return_if_fail (GTK_IS_TREE_ITEM (child));
241   
242   tree = GTK_TREE (container);
243   
244   tree->children = g_list_append (tree->children, child);
245   
246   gtk_widget_set_parent (child, GTK_WIDGET (container));
247   
248   if (!tree->selection && (tree->selection_mode == GTK_SELECTION_BROWSE))
249     gtk_tree_select_child (tree, child);
250 }
251
252 static gint
253 gtk_tree_button_press (GtkWidget      *widget,
254                        GdkEventButton *event)
255 {
256   GtkTree *tree;
257   GtkWidget *item;
258   
259   g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
260   g_return_val_if_fail (event != NULL, FALSE);
261   
262   tree = GTK_TREE (widget);
263   item = gtk_get_event_widget ((GdkEvent*) event);
264   
265   while (item && !GTK_IS_TREE_ITEM (item))
266     item = item->parent;
267   
268   if (!item || (item->parent != widget))
269     return FALSE;
270   
271   switch(event->button) 
272     {
273     case 1:
274       gtk_tree_select_child (tree, item);
275       break;
276     case 2:
277       if(GTK_TREE_ITEM(item)->subtree) gtk_tree_item_expand(GTK_TREE_ITEM(item));
278       break;
279     case 3:
280       if(GTK_TREE_ITEM(item)->subtree) gtk_tree_item_collapse(GTK_TREE_ITEM(item));
281       break;
282     }
283   
284   return TRUE;
285 }
286
287 static gint
288 gtk_tree_button_release (GtkWidget      *widget,
289                          GdkEventButton *event)
290 {
291   GtkTree *tree;
292   GtkWidget *item;
293   
294   g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
295   g_return_val_if_fail (event != NULL, FALSE);
296   
297   tree = GTK_TREE (widget);
298   item = gtk_get_event_widget ((GdkEvent*) event);
299   
300   return TRUE;
301 }
302
303 gint
304 gtk_tree_child_position (GtkTree   *tree,
305                          GtkWidget *child)
306 {
307   GList *children;
308   gint pos;
309   
310   
311   g_return_val_if_fail (GTK_IS_TREE (tree), -1);
312   g_return_val_if_fail (child != NULL, -1);
313   
314   pos = 0;
315   children = tree->children;
316   
317   while (children)
318     {
319       if (child == GTK_WIDGET (children->data)) 
320         return pos;
321       
322       pos += 1;
323       children = children->next;
324     }
325   
326   
327   return -1;
328 }
329
330 void
331 gtk_tree_clear_items (GtkTree *tree,
332                       gint     start,
333                       gint     end)
334 {
335   GtkWidget *widget;
336   GList *clear_list;
337   GList *tmp_list;
338   guint nchildren;
339   guint index;
340   
341   g_return_if_fail (GTK_IS_TREE (tree));
342   
343   nchildren = g_list_length (tree->children);
344   
345   if (nchildren > 0)
346     {
347       if ((end < 0) || (end > nchildren))
348         end = nchildren;
349       
350       if (start >= end)
351         return;
352       
353       tmp_list = g_list_nth (tree->children, start);
354       clear_list = NULL;
355       index = start;
356       while (tmp_list && index <= end)
357         {
358           widget = tmp_list->data;
359           tmp_list = tmp_list->next;
360           index++;
361           
362           clear_list = g_list_prepend (clear_list, widget);
363         }
364       
365       gtk_tree_remove_items (tree, clear_list);
366     }
367 }
368
369 static void
370 gtk_tree_destroy (GtkObject *object)
371 {
372   GtkTree *tree;
373   GtkWidget *child;
374   GList *children;
375   
376   g_return_if_fail (GTK_IS_TREE (object));
377   
378   tree = GTK_TREE (object);
379   
380   children = tree->children;
381   while (children)
382     {
383       child = children->data;
384       children = children->next;
385       
386       gtk_widget_ref (child);
387       gtk_widget_unparent (child);
388       gtk_widget_destroy (child);
389       gtk_widget_unref (child);
390     }
391   
392   g_list_free (tree->children);
393   tree->children = NULL;
394   
395   if (tree->root_tree == tree)
396     {
397       GList *node;
398       for (node = tree->selection; node; node = node->next)
399         gtk_widget_unref ((GtkWidget *)node->data);
400       g_list_free (tree->selection);
401       tree->selection = NULL;
402     }
403   
404   if (GTK_OBJECT_CLASS (parent_class)->destroy)
405     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
406 }
407
408 static void
409 gtk_tree_forall (GtkContainer *container,
410                  gboolean      include_internals,
411                  GtkCallback   callback,
412                  gpointer      callback_data)
413 {
414   GtkTree *tree;
415   GtkWidget *child;
416   GList *children;
417   
418   
419   g_return_if_fail (GTK_IS_TREE (container));
420   g_return_if_fail (callback != NULL);
421   
422   tree = GTK_TREE (container);
423   children = tree->children;
424   
425   while (children)
426     {
427       child = children->data;
428       children = children->next;
429       
430       (* callback) (child, callback_data);
431     }
432 }
433
434 static void
435 gtk_tree_unselect_all (GtkTree *tree)
436 {
437   GList *tmp_list, *selection;
438   GtkWidget *tmp_item;
439       
440   selection = tree->selection;
441   tree->selection = NULL;
442
443   tmp_list = selection;
444   while (tmp_list)
445     {
446       tmp_item = selection->data;
447
448       if (tmp_item->parent &&
449           GTK_IS_TREE (tmp_item->parent) &&
450           GTK_TREE (tmp_item->parent)->root_tree == tree)
451         gtk_tree_item_deselect (GTK_TREE_ITEM (tmp_item));
452
453       gtk_widget_unref (tmp_item);
454
455       tmp_list = tmp_list->next;
456     }
457
458   g_list_free (selection);
459 }
460
461 static void
462 gtk_tree_parent_set (GtkWidget *widget,
463                      GtkWidget *previous_parent)
464 {
465   GtkTree *tree = GTK_TREE (widget);
466   GtkWidget *child;
467   GList *children;
468   
469   if (widget->parent && GTK_IS_TREE (widget->parent))
470     {
471       gtk_tree_unselect_all (tree);
472       
473       /* set root tree for this tree */
474       tree->root_tree = GTK_TREE(widget->parent)->root_tree;
475       
476       tree->level = GTK_TREE(GTK_WIDGET(tree)->parent)->level+1;
477       tree->indent_value = GTK_TREE(GTK_WIDGET(tree)->parent)->indent_value;
478       tree->current_indent = GTK_TREE(GTK_WIDGET(tree)->parent)->current_indent + 
479         tree->indent_value;
480       tree->view_mode = GTK_TREE(GTK_WIDGET(tree)->parent)->view_mode;
481       tree->view_line = GTK_TREE(GTK_WIDGET(tree)->parent)->view_line;
482     }
483   else
484     {
485       tree->root_tree = tree;
486       
487       tree->level = 0;
488       tree->current_indent = 0;
489     }
490
491   children = tree->children;
492   while (children)
493     {
494       child = children->data;
495       children = children->next;
496       
497       if (GTK_TREE_ITEM (child)->subtree)
498         gtk_tree_parent_set (GTK_TREE_ITEM (child)->subtree, child);
499     }
500 }
501
502 static void
503 gtk_tree_map (GtkWidget *widget)
504 {
505   GtkTree *tree = GTK_TREE (widget);
506   GtkWidget *child;
507   GList *children;
508   
509   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
510   
511   children = tree->children;
512   while (children)
513     {
514       child = children->data;
515       children = children->next;
516       
517       if (GTK_WIDGET_VISIBLE (child) &&
518           !GTK_WIDGET_MAPPED (child))
519         gtk_widget_map (child);
520       
521       if (GTK_TREE_ITEM (child)->subtree)
522         {
523           child = GTK_WIDGET (GTK_TREE_ITEM (child)->subtree);
524           
525           if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child))
526             gtk_widget_map (child);
527         }
528     }
529
530   gdk_window_show (widget->window);
531 }
532
533 static gint
534 gtk_tree_motion_notify (GtkWidget      *widget,
535                         GdkEventMotion *event)
536 {
537   g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
538   g_return_val_if_fail (event != NULL, FALSE);
539   
540 #ifdef TREE_DEBUG
541   g_message("gtk_tree_motion_notify\n");
542 #endif /* TREE_DEBUG */
543   
544   return FALSE;
545 }
546
547 static void
548 gtk_tree_realize (GtkWidget *widget)
549 {
550   GdkWindowAttr attributes;
551   gint attributes_mask;
552   
553   
554   g_return_if_fail (GTK_IS_TREE (widget));
555   
556   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
557   
558   attributes.window_type = GDK_WINDOW_CHILD;
559   attributes.x = widget->allocation.x;
560   attributes.y = widget->allocation.y;
561   attributes.width = widget->allocation.width;
562   attributes.height = widget->allocation.height;
563   attributes.wclass = GDK_INPUT_OUTPUT;
564   attributes.visual = gtk_widget_get_visual (widget);
565   attributes.colormap = gtk_widget_get_colormap (widget);
566   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
567   
568   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
569   
570   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
571   gdk_window_set_user_data (widget->window, widget);
572   
573   widget->style = gtk_style_attach (widget->style, widget->window);
574   gdk_window_set_background (widget->window, 
575                              &widget->style->base[GTK_STATE_NORMAL]);
576 }
577
578 void
579 gtk_tree_remove_item (GtkTree      *container,
580                       GtkWidget    *widget)
581 {
582   GList *item_list;
583   
584   g_return_if_fail (GTK_IS_TREE (container));
585   g_return_if_fail (widget != NULL);
586   g_return_if_fail (container == GTK_TREE (widget->parent));
587   
588   item_list = g_list_append (NULL, widget);
589   
590   gtk_tree_remove_items (GTK_TREE (container), item_list);
591   
592   g_list_free (item_list);
593 }
594
595 /* used by gtk_tree_remove_items to make the function independant of
596    order in list of items to remove.
597    Sort item bu depth in tree */
598 static gint 
599 gtk_tree_sort_item_by_depth(GtkWidget* a, GtkWidget* b)
600 {
601   if((GTK_TREE(a->parent)->level) < (GTK_TREE(b->parent)->level))
602     return 1;
603   if((GTK_TREE(a->parent)->level) > (GTK_TREE(b->parent)->level))
604     return -1;
605   
606   return 0;
607 }
608
609 void
610 gtk_tree_remove_items (GtkTree *tree,
611                        GList   *items)
612 {
613   GtkWidget *widget;
614   GList *selected_widgets;
615   GList *tmp_list;
616   GList *sorted_list;
617   GtkTree *real_tree;
618   GtkTree *root_tree;
619   
620   g_return_if_fail (GTK_IS_TREE (tree));
621   
622 #ifdef TREE_DEBUG
623   g_message("+ gtk_tree_remove_items [ tree %#x items list %#x ]\n", (int)tree, (int)items);
624 #endif /* TREE_DEBUG */
625   
626   /* We may not yet be mapped, so we actively have to find our
627    * root tree
628    */
629   if (tree->root_tree)
630     root_tree = tree->root_tree;
631   else
632     {
633       GtkWidget *tmp = GTK_WIDGET (tree);
634       while (tmp->parent && GTK_IS_TREE (tmp->parent))
635         tmp = tmp->parent;
636       
637       root_tree = GTK_TREE (tmp);
638     }
639   
640   tmp_list = items;
641   selected_widgets = NULL;
642   sorted_list = NULL;
643   widget = NULL;
644   
645 #ifdef TREE_DEBUG
646   g_message("* sort list by depth\n");
647 #endif /* TREE_DEBUG */
648   
649   while (tmp_list)
650     {
651       
652 #ifdef TREE_DEBUG
653       g_message ("* item [%#x] depth [%d]\n", 
654                  (int)tmp_list->data,
655                  (int)GTK_TREE(GTK_WIDGET(tmp_list->data)->parent)->level);
656 #endif /* TREE_DEBUG */
657       
658       sorted_list = g_list_insert_sorted(sorted_list,
659                                          tmp_list->data,
660                                          (GCompareFunc)gtk_tree_sort_item_by_depth);
661       tmp_list = g_list_next(tmp_list);
662     }
663   
664 #ifdef TREE_DEBUG
665   /* print sorted list */
666   g_message("* sorted list result\n");
667   tmp_list = sorted_list;
668   while(tmp_list)
669     {
670       g_message("* item [%#x] depth [%d]\n", 
671                 (int)tmp_list->data,
672                 (int)GTK_TREE(GTK_WIDGET(tmp_list->data)->parent)->level);
673       tmp_list = g_list_next(tmp_list);
674     }
675 #endif /* TREE_DEBUG */
676   
677 #ifdef TREE_DEBUG
678   g_message("* scan sorted list\n");
679 #endif /* TREE_DEBUG */
680   
681   tmp_list = sorted_list;
682   while (tmp_list)
683     {
684       widget = tmp_list->data;
685       tmp_list = tmp_list->next;
686       
687 #ifdef TREE_DEBUG
688       g_message("* item [%#x] subtree [%#x]\n", 
689                 (int)widget, (int)GTK_TREE_ITEM_SUBTREE(widget));
690 #endif /* TREE_DEBUG */
691       
692       /* get real owner of this widget */
693       real_tree = GTK_TREE(widget->parent);
694 #ifdef TREE_DEBUG
695       g_message("* subtree having this widget [%#x]\n", (int)real_tree);
696 #endif /* TREE_DEBUG */
697       
698       
699       if (widget->state == GTK_STATE_SELECTED)
700         {
701           selected_widgets = g_list_prepend (selected_widgets, widget);
702 #ifdef TREE_DEBUG
703           g_message("* selected widget - adding it in selected list [%#x]\n",
704                     (int)selected_widgets);
705 #endif /* TREE_DEBUG */
706         }
707       
708       /* remove this item from its real parent */
709 #ifdef TREE_DEBUG
710       g_message("* remove widget from its owner tree\n");
711 #endif /* TREE_DEBUG */
712       real_tree->children = g_list_remove (real_tree->children, widget);
713       
714       /* remove subtree associate at this item if it exist */      
715       if(GTK_TREE_ITEM(widget)->subtree) 
716         {
717 #ifdef TREE_DEBUG
718           g_message("* remove subtree associate at this item [%#x]\n",
719                     (int) GTK_TREE_ITEM(widget)->subtree);
720 #endif /* TREE_DEBUG */
721           if (GTK_WIDGET_MAPPED (GTK_TREE_ITEM(widget)->subtree))
722             gtk_widget_unmap (GTK_TREE_ITEM(widget)->subtree);
723           
724           gtk_widget_unparent (GTK_TREE_ITEM(widget)->subtree);
725           GTK_TREE_ITEM(widget)->subtree = NULL;
726         }
727       
728       /* really remove widget for this item */
729 #ifdef TREE_DEBUG
730       g_message("* unmap and unparent widget [%#x]\n", (int)widget);
731 #endif /* TREE_DEBUG */
732       if (GTK_WIDGET_MAPPED (widget))
733         gtk_widget_unmap (widget);
734       
735       gtk_widget_unparent (widget);
736       
737       /* delete subtree if there is no children in it */
738       if(real_tree->children == NULL && 
739          real_tree != root_tree)
740         {
741 #ifdef TREE_DEBUG
742           g_message("* owner tree don't have children ... destroy it\n");
743 #endif /* TREE_DEBUG */
744           gtk_tree_item_remove_subtree(GTK_TREE_ITEM(real_tree->tree_owner));
745         }
746       
747 #ifdef TREE_DEBUG
748       g_message("* next item in list\n");
749 #endif /* TREE_DEBUG */
750     }
751   
752   if (selected_widgets)
753     {
754 #ifdef TREE_DEBUG
755       g_message("* scan selected item list\n");
756 #endif /* TREE_DEBUG */
757       tmp_list = selected_widgets;
758       while (tmp_list)
759         {
760           widget = tmp_list->data;
761           tmp_list = tmp_list->next;
762           
763 #ifdef TREE_DEBUG
764           g_message("* widget [%#x] subtree [%#x]\n", 
765                     (int)widget, (int)GTK_TREE_ITEM_SUBTREE(widget));
766 #endif /* TREE_DEBUG */
767           
768           /* remove widget of selection */
769           root_tree->selection = g_list_remove (root_tree->selection, widget);
770           
771           /* unref it to authorize is destruction */
772           gtk_widget_unref (widget);
773         }
774       
775       /* emit only one selection_changed signal */
776       gtk_signal_emit (GTK_OBJECT (root_tree), 
777                        tree_signals[SELECTION_CHANGED]);
778     }
779   
780 #ifdef TREE_DEBUG
781   g_message("* free selected_widgets list\n");
782 #endif /* TREE_DEBUG */
783   g_list_free (selected_widgets);
784   g_list_free (sorted_list);
785   
786   if (root_tree->children && !root_tree->selection &&
787       (root_tree->selection_mode == GTK_SELECTION_BROWSE))
788     {
789 #ifdef TREE_DEBUG
790       g_message("* BROWSE mode, select another item\n");
791 #endif /* TREE_DEBUG */
792       widget = root_tree->children->data;
793       gtk_tree_select_child (root_tree, widget);
794     }
795   
796   if (GTK_WIDGET_VISIBLE (root_tree))
797     {
798 #ifdef TREE_DEBUG
799       g_message("* query queue resizing for root_tree\n");
800 #endif /* TREE_DEBUG */      
801       gtk_widget_queue_resize (GTK_WIDGET (root_tree));
802     }
803 }
804
805 void
806 gtk_tree_select_child (GtkTree   *tree,
807                        GtkWidget *tree_item)
808 {
809   g_return_if_fail (GTK_IS_TREE (tree));
810   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
811   
812   gtk_signal_emit (GTK_OBJECT (tree), tree_signals[SELECT_CHILD], tree_item);
813 }
814
815 void
816 gtk_tree_select_item (GtkTree   *tree,
817                       gint       item)
818 {
819   GList *tmp_list;
820   
821   g_return_if_fail (GTK_IS_TREE (tree));
822   
823   tmp_list = g_list_nth (tree->children, item);
824   if (tmp_list)
825     gtk_tree_select_child (tree, GTK_WIDGET (tmp_list->data));
826   
827 }
828
829 static void
830 gtk_tree_size_allocate (GtkWidget     *widget,
831                         GtkAllocation *allocation)
832 {
833   GtkTree *tree;
834   GtkWidget *child, *subtree;
835   GtkAllocation child_allocation;
836   GList *children;
837   
838   
839   g_return_if_fail (GTK_IS_TREE (widget));
840   g_return_if_fail (allocation != NULL);
841   
842   tree = GTK_TREE (widget);
843   
844   widget->allocation = *allocation;
845   if (GTK_WIDGET_REALIZED (widget))
846     gdk_window_move_resize (widget->window,
847                             allocation->x, allocation->y,
848                             allocation->width, allocation->height);
849   
850   if (tree->children)
851     {
852       child_allocation.x = GTK_CONTAINER (tree)->border_width;
853       child_allocation.y = GTK_CONTAINER (tree)->border_width;
854       child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
855       
856       children = tree->children;
857       
858       while (children)
859         {
860           child = children->data;
861           children = children->next;
862           
863           if (GTK_WIDGET_VISIBLE (child))
864             {
865               GtkRequisition child_requisition;
866               gtk_widget_get_child_requisition (child, &child_requisition);
867               
868               child_allocation.height = child_requisition.height;
869               
870               gtk_widget_size_allocate (child, &child_allocation);
871               
872               child_allocation.y += child_allocation.height;
873               
874               if((subtree = GTK_TREE_ITEM(child)->subtree))
875                 if(GTK_WIDGET_VISIBLE (subtree))
876                   {
877                     child_allocation.height = subtree->requisition.height;
878                     gtk_widget_size_allocate (subtree, &child_allocation);
879                     child_allocation.y += child_allocation.height;
880                   }
881             }
882         }
883     }
884   
885 }
886
887 static void
888 gtk_tree_size_request (GtkWidget      *widget,
889                        GtkRequisition *requisition)
890 {
891   GtkTree *tree;
892   GtkWidget *child, *subtree;
893   GList *children;
894   GtkRequisition child_requisition;
895   
896   
897   g_return_if_fail (GTK_IS_TREE (widget));
898   g_return_if_fail (requisition != NULL);
899   
900   tree = GTK_TREE (widget);
901   requisition->width = 0;
902   requisition->height = 0;
903   
904   children = tree->children;
905   while (children)
906     {
907       child = children->data;
908       children = children->next;
909       
910       if (GTK_WIDGET_VISIBLE (child))
911         {
912           gtk_widget_size_request (child, &child_requisition);
913           
914           requisition->width = MAX (requisition->width, child_requisition.width);
915           requisition->height += child_requisition.height;
916           
917           if((subtree = GTK_TREE_ITEM(child)->subtree) &&
918              GTK_WIDGET_VISIBLE (subtree))
919             {
920               gtk_widget_size_request (subtree, &child_requisition);
921               
922               requisition->width = MAX (requisition->width, 
923                                         child_requisition.width);
924               
925               requisition->height += child_requisition.height;
926             }
927         }
928     }
929   
930   requisition->width += GTK_CONTAINER (tree)->border_width * 2;
931   requisition->height += GTK_CONTAINER (tree)->border_width * 2;
932   
933   requisition->width = MAX (requisition->width, 1);
934   requisition->height = MAX (requisition->height, 1);
935   
936 }
937
938 static void
939 gtk_tree_unmap (GtkWidget *widget)
940 {
941   
942   g_return_if_fail (GTK_IS_TREE (widget));
943   
944   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
945   gdk_window_hide (widget->window);
946   
947 }
948
949 void
950 gtk_tree_unselect_child (GtkTree   *tree,
951                          GtkWidget *tree_item)
952 {
953   g_return_if_fail (GTK_IS_TREE (tree));
954   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
955   
956   gtk_signal_emit (GTK_OBJECT (tree), tree_signals[UNSELECT_CHILD], tree_item);
957 }
958
959 void
960 gtk_tree_unselect_item (GtkTree *tree,
961                         gint     item)
962 {
963   GList *tmp_list;
964   
965   g_return_if_fail (GTK_IS_TREE (tree));
966   
967   tmp_list = g_list_nth (tree->children, item);
968   if (tmp_list)
969     gtk_tree_unselect_child (tree, GTK_WIDGET (tmp_list->data));
970   
971 }
972
973 static void
974 gtk_real_tree_select_child (GtkTree   *tree,
975                             GtkWidget *child)
976 {
977   GList *selection, *root_selection;
978   GList *tmp_list;
979   GtkWidget *tmp_item;
980   
981   g_return_if_fail (GTK_IS_TREE (tree));
982   g_return_if_fail (GTK_IS_TREE_ITEM (child));
983
984   root_selection = tree->root_tree->selection;
985   
986   switch (tree->root_tree->selection_mode)
987     {
988     case GTK_SELECTION_SINGLE:
989       
990       selection = root_selection;
991       
992       /* remove old selection list */
993       while (selection)
994         {
995           tmp_item = selection->data;
996           
997           if (tmp_item != child)
998             {
999               gtk_tree_item_deselect (GTK_TREE_ITEM (tmp_item));
1000               
1001               tmp_list = selection;
1002               selection = selection->next;
1003               
1004               root_selection = g_list_remove_link (root_selection, tmp_list);
1005               gtk_widget_unref (tmp_item);
1006               
1007               g_list_free (tmp_list);
1008             }
1009           else
1010             selection = selection->next;
1011         }
1012       
1013       if (child->state == GTK_STATE_NORMAL)
1014         {
1015           gtk_tree_item_select (GTK_TREE_ITEM (child));
1016           root_selection = g_list_prepend (root_selection, child);
1017           gtk_widget_ref (child);
1018         }
1019       else if (child->state == GTK_STATE_SELECTED)
1020         {
1021           gtk_tree_item_deselect (GTK_TREE_ITEM (child));
1022           root_selection = g_list_remove (root_selection, child);
1023           gtk_widget_unref (child);
1024         }
1025       
1026       tree->root_tree->selection = root_selection;
1027       
1028       gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1029                        tree_signals[SELECTION_CHANGED]);
1030       break;
1031       
1032       
1033     case GTK_SELECTION_BROWSE:
1034       selection = root_selection;
1035       
1036       while (selection)
1037         {
1038           tmp_item = selection->data;
1039           
1040           if (tmp_item != child)
1041             {
1042               gtk_tree_item_deselect (GTK_TREE_ITEM (tmp_item));
1043               
1044               tmp_list = selection;
1045               selection = selection->next;
1046               
1047               root_selection = g_list_remove_link (root_selection, tmp_list);
1048               gtk_widget_unref (tmp_item);
1049               
1050               g_list_free (tmp_list);
1051             }
1052           else
1053             selection = selection->next;
1054         }
1055       
1056       tree->root_tree->selection = root_selection;
1057       
1058       if (child->state == GTK_STATE_NORMAL)
1059         {
1060           gtk_tree_item_select (GTK_TREE_ITEM (child));
1061           root_selection = g_list_prepend (root_selection, child);
1062           gtk_widget_ref (child);
1063           tree->root_tree->selection = root_selection;
1064           gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1065                            tree_signals[SELECTION_CHANGED]);
1066         }
1067       break;
1068       
1069     case GTK_SELECTION_MULTIPLE:
1070       if (child->state == GTK_STATE_NORMAL)
1071         {
1072           gtk_tree_item_select (GTK_TREE_ITEM (child));
1073           root_selection = g_list_prepend (root_selection, child);
1074           gtk_widget_ref (child);
1075           tree->root_tree->selection = root_selection;
1076           gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1077                            tree_signals[SELECTION_CHANGED]);
1078         }
1079       else if (child->state == GTK_STATE_SELECTED)
1080         {
1081           gtk_tree_item_deselect (GTK_TREE_ITEM (child));
1082           root_selection = g_list_remove (root_selection, child);
1083           gtk_widget_unref (child);
1084           tree->root_tree->selection = root_selection;
1085           gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1086                            tree_signals[SELECTION_CHANGED]);
1087         }
1088       break;
1089       
1090     case GTK_SELECTION_EXTENDED:
1091       break;
1092     }
1093 }
1094
1095 static void
1096 gtk_real_tree_unselect_child (GtkTree   *tree,
1097                               GtkWidget *child)
1098 {
1099   g_return_if_fail (GTK_IS_TREE (tree));
1100   g_return_if_fail (GTK_IS_TREE_ITEM (child));
1101   
1102   switch (tree->selection_mode)
1103     {
1104     case GTK_SELECTION_SINGLE:
1105     case GTK_SELECTION_MULTIPLE:
1106     case GTK_SELECTION_BROWSE:
1107       if (child->state == GTK_STATE_SELECTED)
1108         {
1109           GtkTree* root_tree = GTK_TREE_ROOT_TREE(tree);
1110           gtk_tree_item_deselect (GTK_TREE_ITEM (child));
1111           root_tree->selection = g_list_remove (root_tree->selection, child);
1112           gtk_widget_unref (child);
1113           gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1114                            tree_signals[SELECTION_CHANGED]);
1115         }
1116       break;
1117       
1118     case GTK_SELECTION_EXTENDED:
1119       break;
1120     }
1121 }
1122
1123 void
1124 gtk_tree_set_selection_mode (GtkTree       *tree,
1125                              GtkSelectionMode mode) 
1126 {
1127   g_return_if_fail (GTK_IS_TREE (tree));
1128   
1129   tree->selection_mode = mode;
1130 }
1131
1132 void
1133 gtk_tree_set_view_mode (GtkTree       *tree,
1134                         GtkTreeViewMode mode) 
1135 {
1136   g_return_if_fail (GTK_IS_TREE (tree));
1137   
1138   tree->view_mode = mode;
1139 }
1140
1141 void
1142 gtk_tree_set_view_lines (GtkTree       *tree,
1143                          gboolean       flag) 
1144 {
1145   g_return_if_fail (GTK_IS_TREE (tree));
1146   
1147   tree->view_line = flag;
1148 }