]> Pileus Git - ~andy/gtk/blob - gtk/gtktree.c
Document expose event->region change and that gtk_widget_event doesn't
[~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 = 1;
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 (tree != NULL);
195   g_return_if_fail (GTK_IS_TREE (tree));
196   g_return_if_fail (tree_item != NULL);
197   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
198   
199   gtk_tree_insert (tree, tree_item, -1);
200 }
201
202 void
203 gtk_tree_prepend (GtkTree   *tree,
204                   GtkWidget *tree_item)
205 {
206   g_return_if_fail (tree != NULL);
207   g_return_if_fail (GTK_IS_TREE (tree));
208   g_return_if_fail (tree_item != NULL);
209   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
210   
211   gtk_tree_insert (tree, tree_item, 0);
212 }
213
214 void
215 gtk_tree_insert (GtkTree   *tree,
216                  GtkWidget *tree_item,
217                  gint       position)
218 {
219   gint nchildren;
220   
221   g_return_if_fail (tree != NULL);
222   g_return_if_fail (GTK_IS_TREE (tree));
223   g_return_if_fail (tree_item != NULL);
224   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
225   
226   nchildren = g_list_length (tree->children);
227   
228   if ((position < 0) || (position > nchildren))
229     position = nchildren;
230   
231   if (position == nchildren)
232     tree->children = g_list_append (tree->children, tree_item);
233   else
234     tree->children = g_list_insert (tree->children, tree_item, position);
235   
236   gtk_widget_set_parent (tree_item, GTK_WIDGET (tree));
237   
238   if (GTK_WIDGET_REALIZED (tree_item->parent))
239     gtk_widget_realize (tree_item);
240
241   if (GTK_WIDGET_VISIBLE (tree_item->parent) && GTK_WIDGET_VISIBLE (tree_item))
242     {
243       if (GTK_WIDGET_MAPPED (tree_item->parent))
244         gtk_widget_map (tree_item);
245
246       gtk_widget_queue_resize (tree_item);
247     }
248 }
249
250 static void
251 gtk_tree_add (GtkContainer *container,
252               GtkWidget    *child)
253 {
254   GtkTree *tree;
255   
256   g_return_if_fail (container != NULL);
257   g_return_if_fail (GTK_IS_TREE (container));
258   g_return_if_fail (GTK_IS_TREE_ITEM (child));
259   
260   tree = GTK_TREE (container);
261   
262   tree->children = g_list_append (tree->children, child);
263   
264   gtk_widget_set_parent (child, GTK_WIDGET (container));
265   
266   if (GTK_WIDGET_REALIZED (child->parent))
267     gtk_widget_realize (child);
268
269   if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
270     {
271       if (GTK_WIDGET_MAPPED (child->parent))
272         gtk_widget_map (child);
273
274       gtk_widget_queue_resize (child);
275     }
276   
277   if (!tree->selection && (tree->selection_mode == GTK_SELECTION_BROWSE))
278     gtk_tree_select_child (tree, child);
279 }
280
281 static gint
282 gtk_tree_button_press (GtkWidget      *widget,
283                        GdkEventButton *event)
284 {
285   GtkTree *tree;
286   GtkWidget *item;
287   
288   g_return_val_if_fail (widget != NULL, FALSE);
289   g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
290   g_return_val_if_fail (event != NULL, FALSE);
291   
292   tree = GTK_TREE (widget);
293   item = gtk_get_event_widget ((GdkEvent*) event);
294   
295   while (item && !GTK_IS_TREE_ITEM (item))
296     item = item->parent;
297   
298   if (!item || (item->parent != widget))
299     return FALSE;
300   
301   switch(event->button) 
302     {
303     case 1:
304       gtk_tree_select_child (tree, item);
305       break;
306     case 2:
307       if(GTK_TREE_ITEM(item)->subtree) gtk_tree_item_expand(GTK_TREE_ITEM(item));
308       break;
309     case 3:
310       if(GTK_TREE_ITEM(item)->subtree) gtk_tree_item_collapse(GTK_TREE_ITEM(item));
311       break;
312     }
313   
314   return TRUE;
315 }
316
317 static gint
318 gtk_tree_button_release (GtkWidget      *widget,
319                          GdkEventButton *event)
320 {
321   GtkTree *tree;
322   GtkWidget *item;
323   
324   g_return_val_if_fail (widget != NULL, FALSE);
325   g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
326   g_return_val_if_fail (event != NULL, FALSE);
327   
328   tree = GTK_TREE (widget);
329   item = gtk_get_event_widget ((GdkEvent*) event);
330   
331   return TRUE;
332 }
333
334 gint
335 gtk_tree_child_position (GtkTree   *tree,
336                          GtkWidget *child)
337 {
338   GList *children;
339   gint pos;
340   
341   
342   g_return_val_if_fail (tree != NULL, -1);
343   g_return_val_if_fail (GTK_IS_TREE (tree), -1);
344   g_return_val_if_fail (child != NULL, -1);
345   
346   pos = 0;
347   children = tree->children;
348   
349   while (children)
350     {
351       if (child == GTK_WIDGET (children->data)) 
352         return pos;
353       
354       pos += 1;
355       children = children->next;
356     }
357   
358   
359   return -1;
360 }
361
362 void
363 gtk_tree_clear_items (GtkTree *tree,
364                       gint     start,
365                       gint     end)
366 {
367   GtkWidget *widget;
368   GList *clear_list;
369   GList *tmp_list;
370   guint nchildren;
371   guint index;
372   
373   g_return_if_fail (tree != NULL);
374   g_return_if_fail (GTK_IS_TREE (tree));
375   
376   nchildren = g_list_length (tree->children);
377   
378   if (nchildren > 0)
379     {
380       if ((end < 0) || (end > nchildren))
381         end = nchildren;
382       
383       if (start >= end)
384         return;
385       
386       tmp_list = g_list_nth (tree->children, start);
387       clear_list = NULL;
388       index = start;
389       while (tmp_list && index <= end)
390         {
391           widget = tmp_list->data;
392           tmp_list = tmp_list->next;
393           index++;
394           
395           clear_list = g_list_prepend (clear_list, widget);
396         }
397       
398       gtk_tree_remove_items (tree, clear_list);
399     }
400 }
401
402 static void
403 gtk_tree_destroy (GtkObject *object)
404 {
405   GtkTree *tree;
406   GtkWidget *child;
407   GList *children;
408   
409   g_return_if_fail (object != NULL);
410   g_return_if_fail (GTK_IS_TREE (object));
411   
412   tree = GTK_TREE (object);
413   
414   children = tree->children;
415   while (children)
416     {
417       child = children->data;
418       children = children->next;
419       
420       gtk_widget_ref (child);
421       gtk_widget_unparent (child);
422       gtk_widget_destroy (child);
423       gtk_widget_unref (child);
424     }
425   
426   g_list_free (tree->children);
427   tree->children = NULL;
428   
429   if (tree->root_tree == tree)
430     {
431       GList *node;
432       for (node = tree->selection; node; node = node->next)
433         gtk_widget_unref ((GtkWidget *)node->data);
434       g_list_free (tree->selection);
435       tree->selection = NULL;
436     }
437   
438   if (GTK_OBJECT_CLASS (parent_class)->destroy)
439     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
440 }
441
442 static void
443 gtk_tree_forall (GtkContainer *container,
444                  gboolean      include_internals,
445                  GtkCallback   callback,
446                  gpointer      callback_data)
447 {
448   GtkTree *tree;
449   GtkWidget *child;
450   GList *children;
451   
452   
453   g_return_if_fail (container != NULL);
454   g_return_if_fail (GTK_IS_TREE (container));
455   g_return_if_fail (callback != NULL);
456   
457   tree = GTK_TREE (container);
458   children = tree->children;
459   
460   while (children)
461     {
462       child = children->data;
463       children = children->next;
464       
465       (* callback) (child, callback_data);
466     }
467 }
468
469 static void
470 gtk_tree_unselect_all (GtkTree *tree)
471 {
472   GList *tmp_list, *selection;
473   GtkWidget *tmp_item;
474       
475   selection = tree->selection;
476   tree->selection = NULL;
477
478   tmp_list = selection;
479   while (tmp_list)
480     {
481       tmp_item = selection->data;
482
483       if (tmp_item->parent &&
484           GTK_IS_TREE (tmp_item->parent) &&
485           GTK_TREE (tmp_item->parent)->root_tree == tree)
486         gtk_tree_item_deselect (GTK_TREE_ITEM (tmp_item));
487
488       gtk_widget_unref (tmp_item);
489
490       tmp_list = tmp_list->next;
491     }
492
493   g_list_free (selection);
494 }
495
496 static void
497 gtk_tree_parent_set (GtkWidget *widget,
498                      GtkWidget *previous_parent)
499 {
500   GtkTree *tree = GTK_TREE (widget);
501   GtkWidget *child;
502   GList *children;
503   
504   if (widget->parent && GTK_IS_TREE (widget->parent))
505     {
506       gtk_tree_unselect_all (tree);
507       
508       /* set root tree for this tree */
509       tree->root_tree = GTK_TREE(widget->parent)->root_tree;
510       
511       tree->level = GTK_TREE(GTK_WIDGET(tree)->parent)->level+1;
512       tree->indent_value = GTK_TREE(GTK_WIDGET(tree)->parent)->indent_value;
513       tree->current_indent = GTK_TREE(GTK_WIDGET(tree)->parent)->current_indent + 
514         tree->indent_value;
515       tree->view_mode = GTK_TREE(GTK_WIDGET(tree)->parent)->view_mode;
516       tree->view_line = GTK_TREE(GTK_WIDGET(tree)->parent)->view_line;
517     }
518   else
519     {
520       tree->root_tree = tree;
521       
522       tree->level = 0;
523       tree->current_indent = 0;
524     }
525
526   children = tree->children;
527   while (children)
528     {
529       child = children->data;
530       children = children->next;
531       
532       if (GTK_TREE_ITEM (child)->subtree)
533         gtk_tree_parent_set (GTK_TREE_ITEM (child)->subtree, child);
534     }
535 }
536
537 static void
538 gtk_tree_map (GtkWidget *widget)
539 {
540   GtkTree *tree = GTK_TREE (widget);
541   GtkWidget *child;
542   GList *children;
543   
544   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
545   
546   children = tree->children;
547   while (children)
548     {
549       child = children->data;
550       children = children->next;
551       
552       if (GTK_WIDGET_VISIBLE (child) &&
553           !GTK_WIDGET_MAPPED (child))
554         gtk_widget_map (child);
555       
556       if (GTK_TREE_ITEM (child)->subtree)
557         {
558           child = GTK_WIDGET (GTK_TREE_ITEM (child)->subtree);
559           
560           if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child))
561             gtk_widget_map (child);
562         }
563     }
564
565   gdk_window_show (widget->window);
566 }
567
568 static gint
569 gtk_tree_motion_notify (GtkWidget      *widget,
570                         GdkEventMotion *event)
571 {
572   g_return_val_if_fail (widget != NULL, FALSE);
573   g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
574   g_return_val_if_fail (event != NULL, FALSE);
575   
576 #ifdef TREE_DEBUG
577   g_message("gtk_tree_motion_notify\n");
578 #endif /* TREE_DEBUG */
579   
580   return FALSE;
581 }
582
583 static void
584 gtk_tree_realize (GtkWidget *widget)
585 {
586   GdkWindowAttr attributes;
587   gint attributes_mask;
588   
589   
590   g_return_if_fail (widget != NULL);
591   g_return_if_fail (GTK_IS_TREE (widget));
592   
593   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
594   
595   attributes.window_type = GDK_WINDOW_CHILD;
596   attributes.x = widget->allocation.x;
597   attributes.y = widget->allocation.y;
598   attributes.width = widget->allocation.width;
599   attributes.height = widget->allocation.height;
600   attributes.wclass = GDK_INPUT_OUTPUT;
601   attributes.visual = gtk_widget_get_visual (widget);
602   attributes.colormap = gtk_widget_get_colormap (widget);
603   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
604   
605   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
606   
607   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
608   gdk_window_set_user_data (widget->window, widget);
609   
610   widget->style = gtk_style_attach (widget->style, widget->window);
611   gdk_window_set_background (widget->window, 
612                              &widget->style->base[GTK_STATE_NORMAL]);
613 }
614
615 void
616 gtk_tree_remove_item (GtkTree      *container,
617                       GtkWidget    *widget)
618 {
619   GList *item_list;
620   
621   g_return_if_fail (container != NULL);
622   g_return_if_fail (GTK_IS_TREE (container));
623   g_return_if_fail (widget != NULL);
624   g_return_if_fail (container == GTK_TREE (widget->parent));
625   
626   item_list = g_list_append (NULL, widget);
627   
628   gtk_tree_remove_items (GTK_TREE (container), item_list);
629   
630   g_list_free (item_list);
631 }
632
633 /* used by gtk_tree_remove_items to make the function independant of
634    order in list of items to remove.
635    Sort item bu depth in tree */
636 static gint 
637 gtk_tree_sort_item_by_depth(GtkWidget* a, GtkWidget* b)
638 {
639   if((GTK_TREE(a->parent)->level) < (GTK_TREE(b->parent)->level))
640     return 1;
641   if((GTK_TREE(a->parent)->level) > (GTK_TREE(b->parent)->level))
642     return -1;
643   
644   return 0;
645 }
646
647 void
648 gtk_tree_remove_items (GtkTree *tree,
649                        GList   *items)
650 {
651   GtkWidget *widget;
652   GList *selected_widgets;
653   GList *tmp_list;
654   GList *sorted_list;
655   GtkTree *real_tree;
656   GtkTree *root_tree;
657   
658   g_return_if_fail (tree != NULL);
659   g_return_if_fail (GTK_IS_TREE (tree));
660   
661 #ifdef TREE_DEBUG
662   g_message("+ gtk_tree_remove_items [ tree %#x items list %#x ]\n", (int)tree, (int)items);
663 #endif /* TREE_DEBUG */
664   
665   /* We may not yet be mapped, so we actively have to find our
666    * root tree
667    */
668   if (tree->root_tree)
669     root_tree = tree->root_tree;
670   else
671     {
672       GtkWidget *tmp = GTK_WIDGET (tree);
673       while (tmp->parent && GTK_IS_TREE (tmp->parent))
674         tmp = tmp->parent;
675       
676       root_tree = GTK_TREE (tmp);
677     }
678   
679   tmp_list = items;
680   selected_widgets = NULL;
681   sorted_list = NULL;
682   widget = NULL;
683   
684 #ifdef TREE_DEBUG
685   g_message("* sort list by depth\n");
686 #endif /* TREE_DEBUG */
687   
688   while (tmp_list)
689     {
690       
691 #ifdef TREE_DEBUG
692       g_message ("* item [%#x] depth [%d]\n", 
693                  (int)tmp_list->data,
694                  (int)GTK_TREE(GTK_WIDGET(tmp_list->data)->parent)->level);
695 #endif /* TREE_DEBUG */
696       
697       sorted_list = g_list_insert_sorted(sorted_list,
698                                          tmp_list->data,
699                                          (GCompareFunc)gtk_tree_sort_item_by_depth);
700       tmp_list = g_list_next(tmp_list);
701     }
702   
703 #ifdef TREE_DEBUG
704   /* print sorted list */
705   g_message("* sorted list result\n");
706   tmp_list = sorted_list;
707   while(tmp_list)
708     {
709       g_message("* item [%#x] depth [%d]\n", 
710                 (int)tmp_list->data,
711                 (int)GTK_TREE(GTK_WIDGET(tmp_list->data)->parent)->level);
712       tmp_list = g_list_next(tmp_list);
713     }
714 #endif /* TREE_DEBUG */
715   
716 #ifdef TREE_DEBUG
717   g_message("* scan sorted list\n");
718 #endif /* TREE_DEBUG */
719   
720   tmp_list = sorted_list;
721   while (tmp_list)
722     {
723       widget = tmp_list->data;
724       tmp_list = tmp_list->next;
725       
726 #ifdef TREE_DEBUG
727       g_message("* item [%#x] subtree [%#x]\n", 
728                 (int)widget, (int)GTK_TREE_ITEM_SUBTREE(widget));
729 #endif /* TREE_DEBUG */
730       
731       /* get real owner of this widget */
732       real_tree = GTK_TREE(widget->parent);
733 #ifdef TREE_DEBUG
734       g_message("* subtree having this widget [%#x]\n", (int)real_tree);
735 #endif /* TREE_DEBUG */
736       
737       
738       if (widget->state == GTK_STATE_SELECTED)
739         {
740           selected_widgets = g_list_prepend (selected_widgets, widget);
741 #ifdef TREE_DEBUG
742           g_message("* selected widget - adding it in selected list [%#x]\n",
743                     (int)selected_widgets);
744 #endif /* TREE_DEBUG */
745         }
746       
747       /* remove this item from its real parent */
748 #ifdef TREE_DEBUG
749       g_message("* remove widget from its owner tree\n");
750 #endif /* TREE_DEBUG */
751       real_tree->children = g_list_remove (real_tree->children, widget);
752       
753       /* remove subtree associate at this item if it exist */      
754       if(GTK_TREE_ITEM(widget)->subtree) 
755         {
756 #ifdef TREE_DEBUG
757           g_message("* remove subtree associate at this item [%#x]\n",
758                     (int) GTK_TREE_ITEM(widget)->subtree);
759 #endif /* TREE_DEBUG */
760           if (GTK_WIDGET_MAPPED (GTK_TREE_ITEM(widget)->subtree))
761             gtk_widget_unmap (GTK_TREE_ITEM(widget)->subtree);
762           
763           gtk_widget_unparent (GTK_TREE_ITEM(widget)->subtree);
764           GTK_TREE_ITEM(widget)->subtree = NULL;
765         }
766       
767       /* really remove widget for this item */
768 #ifdef TREE_DEBUG
769       g_message("* unmap and unparent widget [%#x]\n", (int)widget);
770 #endif /* TREE_DEBUG */
771       if (GTK_WIDGET_MAPPED (widget))
772         gtk_widget_unmap (widget);
773       
774       gtk_widget_unparent (widget);
775       
776       /* delete subtree if there is no children in it */
777       if(real_tree->children == NULL && 
778          real_tree != root_tree)
779         {
780 #ifdef TREE_DEBUG
781           g_message("* owner tree don't have children ... destroy it\n");
782 #endif /* TREE_DEBUG */
783           gtk_tree_item_remove_subtree(GTK_TREE_ITEM(real_tree->tree_owner));
784         }
785       
786 #ifdef TREE_DEBUG
787       g_message("* next item in list\n");
788 #endif /* TREE_DEBUG */
789     }
790   
791   if (selected_widgets)
792     {
793 #ifdef TREE_DEBUG
794       g_message("* scan selected item list\n");
795 #endif /* TREE_DEBUG */
796       tmp_list = selected_widgets;
797       while (tmp_list)
798         {
799           widget = tmp_list->data;
800           tmp_list = tmp_list->next;
801           
802 #ifdef TREE_DEBUG
803           g_message("* widget [%#x] subtree [%#x]\n", 
804                     (int)widget, (int)GTK_TREE_ITEM_SUBTREE(widget));
805 #endif /* TREE_DEBUG */
806           
807           /* remove widget of selection */
808           root_tree->selection = g_list_remove (root_tree->selection, widget);
809           
810           /* unref it to authorize is destruction */
811           gtk_widget_unref (widget);
812         }
813       
814       /* emit only one selection_changed signal */
815       gtk_signal_emit (GTK_OBJECT (root_tree), 
816                        tree_signals[SELECTION_CHANGED]);
817     }
818   
819 #ifdef TREE_DEBUG
820   g_message("* free selected_widgets list\n");
821 #endif /* TREE_DEBUG */
822   g_list_free (selected_widgets);
823   g_list_free (sorted_list);
824   
825   if (root_tree->children && !root_tree->selection &&
826       (root_tree->selection_mode == GTK_SELECTION_BROWSE))
827     {
828 #ifdef TREE_DEBUG
829       g_message("* BROWSE mode, select another item\n");
830 #endif /* TREE_DEBUG */
831       widget = root_tree->children->data;
832       gtk_tree_select_child (root_tree, widget);
833     }
834   
835   if (GTK_WIDGET_VISIBLE (root_tree))
836     {
837 #ifdef TREE_DEBUG
838       g_message("* query queue resizing for root_tree\n");
839 #endif /* TREE_DEBUG */      
840       gtk_widget_queue_resize (GTK_WIDGET (root_tree));
841     }
842 }
843
844 void
845 gtk_tree_select_child (GtkTree   *tree,
846                        GtkWidget *tree_item)
847 {
848   g_return_if_fail (tree != NULL);
849   g_return_if_fail (GTK_IS_TREE (tree));
850   g_return_if_fail (tree_item != NULL);
851   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
852   
853   gtk_signal_emit (GTK_OBJECT (tree), tree_signals[SELECT_CHILD], tree_item);
854 }
855
856 void
857 gtk_tree_select_item (GtkTree   *tree,
858                       gint       item)
859 {
860   GList *tmp_list;
861   
862   g_return_if_fail (tree != NULL);
863   g_return_if_fail (GTK_IS_TREE (tree));
864   
865   tmp_list = g_list_nth (tree->children, item);
866   if (tmp_list)
867     gtk_tree_select_child (tree, GTK_WIDGET (tmp_list->data));
868   
869 }
870
871 static void
872 gtk_tree_size_allocate (GtkWidget     *widget,
873                         GtkAllocation *allocation)
874 {
875   GtkTree *tree;
876   GtkWidget *child, *subtree;
877   GtkAllocation child_allocation;
878   GList *children;
879   
880   
881   g_return_if_fail (widget != NULL);
882   g_return_if_fail (GTK_IS_TREE (widget));
883   g_return_if_fail (allocation != NULL);
884   
885   tree = GTK_TREE (widget);
886   
887   widget->allocation = *allocation;
888   if (GTK_WIDGET_REALIZED (widget))
889     gdk_window_move_resize (widget->window,
890                             allocation->x, allocation->y,
891                             allocation->width, allocation->height);
892   
893   if (tree->children)
894     {
895       child_allocation.x = GTK_CONTAINER (tree)->border_width;
896       child_allocation.y = GTK_CONTAINER (tree)->border_width;
897       child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
898       
899       children = tree->children;
900       
901       while (children)
902         {
903           child = children->data;
904           children = children->next;
905           
906           if (GTK_WIDGET_VISIBLE (child))
907             {
908               GtkRequisition child_requisition;
909               gtk_widget_get_child_requisition (child, &child_requisition);
910               
911               child_allocation.height = child_requisition.height;
912               
913               gtk_widget_size_allocate (child, &child_allocation);
914               
915               child_allocation.y += child_allocation.height;
916               
917               if((subtree = GTK_TREE_ITEM(child)->subtree))
918                 if(GTK_WIDGET_VISIBLE (subtree))
919                   {
920                     child_allocation.height = subtree->requisition.height;
921                     gtk_widget_size_allocate (subtree, &child_allocation);
922                     child_allocation.y += child_allocation.height;
923                   }
924             }
925         }
926     }
927   
928 }
929
930 static void
931 gtk_tree_size_request (GtkWidget      *widget,
932                        GtkRequisition *requisition)
933 {
934   GtkTree *tree;
935   GtkWidget *child, *subtree;
936   GList *children;
937   GtkRequisition child_requisition;
938   
939   
940   g_return_if_fail (widget != NULL);
941   g_return_if_fail (GTK_IS_TREE (widget));
942   g_return_if_fail (requisition != NULL);
943   
944   tree = GTK_TREE (widget);
945   requisition->width = 0;
946   requisition->height = 0;
947   
948   children = tree->children;
949   while (children)
950     {
951       child = children->data;
952       children = children->next;
953       
954       if (GTK_WIDGET_VISIBLE (child))
955         {
956           gtk_widget_size_request (child, &child_requisition);
957           
958           requisition->width = MAX (requisition->width, child_requisition.width);
959           requisition->height += child_requisition.height;
960           
961           if((subtree = GTK_TREE_ITEM(child)->subtree) &&
962              GTK_WIDGET_VISIBLE (subtree))
963             {
964               gtk_widget_size_request (subtree, &child_requisition);
965               
966               requisition->width = MAX (requisition->width, 
967                                         child_requisition.width);
968               
969               requisition->height += child_requisition.height;
970             }
971         }
972     }
973   
974   requisition->width += GTK_CONTAINER (tree)->border_width * 2;
975   requisition->height += GTK_CONTAINER (tree)->border_width * 2;
976   
977   requisition->width = MAX (requisition->width, 1);
978   requisition->height = MAX (requisition->height, 1);
979   
980 }
981
982 static void
983 gtk_tree_unmap (GtkWidget *widget)
984 {
985   
986   g_return_if_fail (widget != NULL);
987   g_return_if_fail (GTK_IS_TREE (widget));
988   
989   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
990   gdk_window_hide (widget->window);
991   
992 }
993
994 void
995 gtk_tree_unselect_child (GtkTree   *tree,
996                          GtkWidget *tree_item)
997 {
998   g_return_if_fail (tree != NULL);
999   g_return_if_fail (GTK_IS_TREE (tree));
1000   g_return_if_fail (tree_item != NULL);
1001   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
1002   
1003   gtk_signal_emit (GTK_OBJECT (tree), tree_signals[UNSELECT_CHILD], tree_item);
1004 }
1005
1006 void
1007 gtk_tree_unselect_item (GtkTree *tree,
1008                         gint     item)
1009 {
1010   GList *tmp_list;
1011   
1012   g_return_if_fail (tree != NULL);
1013   g_return_if_fail (GTK_IS_TREE (tree));
1014   
1015   tmp_list = g_list_nth (tree->children, item);
1016   if (tmp_list)
1017     gtk_tree_unselect_child (tree, GTK_WIDGET (tmp_list->data));
1018   
1019 }
1020
1021 static void
1022 gtk_real_tree_select_child (GtkTree   *tree,
1023                             GtkWidget *child)
1024 {
1025   GList *selection, *root_selection;
1026   GList *tmp_list;
1027   GtkWidget *tmp_item;
1028   
1029   g_return_if_fail (tree != NULL);
1030   g_return_if_fail (GTK_IS_TREE (tree));
1031   g_return_if_fail (child != NULL);
1032   g_return_if_fail (GTK_IS_TREE_ITEM (child));
1033
1034   root_selection = tree->root_tree->selection;
1035   
1036   switch (tree->root_tree->selection_mode)
1037     {
1038     case GTK_SELECTION_SINGLE:
1039       
1040       selection = root_selection;
1041       
1042       /* remove old selection list */
1043       while (selection)
1044         {
1045           tmp_item = selection->data;
1046           
1047           if (tmp_item != child)
1048             {
1049               gtk_tree_item_deselect (GTK_TREE_ITEM (tmp_item));
1050               
1051               tmp_list = selection;
1052               selection = selection->next;
1053               
1054               root_selection = g_list_remove_link (root_selection, tmp_list);
1055               gtk_widget_unref (tmp_item);
1056               
1057               g_list_free (tmp_list);
1058             }
1059           else
1060             selection = selection->next;
1061         }
1062       
1063       if (child->state == GTK_STATE_NORMAL)
1064         {
1065           gtk_tree_item_select (GTK_TREE_ITEM (child));
1066           root_selection = g_list_prepend (root_selection, child);
1067           gtk_widget_ref (child);
1068         }
1069       else if (child->state == GTK_STATE_SELECTED)
1070         {
1071           gtk_tree_item_deselect (GTK_TREE_ITEM (child));
1072           root_selection = g_list_remove (root_selection, child);
1073           gtk_widget_unref (child);
1074         }
1075       
1076       tree->root_tree->selection = root_selection;
1077       
1078       gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1079                        tree_signals[SELECTION_CHANGED]);
1080       break;
1081       
1082       
1083     case GTK_SELECTION_BROWSE:
1084       selection = root_selection;
1085       
1086       while (selection)
1087         {
1088           tmp_item = selection->data;
1089           
1090           if (tmp_item != child)
1091             {
1092               gtk_tree_item_deselect (GTK_TREE_ITEM (tmp_item));
1093               
1094               tmp_list = selection;
1095               selection = selection->next;
1096               
1097               root_selection = g_list_remove_link (root_selection, tmp_list);
1098               gtk_widget_unref (tmp_item);
1099               
1100               g_list_free (tmp_list);
1101             }
1102           else
1103             selection = selection->next;
1104         }
1105       
1106       tree->root_tree->selection = root_selection;
1107       
1108       if (child->state == GTK_STATE_NORMAL)
1109         {
1110           gtk_tree_item_select (GTK_TREE_ITEM (child));
1111           root_selection = g_list_prepend (root_selection, child);
1112           gtk_widget_ref (child);
1113           tree->root_tree->selection = root_selection;
1114           gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1115                            tree_signals[SELECTION_CHANGED]);
1116         }
1117       break;
1118       
1119     case GTK_SELECTION_MULTIPLE:
1120       if (child->state == GTK_STATE_NORMAL)
1121         {
1122           gtk_tree_item_select (GTK_TREE_ITEM (child));
1123           root_selection = g_list_prepend (root_selection, child);
1124           gtk_widget_ref (child);
1125           tree->root_tree->selection = root_selection;
1126           gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1127                            tree_signals[SELECTION_CHANGED]);
1128         }
1129       else if (child->state == GTK_STATE_SELECTED)
1130         {
1131           gtk_tree_item_deselect (GTK_TREE_ITEM (child));
1132           root_selection = g_list_remove (root_selection, child);
1133           gtk_widget_unref (child);
1134           tree->root_tree->selection = root_selection;
1135           gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1136                            tree_signals[SELECTION_CHANGED]);
1137         }
1138       break;
1139       
1140     case GTK_SELECTION_EXTENDED:
1141       break;
1142     }
1143 }
1144
1145 static void
1146 gtk_real_tree_unselect_child (GtkTree   *tree,
1147                               GtkWidget *child)
1148 {
1149   g_return_if_fail (tree != NULL);
1150   g_return_if_fail (GTK_IS_TREE (tree));
1151   g_return_if_fail (child != NULL);
1152   g_return_if_fail (GTK_IS_TREE_ITEM (child));
1153   
1154   switch (tree->selection_mode)
1155     {
1156     case GTK_SELECTION_SINGLE:
1157     case GTK_SELECTION_MULTIPLE:
1158     case GTK_SELECTION_BROWSE:
1159       if (child->state == GTK_STATE_SELECTED)
1160         {
1161           GtkTree* root_tree = GTK_TREE_ROOT_TREE(tree);
1162           gtk_tree_item_deselect (GTK_TREE_ITEM (child));
1163           root_tree->selection = g_list_remove (root_tree->selection, child);
1164           gtk_widget_unref (child);
1165           gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
1166                            tree_signals[SELECTION_CHANGED]);
1167         }
1168       break;
1169       
1170     case GTK_SELECTION_EXTENDED:
1171       break;
1172     }
1173 }
1174
1175 void
1176 gtk_tree_set_selection_mode (GtkTree       *tree,
1177                              GtkSelectionMode mode) 
1178 {
1179   g_return_if_fail (tree != NULL);
1180   g_return_if_fail (GTK_IS_TREE (tree));
1181   
1182   tree->selection_mode = mode;
1183 }
1184
1185 void
1186 gtk_tree_set_view_mode (GtkTree       *tree,
1187                         GtkTreeViewMode mode) 
1188 {
1189   g_return_if_fail (tree != NULL);
1190   g_return_if_fail (GTK_IS_TREE (tree));
1191   
1192   tree->view_mode = mode;
1193 }
1194
1195 void
1196 gtk_tree_set_view_lines (GtkTree       *tree,
1197                          guint          flag) 
1198 {
1199   g_return_if_fail (tree != NULL);
1200   g_return_if_fail (GTK_IS_TREE (tree));
1201   
1202   tree->view_line = flag;
1203 }