]> Pileus Git - ~andy/gtk/blob - gtk/gtkbin.c
Fixed gtkbin.c:parent_extended_layout_iface to be static.
[~andy/gtk] / gtk / gtkbin.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 "config.h"
28 #include "gtkbin.h"
29 #include "gtkextendedlayout.h"
30 #include "gtkintl.h"
31 #include "gtkalias.h"
32
33 static void gtk_bin_add         (GtkContainer   *container,
34                                  GtkWidget      *widget);
35 static void gtk_bin_remove      (GtkContainer   *container,
36                                  GtkWidget      *widget);
37 static void gtk_bin_forall      (GtkContainer   *container,
38                                  gboolean       include_internals,
39                                  GtkCallback     callback,
40                                  gpointer        callback_data);
41 static GType gtk_bin_child_type (GtkContainer   *container);
42
43
44 static void gtk_bin_extended_layout_init  (GtkExtendedLayoutIface *iface);
45 static void gtk_bin_get_width_for_height  (GtkExtendedLayout      *layout,
46                                            gint                    height,
47                                            gint                   *minimum_width,
48                                            gint                   *natural_width);
49 static void gtk_bin_get_height_for_width  (GtkExtendedLayout      *layout,
50                                            gint                    width,
51                                            gint                   *minimum_height,
52                                            gint                   *natural_height);
53
54
55 static GtkExtendedLayoutIface *parent_extended_layout_iface;
56
57 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkBin, gtk_bin, GTK_TYPE_CONTAINER,
58                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
59                                                          gtk_bin_extended_layout_init))
60
61 static void
62 gtk_bin_class_init (GtkBinClass *class)
63 {
64   GtkContainerClass *container_class;
65
66   container_class = (GtkContainerClass*) class;
67
68   container_class->add = gtk_bin_add;
69   container_class->remove = gtk_bin_remove;
70   container_class->forall = gtk_bin_forall;
71   container_class->child_type = gtk_bin_child_type;
72 }
73
74 static void
75 gtk_bin_init (GtkBin *bin)
76 {
77   gtk_widget_set_has_window (GTK_WIDGET (bin), FALSE);
78
79   bin->child = NULL;
80 }
81
82
83 static GType
84 gtk_bin_child_type (GtkContainer *container)
85 {
86   if (!GTK_BIN (container)->child)
87     return GTK_TYPE_WIDGET;
88   else
89     return G_TYPE_NONE;
90 }
91
92 static void
93 gtk_bin_add (GtkContainer *container,
94              GtkWidget    *child)
95 {
96   GtkBin *bin = GTK_BIN (container);
97
98   if (bin->child != NULL)
99     {
100       g_warning ("Attempting to add a widget with type %s to a %s, "
101                  "but as a GtkBin subclass a %s can only contain one widget at a time; "
102                  "it already contains a widget of type %s",
103                  g_type_name (G_OBJECT_TYPE (child)),
104                  g_type_name (G_OBJECT_TYPE (bin)),
105                  g_type_name (G_OBJECT_TYPE (bin)),
106                  g_type_name (G_OBJECT_TYPE (bin->child)));
107       return;
108     }
109
110   gtk_widget_set_parent (child, GTK_WIDGET (bin));
111   bin->child = child;
112 }
113
114 static void
115 gtk_bin_remove (GtkContainer *container,
116                 GtkWidget    *child)
117 {
118   GtkBin *bin = GTK_BIN (container);
119   gboolean widget_was_visible;
120
121   g_return_if_fail (bin->child == child);
122
123   widget_was_visible = gtk_widget_get_visible (child);
124   
125   gtk_widget_unparent (child);
126   bin->child = NULL;
127   
128   /* queue resize regardless of gtk_widget_get_visible (container),
129    * since that's what is needed by toplevels, which derive from GtkBin.
130    */
131   if (widget_was_visible)
132     gtk_widget_queue_resize (GTK_WIDGET (container));
133 }
134
135 static void
136 gtk_bin_forall (GtkContainer *container,
137                 gboolean      include_internals,
138                 GtkCallback   callback,
139                 gpointer      callback_data)
140 {
141   GtkBin *bin = GTK_BIN (container);
142
143   if (bin->child)
144     (* callback) (bin->child, callback_data);
145 }
146
147
148 /* GtkBin widgets define the padding and borders independantly so
149  * we cannot provide a generic get_desired_size() for the same reason
150  * we never implemented size_request() here.
151  *
152  * But for cases where the GtkBin class's padding is constant and
153  * does not vary based on allocation (most cases), we can at least 
154  * deduce a common code path for the get_width_for_height()/get_height_for_width()
155  * cases by using the delta of the base size requsts.
156  */
157 static void 
158 gtk_bin_extended_layout_init (GtkExtendedLayoutIface *iface)
159 {
160   parent_extended_layout_iface = g_type_interface_peek_parent (iface);
161
162   iface->get_width_for_height  = gtk_bin_get_width_for_height;
163   iface->get_height_for_width  = gtk_bin_get_height_for_width;
164 }
165
166 static void
167 get_child_padding_delta (GtkBin         *bin,
168                          gint           *delta_h,
169                          gint           *delta_v)
170 {
171   GtkRequisition min_req, child_min;
172
173   gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (bin), 
174                                         &min_req, NULL);
175
176   gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (bin->child), 
177                                         &child_min, NULL);
178
179
180   *delta_h = min_req.width  - child_min.width;
181   *delta_v = min_req.height - child_min.height;
182 }
183
184 static void 
185 gtk_bin_get_width_for_height (GtkExtendedLayout      *layout,
186                               gint                    height,
187                               gint                   *minimum_width,
188                               gint                   *natural_width)
189 {
190   GtkBin *bin = GTK_BIN (layout);
191   gint    hdelta, vdelta, child_min, child_nat;
192
193   if (bin->child)
194     {
195       get_child_padding_delta (bin, &hdelta, &vdelta);
196       
197       gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (bin->child),
198                                                 height - vdelta,
199                                                 &child_min, &child_nat);
200       
201       if (minimum_width)
202         *minimum_width = child_min + hdelta;
203       
204       if (natural_width)
205         *natural_width = child_nat + hdelta;
206     }
207   else
208     parent_extended_layout_iface->get_height_for_width (layout, height, minimum_width, natural_width);
209 }
210
211 static void
212 gtk_bin_get_height_for_width  (GtkExtendedLayout      *layout,
213                                gint                    width,
214                                gint                   *minimum_height,
215                                gint                   *natural_height)
216 {
217   GtkBin *bin = GTK_BIN (layout);
218   gint    hdelta, vdelta, child_min, child_nat;
219
220   if (bin->child)
221     {
222       get_child_padding_delta (bin, &hdelta, &vdelta);
223       
224       gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (bin->child),
225                                                 width - hdelta,
226                                                 &child_min, &child_nat);
227       
228       if (minimum_height)
229         *minimum_height = child_min + vdelta;
230       
231       if (natural_height)
232         *natural_height = child_nat + vdelta;
233     }
234   else
235     parent_extended_layout_iface->get_height_for_width (layout, width, minimum_height, natural_height);
236 }
237
238
239 /**
240  * gtk_bin_get_child:
241  * @bin: a #GtkBin
242  * 
243  * Gets the child of the #GtkBin, or %NULL if the bin contains
244  * no child widget. The returned widget does not have a reference
245  * added, so you do not need to unref it.
246  *
247  * Return value: (transfer none): pointer to child of the #GtkBin
248  **/
249 GtkWidget*
250 gtk_bin_get_child (GtkBin *bin)
251 {
252   g_return_val_if_fail (GTK_IS_BIN (bin), NULL);
253
254   return bin->child;
255 }
256
257 #define __GTK_BIN_C__
258 #include "gtkaliasdef.c"