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