]> Pileus Git - ~andy/gtk/blob - gtk/gtkbox.c
fixed signals with GDK_TYPE_DRAG_CONTEXT, it needs to be marshaled as an
[~andy/gtk] / gtk / gtkbox.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 Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtkbox.h"
28
29 enum {
30   ARG_0,
31   ARG_SPACING,
32   ARG_HOMOGENEOUS
33 };
34
35 enum {
36   CHILD_ARG_0,
37   CHILD_ARG_EXPAND,
38   CHILD_ARG_FILL,
39   CHILD_ARG_PADDING,
40   CHILD_ARG_PACK_TYPE,
41   CHILD_ARG_POSITION
42 };
43
44 static void gtk_box_class_init (GtkBoxClass    *klass);
45 static void gtk_box_init       (GtkBox         *box);
46 static void gtk_box_get_arg    (GtkObject      *object,
47                                 GtkArg         *arg,
48                                 guint           arg_id);
49 static void gtk_box_set_arg    (GtkObject      *object,
50                                 GtkArg         *arg,
51                                 guint           arg_id);
52 static void gtk_box_map        (GtkWidget      *widget);
53 static void gtk_box_unmap      (GtkWidget      *widget);
54 static void gtk_box_add        (GtkContainer   *container,
55                                 GtkWidget      *widget);
56 static void gtk_box_remove     (GtkContainer   *container,
57                                 GtkWidget      *widget);
58 static void gtk_box_forall     (GtkContainer   *container,
59                                 gboolean        include_internals,
60                                 GtkCallback     callback,
61                                 gpointer        callback_data);
62 static void gtk_box_set_child_arg (GtkContainer   *container,
63                                    GtkWidget      *child,
64                                    GtkArg         *arg,
65                                    guint           arg_id);
66 static void gtk_box_get_child_arg (GtkContainer   *container,
67                                    GtkWidget      *child,
68                                    GtkArg         *arg,
69                                    guint           arg_id);
70 static GtkType gtk_box_child_type (GtkContainer   *container);
71      
72
73 static GtkContainerClass *parent_class = NULL;
74
75
76 GtkType
77 gtk_box_get_type (void)
78 {
79   static GtkType box_type = 0;
80
81   if (!box_type)
82     {
83       static const GtkTypeInfo box_info =
84       {
85         "GtkBox",
86         sizeof (GtkBox),
87         sizeof (GtkBoxClass),
88         (GtkClassInitFunc) gtk_box_class_init,
89         (GtkObjectInitFunc) gtk_box_init,
90         /* reserved_1 */ NULL,
91         /* reserved_2 */ NULL,
92         (GtkClassInitFunc) NULL,
93       };
94
95       box_type = gtk_type_unique (GTK_TYPE_CONTAINER, &box_info);
96     }
97
98   return box_type;
99 }
100
101 static void
102 gtk_box_class_init (GtkBoxClass *class)
103 {
104   GtkObjectClass *object_class;
105   GtkWidgetClass *widget_class;
106   GtkContainerClass *container_class;
107
108   object_class = (GtkObjectClass*) class;
109   widget_class = (GtkWidgetClass*) class;
110   container_class = (GtkContainerClass*) class;
111
112   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
113
114   gtk_object_add_arg_type ("GtkBox::spacing", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_SPACING);
115   gtk_object_add_arg_type ("GtkBox::homogeneous", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS);
116   gtk_container_add_child_arg_type ("GtkBox::expand", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_EXPAND);
117   gtk_container_add_child_arg_type ("GtkBox::fill", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_FILL);
118   gtk_container_add_child_arg_type ("GtkBox::padding", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_PADDING);
119   gtk_container_add_child_arg_type ("GtkBox::pack_type", GTK_TYPE_PACK_TYPE, GTK_ARG_READWRITE, CHILD_ARG_PACK_TYPE);
120   gtk_container_add_child_arg_type ("GtkBox::position", GTK_TYPE_INT, GTK_ARG_READWRITE, CHILD_ARG_POSITION);
121
122   object_class->set_arg = gtk_box_set_arg;
123   object_class->get_arg = gtk_box_get_arg;
124
125   widget_class->map = gtk_box_map;
126   widget_class->unmap = gtk_box_unmap;
127
128   container_class->add = gtk_box_add;
129   container_class->remove = gtk_box_remove;
130   container_class->forall = gtk_box_forall;
131   container_class->child_type = gtk_box_child_type;
132   container_class->set_child_arg = gtk_box_set_child_arg;
133   container_class->get_child_arg = gtk_box_get_child_arg;
134 }
135
136 static void
137 gtk_box_init (GtkBox *box)
138 {
139   GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW);
140
141   box->children = NULL;
142   box->spacing = 0;
143   box->homogeneous = FALSE;
144 }
145
146 static void
147 gtk_box_set_arg (GtkObject    *object,
148                  GtkArg       *arg,
149                  guint         arg_id)
150 {
151   GtkBox *box;
152
153   box = GTK_BOX (object);
154
155   switch (arg_id)
156     {
157     case ARG_SPACING:
158       gtk_box_set_spacing (box, GTK_VALUE_INT (*arg));
159       break;
160     case ARG_HOMOGENEOUS:
161       gtk_box_set_homogeneous (box, GTK_VALUE_BOOL (*arg));
162       break;
163     default:
164       break;
165     }
166 }
167
168 static void
169 gtk_box_get_arg (GtkObject    *object,
170                  GtkArg       *arg,
171                  guint         arg_id)
172 {
173   GtkBox *box;
174
175   box = GTK_BOX (object);
176
177   switch (arg_id)
178     {
179     case ARG_SPACING:
180       GTK_VALUE_INT (*arg) = box->spacing;
181       break;
182     case ARG_HOMOGENEOUS:
183       GTK_VALUE_BOOL (*arg) = box->homogeneous;
184       break;
185     default:
186       arg->type = GTK_TYPE_INVALID;
187       break;
188     }
189 }
190
191 static GtkType
192 gtk_box_child_type      (GtkContainer   *container)
193 {
194   return GTK_TYPE_WIDGET;
195 }
196
197 static void
198 gtk_box_set_child_arg (GtkContainer   *container,
199                        GtkWidget      *child,
200                        GtkArg         *arg,
201                        guint           arg_id)
202 {
203   gboolean expand = 0;
204   gboolean fill = 0;
205   guint padding = 0;
206   GtkPackType pack_type = 0;
207
208   if (arg_id != CHILD_ARG_POSITION)
209     gtk_box_query_child_packing (GTK_BOX (container),
210                                  child,
211                                  &expand,
212                                  &fill,
213                                  &padding,
214                                  &pack_type);
215   
216   switch (arg_id)
217     {
218     case CHILD_ARG_EXPAND:
219       gtk_box_set_child_packing (GTK_BOX (container),
220                                  child,
221                                  GTK_VALUE_BOOL (*arg),
222                                  fill,
223                                  padding,
224                                  pack_type);
225       break;
226     case CHILD_ARG_FILL:
227       gtk_box_set_child_packing (GTK_BOX (container),
228                                  child,
229                                  expand,
230                                  GTK_VALUE_BOOL (*arg),
231                                  padding,
232                                  pack_type);
233       break;
234     case CHILD_ARG_PADDING:
235       gtk_box_set_child_packing (GTK_BOX (container),
236                                  child,
237                                  expand,
238                                  fill,
239                                  GTK_VALUE_UINT (*arg),
240                                  pack_type);
241       break;
242     case CHILD_ARG_PACK_TYPE:
243       gtk_box_set_child_packing (GTK_BOX (container),
244                                  child,
245                                  expand,
246                                  fill,
247                                  padding,
248                                  GTK_VALUE_ENUM (*arg));
249       break;
250     case CHILD_ARG_POSITION:
251       gtk_box_reorder_child (GTK_BOX (container),
252                              child,
253                              GTK_VALUE_INT (*arg));
254       break;
255     default:
256       break;
257     }
258 }
259
260 static void
261 gtk_box_get_child_arg (GtkContainer   *container,
262                        GtkWidget      *child,
263                        GtkArg         *arg,
264                        guint           arg_id)
265 {
266   gboolean expand = 0;
267   gboolean fill = 0;
268   guint padding = 0;
269   GtkPackType pack_type = 0;
270   GList *list;
271
272   if (arg_id != CHILD_ARG_POSITION)
273     gtk_box_query_child_packing (GTK_BOX (container),
274                                  child,
275                                  &expand,
276                                  &fill,
277                                  &padding,
278                                  &pack_type);
279   
280   switch (arg_id)
281     {
282     case CHILD_ARG_EXPAND:
283       GTK_VALUE_BOOL (*arg) = expand;
284       break;
285     case CHILD_ARG_FILL:
286       GTK_VALUE_BOOL (*arg) = fill;
287       break;
288     case CHILD_ARG_PADDING:
289       GTK_VALUE_UINT (*arg) = padding;
290       break;
291     case CHILD_ARG_PACK_TYPE:
292       GTK_VALUE_ENUM (*arg) = pack_type;
293       break;
294     case CHILD_ARG_POSITION:
295       GTK_VALUE_INT (*arg) = 0;
296       for (list = GTK_BOX (container)->children; list; list = list->next)
297         {
298           GtkBoxChild *child_entry;
299
300           child_entry = list->data;
301           if (child_entry->widget == child)
302             break;
303           GTK_VALUE_INT (*arg)++;
304         }
305       if (!list)
306         GTK_VALUE_INT (*arg) = -1;
307       break;
308     default:
309       arg->type = GTK_TYPE_INVALID;
310       break;
311     }
312 }
313
314 void
315 gtk_box_pack_start (GtkBox    *box,
316                     GtkWidget *child,
317                     gboolean   expand,
318                     gboolean   fill,
319                     guint      padding)
320 {
321   GtkBoxChild *child_info;
322
323   g_return_if_fail (box != NULL);
324   g_return_if_fail (GTK_IS_BOX (box));
325   g_return_if_fail (child != NULL);
326   g_return_if_fail (child->parent == NULL);
327
328   child_info = g_new (GtkBoxChild, 1);
329   child_info->widget = child;
330   child_info->padding = padding;
331   child_info->expand = expand ? TRUE : FALSE;
332   child_info->fill = fill ? TRUE : FALSE;
333   child_info->pack = GTK_PACK_START;
334
335   box->children = g_list_append (box->children, child_info);
336
337   gtk_widget_set_parent (child, GTK_WIDGET (box));
338   
339   if (GTK_WIDGET_REALIZED (box))
340     gtk_widget_realize (child);
341
342   if (GTK_WIDGET_VISIBLE (box) && GTK_WIDGET_VISIBLE (child))
343     {
344       if (GTK_WIDGET_MAPPED (box))
345         gtk_widget_map (child);
346
347       gtk_widget_queue_resize (child);
348     }
349 }
350
351 void
352 gtk_box_pack_end (GtkBox    *box,
353                   GtkWidget *child,
354                   gboolean   expand,
355                   gboolean   fill,
356                   guint      padding)
357 {
358   GtkBoxChild *child_info;
359
360   g_return_if_fail (box != NULL);
361   g_return_if_fail (GTK_IS_BOX (box));
362   g_return_if_fail (child != NULL);
363   g_return_if_fail (child->parent == NULL);
364
365   child_info = g_new (GtkBoxChild, 1);
366   child_info->widget = child;
367   child_info->padding = padding;
368   child_info->expand = expand ? TRUE : FALSE;
369   child_info->fill = fill ? TRUE : FALSE;
370   child_info->pack = GTK_PACK_END;
371
372   box->children = g_list_append (box->children, child_info);
373
374   gtk_widget_set_parent (child, GTK_WIDGET (box));
375
376   if (GTK_WIDGET_REALIZED (box))
377     gtk_widget_realize (child);
378
379   if (GTK_WIDGET_VISIBLE (box) && GTK_WIDGET_VISIBLE (child))
380     {
381       if (GTK_WIDGET_MAPPED (box))
382         gtk_widget_map (child);
383
384       gtk_widget_queue_resize (child);
385     }
386 }
387
388 void
389 gtk_box_pack_start_defaults (GtkBox    *box,
390                              GtkWidget *child)
391 {
392   g_return_if_fail (box != NULL);
393   g_return_if_fail (GTK_IS_BOX (box));
394   g_return_if_fail (child != NULL);
395
396   gtk_box_pack_start (box, child, TRUE, TRUE, 0);
397 }
398
399 void
400 gtk_box_pack_end_defaults (GtkBox    *box,
401                            GtkWidget *child)
402 {
403   g_return_if_fail (box != NULL);
404   g_return_if_fail (GTK_IS_BOX (box));
405   g_return_if_fail (child != NULL);
406
407   gtk_box_pack_end (box, child, TRUE, TRUE, 0);
408 }
409
410 void
411 gtk_box_set_homogeneous (GtkBox  *box,
412                          gboolean homogeneous)
413 {
414   g_return_if_fail (box != NULL);
415   g_return_if_fail (GTK_IS_BOX (box));
416
417   if ((homogeneous ? TRUE : FALSE) != box->homogeneous)
418     {
419       box->homogeneous = homogeneous ? TRUE : FALSE;
420       gtk_widget_queue_resize (GTK_WIDGET (box));
421     }
422 }
423
424 void
425 gtk_box_set_spacing (GtkBox *box,
426                      gint    spacing)
427 {
428   g_return_if_fail (box != NULL);
429   g_return_if_fail (GTK_IS_BOX (box));
430
431   if (spacing != box->spacing)
432     {
433       box->spacing = spacing;
434       gtk_widget_queue_resize (GTK_WIDGET (box));
435     }
436 }
437
438 /**
439  * gtk_box_get_spacing:
440  * @box: a #GtkBox
441  * 
442  * Gets the value set by gtk_box_set_spacing().
443  * 
444  * Return value: spacing between children
445  **/
446 gint
447 gtk_box_get_spacing (GtkBox *box)
448 {
449   g_return_val_if_fail (GTK_IS_BOX (box), 0);
450
451   return box->spacing;
452 }
453
454 void
455 gtk_box_reorder_child (GtkBox                   *box,
456                        GtkWidget                *child,
457                        gint                      position)
458 {
459   GList *list;
460
461   g_return_if_fail (box != NULL);
462   g_return_if_fail (GTK_IS_BOX (box));
463   g_return_if_fail (child != NULL);
464
465   list = box->children;
466   while (list)
467     {
468       GtkBoxChild *child_info;
469
470       child_info = list->data;
471       if (child_info->widget == child)
472         break;
473
474       list = list->next;
475     }
476
477   if (list && box->children->next)
478     {
479       GList *tmp_list;
480
481       if (list->next)
482         list->next->prev = list->prev;
483       if (list->prev)
484         list->prev->next = list->next;
485       else
486         box->children = list->next;
487
488       tmp_list = box->children;
489       while (position && tmp_list->next)
490         {
491           position--;
492           tmp_list = tmp_list->next;
493         }
494
495       if (position)
496         {
497           tmp_list->next = list;
498           list->prev = tmp_list;
499           list->next = NULL;
500         }
501       else
502         {
503           if (tmp_list->prev)
504             tmp_list->prev->next = list;
505           else
506             box->children = list;
507           list->prev = tmp_list->prev;
508           tmp_list->prev = list;
509           list->next = tmp_list;
510         }
511
512       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
513         gtk_widget_queue_resize (child);
514     }
515 }
516
517 void
518 gtk_box_query_child_packing (GtkBox             *box,
519                              GtkWidget          *child,
520                              gboolean           *expand,
521                              gboolean           *fill,
522                              guint              *padding,
523                              GtkPackType        *pack_type)
524 {
525   GList *list;
526   GtkBoxChild *child_info = NULL;
527
528   g_return_if_fail (box != NULL);
529   g_return_if_fail (GTK_IS_BOX (box));
530   g_return_if_fail (child != NULL);
531
532   list = box->children;
533   while (list)
534     {
535       child_info = list->data;
536       if (child_info->widget == child)
537         break;
538
539       list = list->next;
540     }
541
542   if (list)
543     {
544       if (expand)
545         *expand = child_info->expand;
546       if (fill)
547         *fill = child_info->fill;
548       if (padding)
549         *padding = child_info->padding;
550       if (pack_type)
551         *pack_type = child_info->pack;
552     }
553 }
554
555 void
556 gtk_box_set_child_packing (GtkBox               *box,
557                            GtkWidget            *child,
558                            gboolean              expand,
559                            gboolean              fill,
560                            guint                 padding,
561                            GtkPackType           pack_type)
562 {
563   GList *list;
564   GtkBoxChild *child_info = NULL;
565
566   g_return_if_fail (box != NULL);
567   g_return_if_fail (GTK_IS_BOX (box));
568   g_return_if_fail (child != NULL);
569
570   list = box->children;
571   while (list)
572     {
573       child_info = list->data;
574       if (child_info->widget == child)
575         break;
576
577       list = list->next;
578     }
579
580   if (list)
581     {
582       child_info->expand = expand != FALSE;
583       child_info->fill = fill != FALSE;
584       child_info->padding = padding;
585       if (pack_type == GTK_PACK_END)
586         child_info->pack = GTK_PACK_END;
587       else
588         child_info->pack = GTK_PACK_START;
589
590       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
591         gtk_widget_queue_resize (child);
592     }
593 }
594
595 static void
596 gtk_box_map (GtkWidget *widget)
597 {
598   GtkBox *box;
599   GtkBoxChild *child;
600   GList *children;
601
602   g_return_if_fail (widget != NULL);
603   g_return_if_fail (GTK_IS_BOX (widget));
604
605   box = GTK_BOX (widget);
606   GTK_WIDGET_SET_FLAGS (box, GTK_MAPPED);
607
608   children = box->children;
609   while (children)
610     {
611       child = children->data;
612       children = children->next;
613
614       if (GTK_WIDGET_VISIBLE (child->widget) &&
615           !GTK_WIDGET_MAPPED (child->widget))
616         gtk_widget_map (child->widget);
617     }
618 }
619
620 static void
621 gtk_box_unmap (GtkWidget *widget)
622 {
623   GtkBox *box;
624   GtkBoxChild *child;
625   GList *children;
626
627   g_return_if_fail (widget != NULL);
628   g_return_if_fail (GTK_IS_BOX (widget));
629
630   box = GTK_BOX (widget);
631   GTK_WIDGET_UNSET_FLAGS (box, GTK_MAPPED);
632
633   children = box->children;
634   while (children)
635     {
636       child = children->data;
637       children = children->next;
638
639       if (GTK_WIDGET_VISIBLE (child->widget) &&
640           GTK_WIDGET_MAPPED (child->widget))
641         gtk_widget_unmap (child->widget);
642     }
643 }
644
645 static void
646 gtk_box_add (GtkContainer *container,
647              GtkWidget    *widget)
648 {
649   g_return_if_fail (container != NULL);
650   g_return_if_fail (GTK_IS_BOX (container));
651   g_return_if_fail (widget != NULL);
652
653   gtk_box_pack_start_defaults (GTK_BOX (container), widget);
654 }
655
656 static void
657 gtk_box_remove (GtkContainer *container,
658                 GtkWidget    *widget)
659 {
660   GtkBox *box;
661   GtkBoxChild *child;
662   GList *children;
663
664   g_return_if_fail (container != NULL);
665   g_return_if_fail (GTK_IS_BOX (container));
666   g_return_if_fail (widget != NULL);
667
668   box = GTK_BOX (container);
669
670   children = box->children;
671   while (children)
672     {
673       child = children->data;
674
675       if (child->widget == widget)
676         {
677           gboolean was_visible;
678
679           was_visible = GTK_WIDGET_VISIBLE (widget);
680           gtk_widget_unparent (widget);
681
682           box->children = g_list_remove_link (box->children, children);
683           g_list_free (children);
684           g_free (child);
685
686           /* queue resize regardless of GTK_WIDGET_VISIBLE (container),
687            * since that's what is needed by toplevels.
688            */
689           if (was_visible)
690             gtk_widget_queue_resize (GTK_WIDGET (container));
691
692           break;
693         }
694
695       children = children->next;
696     }
697 }
698
699 static void
700 gtk_box_forall (GtkContainer *container,
701                 gboolean      include_internals,
702                 GtkCallback   callback,
703                 gpointer      callback_data)
704 {
705   GtkBox *box;
706   GtkBoxChild *child;
707   GList *children;
708
709   g_return_if_fail (container != NULL);
710   g_return_if_fail (GTK_IS_BOX (container));
711   g_return_if_fail (callback != NULL);
712
713   box = GTK_BOX (container);
714
715   children = box->children;
716   while (children)
717     {
718       child = children->data;
719       children = children->next;
720
721       if (child->pack == GTK_PACK_START)
722         (* callback) (child->widget, callback_data);
723     }
724
725   children = g_list_last (box->children);
726   while (children)
727     {
728       child = children->data;
729       children = children->prev;
730
731       if (child->pack == GTK_PACK_END)
732         (* callback) (child->widget, callback_data);
733     }
734 }