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