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