]> Pileus Git - ~andy/gtk/blob - gtk/gtklist.c
fixup, so that enum values are looked up.
[~andy/gtk] / gtk / gtklist.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 "gtklist.h"
20 #include "gtklistitem.h"
21 #include "gtkmain.h"
22 #include "gtksignal.h"
23
24
25 enum {
26   SELECTION_CHANGED,
27   SELECT_CHILD,
28   UNSELECT_CHILD,
29   LAST_SIGNAL
30 };
31
32 static void gtk_list_class_init      (GtkListClass   *klass);
33 static void gtk_list_init            (GtkList        *list);
34 static void gtk_list_shutdown        (GtkObject      *object);
35 static void gtk_list_destroy         (GtkObject      *object);
36 static void gtk_list_map             (GtkWidget      *widget);
37 static void gtk_list_unmap           (GtkWidget      *widget);
38 static void gtk_list_realize         (GtkWidget      *widget);
39 static void gtk_list_draw            (GtkWidget      *widget,
40                                       GdkRectangle   *area);
41 static gint gtk_list_expose          (GtkWidget      *widget,
42                                       GdkEventExpose *event);
43 static gint gtk_list_enter_notify    (GtkWidget        *widget,
44                                       GdkEventCrossing *event);
45 static gint gtk_list_button_press    (GtkWidget      *widget,
46                                       GdkEventButton *event);
47 static gint gtk_list_button_release  (GtkWidget      *widget,
48                                       GdkEventButton *event);
49 static void gtk_list_size_request    (GtkWidget      *widget,
50                                       GtkRequisition *requisition);
51 static void gtk_list_size_allocate   (GtkWidget      *widget,
52                                       GtkAllocation  *allocation);
53 static void gtk_list_add             (GtkContainer   *container,
54                                       GtkWidget      *widget);
55 static void gtk_list_remove          (GtkContainer   *container,
56                                       GtkWidget      *widget);
57 static void gtk_list_foreach         (GtkContainer   *container,
58                                       GtkCallback     callback,
59                                       gpointer        callback_data);
60
61 static void gtk_real_list_select_child   (GtkList       *list,
62                                           GtkWidget     *child);
63 static void gtk_real_list_unselect_child (GtkList       *list,
64                                           GtkWidget     *child);
65
66 static GtkType gtk_list_child_type  (GtkContainer   *container);
67
68
69 static GtkContainerClass *parent_class = NULL;
70 static guint list_signals[LAST_SIGNAL] = { 0 };
71
72
73 GtkType
74 gtk_list_get_type (void)
75 {
76   static guint list_type = 0;
77
78   if (!list_type)
79     {
80       GtkTypeInfo list_info =
81       {
82         "GtkList",
83         sizeof (GtkList),
84         sizeof (GtkListClass),
85         (GtkClassInitFunc) gtk_list_class_init,
86         (GtkObjectInitFunc) gtk_list_init,
87         /* reserved_1 */ NULL,
88         /* reserved_2 */ NULL,
89         (GtkClassInitFunc) NULL,
90       };
91
92       list_type = gtk_type_unique (gtk_container_get_type (), &list_info);
93     }
94
95   return list_type;
96 }
97
98 static void
99 gtk_list_class_init (GtkListClass *class)
100 {
101   GtkObjectClass *object_class;
102   GtkWidgetClass *widget_class;
103   GtkContainerClass *container_class;
104
105   object_class = (GtkObjectClass*) class;
106   widget_class = (GtkWidgetClass*) class;
107   container_class = (GtkContainerClass*) class;
108
109   parent_class = gtk_type_class (gtk_container_get_type ());
110
111   list_signals[SELECTION_CHANGED] =
112     gtk_signal_new ("selection_changed",
113                     GTK_RUN_FIRST,
114                     object_class->type,
115                     GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
116                     gtk_marshal_NONE__NONE,
117                     GTK_TYPE_NONE, 0);
118   list_signals[SELECT_CHILD] =
119     gtk_signal_new ("select_child",
120                     GTK_RUN_FIRST,
121                     object_class->type,
122                     GTK_SIGNAL_OFFSET (GtkListClass, select_child),
123                     gtk_marshal_NONE__POINTER,
124                     GTK_TYPE_NONE, 1,
125                     GTK_TYPE_WIDGET);
126   list_signals[UNSELECT_CHILD] =
127     gtk_signal_new ("unselect_child",
128                     GTK_RUN_FIRST,
129                     object_class->type,
130                     GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
131                     gtk_marshal_NONE__POINTER,
132                     GTK_TYPE_NONE, 1,
133                     GTK_TYPE_WIDGET);
134
135   gtk_object_class_add_signals (object_class, list_signals, LAST_SIGNAL);
136
137   object_class->shutdown = gtk_list_shutdown;
138   object_class->destroy = gtk_list_destroy;
139
140   widget_class->map = gtk_list_map;
141   widget_class->unmap = gtk_list_unmap;
142   widget_class->realize = gtk_list_realize;
143   widget_class->draw = gtk_list_draw;
144   widget_class->expose_event = gtk_list_expose;
145   widget_class->button_press_event = gtk_list_button_press;
146   widget_class->button_release_event = gtk_list_button_release;
147   widget_class->enter_notify_event = gtk_list_enter_notify;
148   widget_class->size_request = gtk_list_size_request;
149   widget_class->size_allocate = gtk_list_size_allocate;
150
151   container_class->add = gtk_list_add;
152   container_class->remove = gtk_list_remove;
153   container_class->foreach = gtk_list_foreach;
154   container_class->child_type = gtk_list_child_type;
155
156   class->selection_changed = NULL;
157   class->select_child = gtk_real_list_select_child;
158   class->unselect_child = gtk_real_list_unselect_child;
159 }
160
161 static GtkType
162 gtk_list_child_type (GtkContainer     *container)
163 {
164   return GTK_TYPE_LIST_ITEM;
165 }
166
167 static void
168 gtk_list_init (GtkList *list)
169 {
170   list->children = NULL;
171   list->selection = NULL;
172   list->timer = 0;
173   list->selection_start_pos = 0;
174   list->selection_end_pos = 0;
175   list->selection_mode = GTK_SELECTION_SINGLE;
176   list->scroll_direction = 0;
177   list->button = 0;
178 }
179
180 GtkWidget*
181 gtk_list_new (void)
182 {
183   return GTK_WIDGET (gtk_type_new (gtk_list_get_type ()));
184 }
185
186 static void
187 gtk_list_shutdown (GtkObject *object)
188 {
189   gtk_list_clear_items (GTK_LIST (object), 0, -1);
190
191   GTK_OBJECT_CLASS (parent_class)->shutdown (object);
192 }
193
194 static void
195 gtk_list_destroy (GtkObject *object)
196 {
197   GList *node;
198
199   GtkList *list = GTK_LIST (object);
200
201   for (node = list->children; node; node = node->next)
202     {
203       GtkWidget *child;
204
205       child = (GtkWidget *)node->data;
206       gtk_widget_ref (child);
207       gtk_widget_unparent (child);
208       gtk_widget_destroy (child);
209       gtk_widget_unref (child);
210     }
211   g_list_free (list->children);
212   list->children = NULL;
213
214   for (node = list->selection; node; node = node->next)
215     {
216       GtkWidget *child;
217
218       child = (GtkWidget *)node->data;
219       gtk_widget_unref (child);
220     }
221   g_list_free (list->selection);
222   list->selection = NULL;
223
224   if (GTK_OBJECT_CLASS (parent_class)->destroy)
225     (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
226 }
227
228 static void
229 gtk_list_ungrab (GtkList *list)
230 {
231   g_return_if_fail (list != NULL);
232   g_return_if_fail (GTK_IS_LIST (list));
233
234   if (list->button)
235     {
236       list->button = 0;
237       gtk_grab_remove (GTK_WIDGET (list));
238       gdk_pointer_ungrab (GDK_CURRENT_TIME);
239     }
240 }
241
242 void
243 gtk_list_insert_items (GtkList *list,
244                        GList   *items,
245                        gint     position)
246 {
247   GtkWidget *widget;
248   GList *tmp_list;
249   GList *last;
250   gint nchildren;
251
252   g_return_if_fail (list != NULL);
253   g_return_if_fail (GTK_IS_LIST (list));
254
255   if (!items)
256     return;
257
258   gtk_list_ungrab (list);
259
260   tmp_list = items;
261   while (tmp_list)
262     {
263       widget = tmp_list->data;
264       tmp_list = tmp_list->next;
265
266       gtk_widget_set_parent (widget, GTK_WIDGET (list));
267
268       if (GTK_WIDGET_VISIBLE (widget->parent))
269         {
270           if (GTK_WIDGET_REALIZED (widget->parent) &&
271               !GTK_WIDGET_REALIZED (widget))
272             gtk_widget_realize (widget);
273
274           if (GTK_WIDGET_MAPPED (widget->parent) &&
275               !GTK_WIDGET_MAPPED (widget))
276             gtk_widget_map (widget);
277         }
278     }
279
280   nchildren = g_list_length (list->children);
281   if ((position < 0) || (position > nchildren))
282     position = nchildren;
283
284   if (position == nchildren)
285     {
286       if (list->children)
287         {
288           tmp_list = g_list_last (list->children);
289           tmp_list->next = items;
290           items->prev = tmp_list;
291         }
292       else
293         {
294           list->children = items;
295         }
296     }
297   else
298     {
299       tmp_list = g_list_nth (list->children, position);
300       last = g_list_last (items);
301
302       if (tmp_list->prev)
303         tmp_list->prev->next = items;
304       last->next = tmp_list;
305       items->prev = tmp_list->prev;
306       tmp_list->prev = last;
307
308       if (tmp_list == list->children)
309         list->children = items;
310     }
311
312   if (list->children && !list->selection &&
313       (list->selection_mode == GTK_SELECTION_BROWSE))
314     {
315       widget = list->children->data;
316       gtk_list_select_child (list, widget);
317     }
318
319   if (GTK_WIDGET_VISIBLE (list))
320     gtk_widget_queue_resize (GTK_WIDGET (list));
321 }
322
323 void
324 gtk_list_append_items (GtkList *list,
325                        GList   *items)
326 {
327   g_return_if_fail (list != NULL);
328   g_return_if_fail (GTK_IS_LIST (list));
329
330   gtk_list_insert_items (list, items, -1);
331 }
332
333 void
334 gtk_list_prepend_items (GtkList *list,
335                         GList   *items)
336 {
337   g_return_if_fail (list != NULL);
338   g_return_if_fail (GTK_IS_LIST (list));
339
340   gtk_list_insert_items (list, items, 0);
341 }
342
343 static void
344 gtk_list_remove_items_internal (GtkList  *list,
345                                 GList    *items,
346                                 gboolean no_unref)
347 {
348   GtkWidget *widget;
349   GList *selected_widgets;
350   GList *tmp_list;
351   
352   g_return_if_fail (list != NULL);
353   g_return_if_fail (GTK_IS_LIST (list));
354
355   if (!items)
356     return;
357
358   gtk_list_ungrab (list);
359   
360   tmp_list = items;
361   selected_widgets = NULL;
362   widget = NULL;
363   
364   while (tmp_list)
365     {
366       widget = tmp_list->data;
367       tmp_list = tmp_list->next;
368       
369       if (no_unref)
370         gtk_widget_ref (widget);
371
372       list->children = g_list_remove (list->children, widget);
373
374       if (widget->state == GTK_STATE_SELECTED)
375         selected_widgets = g_list_prepend (selected_widgets, widget);
376       else
377         gtk_widget_unparent (widget);
378     }
379   
380   if (selected_widgets)
381     {
382       tmp_list = selected_widgets;
383       while (tmp_list)
384         {
385           widget = tmp_list->data;
386           tmp_list = tmp_list->next;
387           
388           gtk_list_unselect_child (list, widget);
389
390           gtk_widget_unparent (widget);
391         }
392       
393       gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
394     }
395   
396   g_list_free (selected_widgets);
397   
398   if (list->children && !list->selection &&
399       (list->selection_mode == GTK_SELECTION_BROWSE))
400     {
401       widget = list->children->data;
402       gtk_list_select_child (list, widget);
403     }
404   
405   if (GTK_WIDGET_VISIBLE (list))
406     gtk_widget_queue_resize (GTK_WIDGET (list));
407 }
408
409 void
410 gtk_list_remove_items (GtkList  *list,
411                        GList    *items)
412 {
413   gtk_list_remove_items_internal (list, items, FALSE);
414 }
415
416 void
417 gtk_list_remove_items_no_unref (GtkList  *list,
418                                 GList    *items)
419 {
420   gtk_list_remove_items_internal (list, items, TRUE);
421 }
422
423 void
424 gtk_list_clear_items (GtkList *list,
425                       gint     start,
426                       gint     end)
427 {
428   GtkWidget *widget;
429   GList *start_list;
430   GList *end_list;
431   GList *tmp_list;
432   guint nchildren;
433
434   g_return_if_fail (list != NULL);
435   g_return_if_fail (GTK_IS_LIST (list));
436
437   nchildren = g_list_length (list->children);
438
439   if (nchildren > 0)
440     {
441       gboolean selection_changed;
442
443       if ((end < 0) || (end > nchildren))
444         end = nchildren;
445
446       if (start >= end)
447         return;
448
449       start_list = g_list_nth (list->children, start);
450       end_list = g_list_nth (list->children, end);
451
452       gtk_list_ungrab (list);
453
454       if (start_list->prev)
455         start_list->prev->next = end_list;
456       if (end_list && end_list->prev)
457         end_list->prev->next = NULL;
458       if (end_list)
459         end_list->prev = start_list->prev;
460       if (start_list == list->children)
461         list->children = end_list;
462
463       selection_changed = FALSE;
464       widget = NULL;
465       tmp_list = start_list;
466
467       while (tmp_list)
468         {
469           widget = tmp_list->data;
470           tmp_list = tmp_list->next;
471
472           if (widget->state == GTK_STATE_SELECTED)
473             {
474               gtk_list_unselect_child (list, widget);
475               selection_changed = TRUE;
476             }
477
478           gtk_widget_unparent (widget);
479         }
480
481       g_list_free (start_list);
482
483       if (list->children && !list->selection &&
484           (list->selection_mode == GTK_SELECTION_BROWSE))
485         {
486           widget = list->children->data;
487           gtk_list_select_child (list, widget);
488         }
489       else if (selection_changed)
490         gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
491
492       gtk_widget_queue_resize (GTK_WIDGET (list));
493     }
494 }
495
496 void
497 gtk_list_select_item (GtkList *list,
498                       gint     item)
499 {
500   GList *tmp_list;
501
502   g_return_if_fail (list != NULL);
503   g_return_if_fail (GTK_IS_LIST (list));
504
505   tmp_list = g_list_nth (list->children, item);
506   if (tmp_list)
507     gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
508 }
509
510 void
511 gtk_list_unselect_item (GtkList *list,
512                         gint     item)
513 {
514   GList *tmp_list;
515
516   g_return_if_fail (list != NULL);
517   g_return_if_fail (GTK_IS_LIST (list));
518
519   tmp_list = g_list_nth (list->children, item);
520   if (tmp_list)
521     gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
522 }
523
524 void
525 gtk_list_select_child (GtkList   *list,
526                        GtkWidget *child)
527 {
528   gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
529 }
530
531 void
532 gtk_list_unselect_child (GtkList   *list,
533                          GtkWidget *child)
534 {
535   gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
536 }
537
538 gint
539 gtk_list_child_position (GtkList   *list,
540                          GtkWidget *child)
541 {
542   GList *children;
543   gint pos;
544
545   g_return_val_if_fail (list != NULL, -1);
546   g_return_val_if_fail (GTK_IS_LIST (list), -1);
547   g_return_val_if_fail (child != NULL, -1);
548
549   pos = 0;
550   children = list->children;
551
552   while (children)
553     {
554       if (child == GTK_WIDGET (children->data))
555         return pos;
556
557       pos += 1;
558       children = children->next;
559     }
560
561   return -1;
562 }
563
564 void
565 gtk_list_set_selection_mode (GtkList          *list,
566                              GtkSelectionMode  mode)
567 {
568   g_return_if_fail (list != NULL);
569   g_return_if_fail (GTK_IS_LIST (list));
570
571   list->selection_mode = mode;
572 }
573
574
575 static void
576 gtk_list_map (GtkWidget *widget)
577 {
578   GtkList *list;
579   GtkWidget *child;
580   GList *children;
581
582   g_return_if_fail (widget != NULL);
583   g_return_if_fail (GTK_IS_LIST (widget));
584
585   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
586   list = GTK_LIST (widget);
587
588   gdk_window_show (widget->window);
589
590   children = list->children;
591   while (children)
592     {
593       child = children->data;
594       children = children->next;
595
596       if (GTK_WIDGET_VISIBLE (child) &&
597           !GTK_WIDGET_MAPPED (child))
598         gtk_widget_map (child);
599     }
600 }
601
602 static void
603 gtk_list_unmap (GtkWidget *widget)
604 {
605   g_return_if_fail (widget != NULL);
606   g_return_if_fail (GTK_IS_LIST (widget));
607
608   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
609   gdk_window_hide (widget->window);
610 }
611
612 static void
613 gtk_list_realize (GtkWidget *widget)
614 {
615   GdkWindowAttr attributes;
616   gint attributes_mask;
617
618   g_return_if_fail (widget != NULL);
619   g_return_if_fail (GTK_IS_LIST (widget));
620
621   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
622
623   attributes.window_type = GDK_WINDOW_CHILD;
624   attributes.x = widget->allocation.x;
625   attributes.y = widget->allocation.y;
626   attributes.width = widget->allocation.width;
627   attributes.height = widget->allocation.height;
628   attributes.wclass = GDK_INPUT_OUTPUT;
629   attributes.visual = gtk_widget_get_visual (widget);
630   attributes.colormap = gtk_widget_get_colormap (widget);
631   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
632
633   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
634
635   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
636   gdk_window_set_user_data (widget->window, widget);
637
638   widget->style = gtk_style_attach (widget->style, widget->window);
639   gdk_window_set_background (widget->window, 
640                              &widget->style->base[GTK_STATE_NORMAL]);
641 }
642
643 static void
644 gtk_list_draw (GtkWidget    *widget,
645                GdkRectangle *area)
646 {
647   GtkList *list;
648   GtkWidget *child;
649   GdkRectangle child_area;
650   GList *children;
651
652   g_return_if_fail (widget != NULL);
653   g_return_if_fail (GTK_IS_LIST (widget));
654   g_return_if_fail (area != NULL);
655
656   if (GTK_WIDGET_DRAWABLE (widget))
657     {
658       list = GTK_LIST (widget);
659
660       children = list->children;
661       while (children)
662         {
663           child = children->data;
664           children = children->next;
665
666           if (gtk_widget_intersect (child, area, &child_area))
667             gtk_widget_draw (child, &child_area);
668         }
669     }
670 }
671
672 static gint
673 gtk_list_expose (GtkWidget      *widget,
674                  GdkEventExpose *event)
675 {
676   GtkList *list;
677   GtkWidget *child;
678   GdkEventExpose child_event;
679   GList *children;
680
681   g_return_val_if_fail (widget != NULL, FALSE);
682   g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
683   g_return_val_if_fail (event != NULL, FALSE);
684
685   if (GTK_WIDGET_DRAWABLE (widget))
686     {
687       list = GTK_LIST (widget);
688
689       child_event = *event;
690
691       children = list->children;
692       while (children)
693         {
694           child = children->data;
695           children = children->next;
696
697           if (GTK_WIDGET_NO_WINDOW (child) &&
698               gtk_widget_intersect (child, &event->area, &child_event.area))
699             gtk_widget_event (child, (GdkEvent*) &child_event);
700         }
701     }
702
703   return FALSE;
704 }
705
706 static gint
707 gtk_list_enter_notify (GtkWidget        *widget,
708                        GdkEventCrossing *event)
709 {
710   GtkList *list;
711   GtkWidget *item;
712
713   g_return_val_if_fail (widget != NULL, FALSE);
714   g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
715   g_return_val_if_fail (event != NULL, FALSE);
716
717   list = GTK_LIST (widget);
718   item = gtk_get_event_widget ((GdkEvent*) event);
719
720   if (!list->button)
721     return FALSE;
722   
723   while (item && !GTK_IS_LIST_ITEM (item))
724     item = item->parent;
725
726   if (item && (item->parent == widget))
727     {
728       gtk_list_select_child (list, item);
729
730       if (!GTK_WIDGET_HAS_FOCUS (item))
731         gtk_widget_grab_focus (item);
732     }
733
734   return FALSE;
735 }
736
737 static gint
738 gtk_list_button_press (GtkWidget      *widget,
739                        GdkEventButton *event)
740 {
741   GtkList *list;
742   GtkWidget *item;
743
744   g_return_val_if_fail (widget != NULL, FALSE);
745   g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
746   g_return_val_if_fail (event != NULL, FALSE);
747
748   list = GTK_LIST (widget);
749   item = gtk_get_event_widget ((GdkEvent*) event);
750
751   if ((event->button != 1) || (list->button))
752     return FALSE;
753   
754   while (item && !GTK_IS_LIST_ITEM (item))
755     item = item->parent;
756
757   list->button = event->button;
758   gdk_pointer_grab (widget->window, TRUE,
759                     GDK_BUTTON_PRESS_MASK | 
760                     GDK_BUTTON_RELEASE_MASK,
761                     NULL, NULL, event->time);
762   gtk_grab_add (widget);
763
764   /* note: gtk_list_select_child() may cause the grab to be removed again!
765    */
766   if (item && (item->parent == widget))
767     gtk_list_select_child (list, item);
768   
769   return FALSE;
770 }
771
772 static gint
773 gtk_list_button_release (GtkWidget      *widget,
774                          GdkEventButton *event)
775 {
776   GtkList *list;
777   GtkWidget *item;
778
779   g_return_val_if_fail (widget != NULL, FALSE);
780   g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
781   g_return_val_if_fail (event != NULL, FALSE);
782
783   list = GTK_LIST (widget);
784   item = gtk_get_event_widget ((GdkEvent*) event);
785
786   if (list->button == event->button)
787     gtk_list_ungrab (list);
788
789   return FALSE;
790 }
791
792 static void
793 gtk_list_size_request (GtkWidget      *widget,
794                        GtkRequisition *requisition)
795 {
796   GtkList *list;
797   GtkWidget *child;
798   GList *children;
799
800   g_return_if_fail (widget != NULL);
801   g_return_if_fail (GTK_IS_LIST (widget));
802   g_return_if_fail (requisition != NULL);
803
804   list = GTK_LIST (widget);
805   requisition->width = 0;
806   requisition->height = 0;
807
808   children = list->children;
809   while (children)
810     {
811       child = children->data;
812       children = children->next;
813
814       if (GTK_WIDGET_VISIBLE (child))
815         {
816           gtk_widget_size_request (child, &child->requisition);
817
818           requisition->width = MAX (requisition->width, child->requisition.width);
819           requisition->height += child->requisition.height;
820         }
821     }
822
823   requisition->width += GTK_CONTAINER (list)->border_width * 2;
824   requisition->height += GTK_CONTAINER (list)->border_width * 2;
825
826   requisition->width = MAX (requisition->width, 1);
827   requisition->height = MAX (requisition->height, 1);
828 }
829
830 static void
831 gtk_list_size_allocate (GtkWidget     *widget,
832                         GtkAllocation *allocation)
833 {
834   GtkList *list;
835   GtkWidget *child;
836   GtkAllocation child_allocation;
837   GList *children;
838
839   g_return_if_fail (widget != NULL);
840   g_return_if_fail (GTK_IS_LIST (widget));
841   g_return_if_fail (allocation != NULL);
842
843   list = GTK_LIST (widget);
844
845   widget->allocation = *allocation;
846   if (GTK_WIDGET_REALIZED (widget))
847     gdk_window_move_resize (widget->window,
848                             allocation->x, allocation->y,
849                             allocation->width, allocation->height);
850
851   if (list->children)
852     {
853       child_allocation.x = GTK_CONTAINER (list)->border_width;
854       child_allocation.y = GTK_CONTAINER (list)->border_width;
855       child_allocation.width = MAX (1, allocation->width - child_allocation.x * 2);
856
857       children = list->children;
858
859       while (children)
860         {
861           child = children->data;
862           children = children->next;
863
864           if (GTK_WIDGET_VISIBLE (child))
865             {
866               child_allocation.height = child->requisition.height;
867
868               gtk_widget_size_allocate (child, &child_allocation);
869
870               child_allocation.y += child_allocation.height;
871             }
872         }
873     }
874 }
875
876 static void
877 gtk_list_add (GtkContainer *container,
878               GtkWidget    *widget)
879 {
880   GList *item_list;
881
882   g_return_if_fail (container != NULL);
883   g_return_if_fail (GTK_IS_LIST (container));
884   g_return_if_fail (widget != NULL);
885   g_return_if_fail (GTK_IS_LIST_ITEM (widget));
886
887   item_list = g_list_alloc ();
888   item_list->data = widget;
889   
890   gtk_list_append_items (GTK_LIST (container), item_list);
891 }
892
893 static void
894 gtk_list_remove (GtkContainer *container,
895                  GtkWidget    *widget)
896 {
897   GList *item_list;
898   
899   g_return_if_fail (container != NULL);
900   g_return_if_fail (GTK_IS_LIST (container));
901   g_return_if_fail (widget != NULL);
902   g_return_if_fail (container == GTK_CONTAINER (widget->parent));
903   
904   
905   item_list = g_list_alloc ();
906   item_list->data = widget;
907   
908   gtk_list_remove_items (GTK_LIST (container), item_list);
909   
910   g_list_free (item_list);
911 }
912
913 static void
914 gtk_list_foreach (GtkContainer *container,
915                   GtkCallback   callback,
916                   gpointer      callback_data)
917 {
918   GtkList *list;
919   GtkWidget *child;
920   GList *children;
921
922   g_return_if_fail (container != NULL);
923   g_return_if_fail (GTK_IS_LIST (container));
924   g_return_if_fail (callback != NULL);
925
926   list = GTK_LIST (container);
927   children = list->children;
928
929   while (children)
930     {
931       child = children->data;
932       children = children->next;
933
934       (* callback) (child, callback_data);
935     }
936 }
937
938
939 static void
940 gtk_real_list_select_child (GtkList   *list,
941                             GtkWidget *child)
942 {
943   GList *selection;
944   GList *tmp_list;
945   GtkWidget *tmp_item;
946
947   g_return_if_fail (list != NULL);
948   g_return_if_fail (GTK_IS_LIST (list));
949   g_return_if_fail (child != NULL);
950   g_return_if_fail (GTK_IS_LIST_ITEM (child));
951
952   switch (list->selection_mode)
953     {
954     case GTK_SELECTION_SINGLE:
955       selection = list->selection;
956
957       while (selection)
958         {
959           tmp_item = selection->data;
960
961           if (tmp_item != child)
962             {
963               tmp_list = selection;
964               selection = selection->next;
965
966               list->selection = g_list_remove_link (list->selection, tmp_list);
967               g_list_free (tmp_list);
968
969               gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item));
970               gtk_widget_unref (GTK_WIDGET (tmp_item));
971             }
972           else
973             selection = selection->next;
974         }
975
976       if (child->state == GTK_STATE_NORMAL)
977         {
978           list->selection = g_list_prepend (list->selection, child);
979           gtk_widget_ref (child);
980           gtk_list_item_select (GTK_LIST_ITEM (child));
981         }
982       else if (child->state == GTK_STATE_SELECTED)
983         {
984           list->selection = g_list_remove (list->selection, child);
985           gtk_list_item_deselect (GTK_LIST_ITEM (child));
986           gtk_widget_unref (child);
987         }
988
989       gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
990       break;
991
992     case GTK_SELECTION_BROWSE:
993       selection = list->selection;
994
995       while (selection)
996         {
997           tmp_item = selection->data;
998
999           if (tmp_item != child)
1000             {
1001               tmp_list = selection;
1002               selection = selection->next;
1003
1004               list->selection = g_list_remove_link (list->selection, tmp_list);
1005               g_list_free (tmp_list);
1006
1007               gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item));
1008               gtk_widget_unref (GTK_WIDGET (tmp_item));
1009             }
1010           else
1011             selection = selection->next;
1012         }
1013
1014       if (child->state == GTK_STATE_NORMAL)
1015         {
1016           list->selection = g_list_prepend (list->selection, child);
1017           gtk_widget_ref (child);
1018           gtk_list_item_select (GTK_LIST_ITEM (child));
1019           gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
1020         }
1021       break;
1022
1023     case GTK_SELECTION_MULTIPLE:
1024       if (child->state == GTK_STATE_NORMAL)
1025         {
1026           list->selection = g_list_prepend (list->selection, child);
1027           gtk_widget_ref (child);
1028           gtk_list_item_select (GTK_LIST_ITEM (child));
1029           gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
1030         }
1031       else if (child->state == GTK_STATE_SELECTED)
1032         {
1033           list->selection = g_list_remove (list->selection, child);
1034           gtk_list_item_deselect (GTK_LIST_ITEM (child));
1035           gtk_widget_unref (child);
1036           gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
1037         }
1038       break;
1039
1040     case GTK_SELECTION_EXTENDED:
1041       break;
1042     }
1043 }
1044
1045 static void
1046 gtk_real_list_unselect_child (GtkList   *list,
1047                               GtkWidget *child)
1048 {
1049   g_return_if_fail (list != NULL);
1050   g_return_if_fail (GTK_IS_LIST (list));
1051   g_return_if_fail (child != NULL);
1052   g_return_if_fail (GTK_IS_LIST_ITEM (child));
1053
1054   switch (list->selection_mode)
1055     {
1056     case GTK_SELECTION_SINGLE:
1057     case GTK_SELECTION_MULTIPLE:
1058     case GTK_SELECTION_BROWSE:
1059       if (child->state == GTK_STATE_SELECTED)
1060         {
1061           list->selection = g_list_remove (list->selection, child);
1062           gtk_list_item_deselect (GTK_LIST_ITEM (child));
1063           gtk_widget_unref (child);
1064           gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
1065         }
1066       break;
1067
1068     case GTK_SELECTION_EXTENDED:
1069       break;
1070     }
1071 }