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