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