]> Pileus Git - ~andy/gtk/blob - gtk/gtkalignment.c
Fix #99593: Fix a memory leak when XmbLookupString returns XBufferOverflow
[~andy/gtk] / gtk / gtkalignment.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 "gtkalignment.h"
28 #include "gtkintl.h"
29
30 enum {
31   PROP_0,
32
33   PROP_XALIGN,
34   PROP_YALIGN,
35   PROP_XSCALE,
36   PROP_YSCALE,
37   
38   PROP_LAST
39 };
40
41
42 static void gtk_alignment_class_init    (GtkAlignmentClass *klass);
43 static void gtk_alignment_init          (GtkAlignment      *alignment);
44 static void gtk_alignment_size_request  (GtkWidget         *widget,
45                                          GtkRequisition    *requisition);
46 static void gtk_alignment_size_allocate (GtkWidget         *widget,
47                                          GtkAllocation     *allocation);
48 static void gtk_alignment_set_property (GObject         *object,
49                                         guint            prop_id,
50                                         const GValue    *value,
51                                         GParamSpec      *pspec);
52 static void gtk_alignment_get_property (GObject         *object,
53                                         guint            prop_id,
54                                         GValue          *value,
55                                         GParamSpec      *pspec);
56
57 GType
58 gtk_alignment_get_type (void)
59 {
60   static GType alignment_type = 0;
61
62   if (!alignment_type)
63     {
64       static const GTypeInfo alignment_info =
65       {
66         sizeof (GtkAlignmentClass),
67         NULL,           /* base_init */
68         NULL,           /* base_finalize */
69         (GClassInitFunc) gtk_alignment_class_init,
70         NULL,           /* class_finalize */
71         NULL,           /* class_data */
72         sizeof (GtkAlignment),
73         0,              /* n_preallocs */
74         (GInstanceInitFunc) gtk_alignment_init,
75       };
76
77       alignment_type = g_type_register_static (GTK_TYPE_BIN, "GtkAlignment",
78                                                &alignment_info, 0);
79     }
80
81   return alignment_type;
82 }
83
84 static void
85 gtk_alignment_class_init (GtkAlignmentClass *class)
86 {
87   GObjectClass *gobject_class;
88   GtkWidgetClass *widget_class;
89
90   gobject_class = (GObjectClass*) class;
91   widget_class = (GtkWidgetClass*) class;
92   
93   gobject_class->set_property = gtk_alignment_set_property;
94   gobject_class->get_property = gtk_alignment_get_property;
95
96   widget_class->size_request = gtk_alignment_size_request;
97   widget_class->size_allocate = gtk_alignment_size_allocate;
98   
99   g_object_class_install_property (gobject_class,
100                                    PROP_XALIGN,
101                                    g_param_spec_float("xalign",
102                                                       _("Horizontal alignment"),
103                                                       _("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
104                                                       0.0,
105                                                       1.0,
106                                                       0.5,
107                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
108    
109   g_object_class_install_property (gobject_class,
110                                    PROP_YALIGN,
111                                    g_param_spec_float("yalign",
112                                                       _("Vertical alignment"),
113                                                       _("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
114                                                       0.0,
115                                                       1.0,
116                                                       0.5,
117                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
118   g_object_class_install_property (gobject_class,
119                                    PROP_XSCALE,
120                                    g_param_spec_float("xscale",
121                                                       _("Horizontal scale"),
122                                                       _("If available horizontal space is bigger than needed for the child, how much of it to use for the child. 0.0 means none, 1.0 means all"),
123                                                       0.0,
124                                                       1.0,
125                                                       1.0,
126                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
127   g_object_class_install_property (gobject_class,
128                                    PROP_YSCALE,
129                                    g_param_spec_float("yscale",
130                                                       _("Vertical scale"),
131                                                       _("If available vertical space is bigger than needed for the child, how much of it to use for the child. 0.0 means none, 1.0 means all"),
132                                                       0.0,
133                                                       1.0,
134                                                       1.0,
135                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
136 }
137
138 static void
139 gtk_alignment_init (GtkAlignment *alignment)
140 {
141   GTK_WIDGET_SET_FLAGS (alignment, GTK_NO_WINDOW);
142   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (alignment), FALSE);
143
144   alignment->xalign = 0.5;
145   alignment->yalign = 0.5;
146   alignment->xscale = 1.0;
147   alignment->yscale = 1.0;
148 }
149
150 GtkWidget*
151 gtk_alignment_new (gfloat xalign,
152                    gfloat yalign,
153                    gfloat xscale,
154                    gfloat yscale)
155 {
156   GtkAlignment *alignment;
157
158   alignment = g_object_new (GTK_TYPE_ALIGNMENT, NULL);
159
160   alignment->xalign = CLAMP (xalign, 0.0, 1.0);
161   alignment->yalign = CLAMP (yalign, 0.0, 1.0);
162   alignment->xscale = CLAMP (xscale, 0.0, 1.0);
163   alignment->yscale = CLAMP (yscale, 0.0, 1.0);
164
165   return GTK_WIDGET (alignment);
166 }
167
168 static void
169 gtk_alignment_set_property (GObject         *object,
170                             guint            prop_id,
171                             const GValue    *value,
172                             GParamSpec      *pspec)
173 {
174   GtkAlignment *alignment;
175   
176   alignment = GTK_ALIGNMENT (object);
177   
178   switch (prop_id)
179     {
180     case PROP_XALIGN:
181       gtk_alignment_set (alignment,
182                          g_value_get_float (value),
183                          alignment->yalign,
184                          alignment->xscale,
185                          alignment->yscale);
186       break;
187     case PROP_YALIGN:
188       gtk_alignment_set (alignment,
189                          alignment->xalign,
190                          g_value_get_float (value),
191                          alignment->xscale,
192                          alignment->yscale);
193       break;
194     case PROP_XSCALE:
195       gtk_alignment_set (alignment,
196                          alignment->xalign,
197                          alignment->yalign,
198                          g_value_get_float (value),
199                          alignment->yscale);
200       break;
201     case PROP_YSCALE:
202       gtk_alignment_set (alignment,
203                          alignment->xalign,
204                          alignment->yalign,
205                          alignment->xscale,
206                          g_value_get_float (value));
207       break;
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210       break;
211     }
212 }
213
214 static void
215 gtk_alignment_get_property (GObject         *object,
216                             guint            prop_id,
217                             GValue          *value,
218                             GParamSpec      *pspec)
219 {
220   GtkAlignment *alignment;
221   
222   alignment = GTK_ALIGNMENT (object);
223    
224   switch (prop_id)
225     {
226     case PROP_XALIGN:
227       g_value_set_float(value, alignment->xalign);
228       break;
229     case PROP_YALIGN:
230       g_value_set_float(value, alignment->yalign);
231       break;
232     case PROP_XSCALE:
233       g_value_set_float(value, alignment->xscale);
234       break;
235     case PROP_YSCALE:
236       g_value_set_float(value, alignment->yscale);
237       break;
238     default:
239       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
240       break;
241     }
242 }
243
244 void
245 gtk_alignment_set (GtkAlignment *alignment,
246                    gfloat        xalign,
247                    gfloat        yalign,
248                    gfloat        xscale,
249                    gfloat        yscale)
250 {
251   g_return_if_fail (GTK_IS_ALIGNMENT (alignment));
252
253   xalign = CLAMP (xalign, 0.0, 1.0);
254   yalign = CLAMP (yalign, 0.0, 1.0);
255   xscale = CLAMP (xscale, 0.0, 1.0);
256   yscale = CLAMP (yscale, 0.0, 1.0);
257
258   if (   (alignment->xalign != xalign)
259       || (alignment->yalign != yalign)
260       || (alignment->xscale != xscale)
261       || (alignment->yscale != yscale))
262     {
263       g_object_freeze_notify (G_OBJECT (alignment));
264       if (alignment->xalign != xalign)
265         {
266            alignment->xalign = xalign;
267            g_object_notify (G_OBJECT (alignment), "xalign");
268         }
269       if (alignment->yalign != yalign)
270         {
271            alignment->yalign = yalign;
272            g_object_notify (G_OBJECT (alignment), "yalign");
273         }
274       if (alignment->xscale != xscale)
275         {
276            alignment->xscale = xscale;
277            g_object_notify (G_OBJECT (alignment), "xscale");
278         }
279       if (alignment->yscale != yscale)
280         {
281            alignment->yscale = yscale;
282            g_object_notify (G_OBJECT (alignment), "yscale");
283         }
284       g_object_thaw_notify (G_OBJECT (alignment));
285
286       if (GTK_BIN (alignment)->child)
287         gtk_widget_queue_resize (GTK_BIN (alignment)->child);
288       gtk_widget_queue_draw (GTK_WIDGET (alignment));
289     }
290 }
291
292
293 static void
294 gtk_alignment_size_request (GtkWidget      *widget,
295                             GtkRequisition *requisition)
296 {
297   GtkAlignment *alignment;
298   GtkBin *bin;
299
300   alignment = GTK_ALIGNMENT (widget);
301   bin = GTK_BIN (widget);
302
303   requisition->width = GTK_CONTAINER (widget)->border_width * 2;
304   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
305
306   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
307     {
308       GtkRequisition child_requisition;
309       
310       gtk_widget_size_request (bin->child, &child_requisition);
311
312       requisition->width += child_requisition.width;
313       requisition->height += child_requisition.height;
314     }
315 }
316
317 static void
318 gtk_alignment_size_allocate (GtkWidget     *widget,
319                              GtkAllocation *allocation)
320 {
321   GtkAlignment *alignment;
322   GtkBin *bin;
323   GtkAllocation child_allocation;
324   GtkRequisition child_requisition;
325   gint width, height;
326   gint x, y;
327
328   widget->allocation = *allocation;
329   alignment = GTK_ALIGNMENT (widget);
330   bin = GTK_BIN (widget);
331   
332   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
333     {
334       gtk_widget_get_child_requisition (bin->child, &child_requisition);
335       
336       x = GTK_CONTAINER (alignment)->border_width;
337       y = GTK_CONTAINER (alignment)->border_width;
338       width = MAX (allocation->width - 2 * x, 0);
339       height = MAX (allocation->height - 2 * y, 0);
340       
341       if (width > child_requisition.width)
342         child_allocation.width = (child_requisition.width *
343                                   (1.0 - alignment->xscale) +
344                                   width * alignment->xscale);
345       else
346         child_allocation.width = width;
347       
348       if (height > child_requisition.height)
349         child_allocation.height = (child_requisition.height *
350                                    (1.0 - alignment->yscale) +
351                                    height * alignment->yscale);
352       else
353         child_allocation.height = height;
354
355       child_allocation.x = alignment->xalign * (width - child_allocation.width) + allocation->x + x;
356       child_allocation.y = alignment->yalign * (height - child_allocation.height) + allocation->y + y;
357
358       gtk_widget_size_allocate (bin->child, &child_allocation);
359     }
360 }