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