]> Pileus Git - ~andy/gtk/blob - gtk/gtkfixed.c
Revert name change
[~andy/gtk] / gtk / gtkfixed.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 "gtkfixed.h"
29 #include "gtkprivate.h"
30 #include "gtkintl.h"
31 #include "gtkalias.h"
32 enum {
33   CHILD_PROP_0,
34   CHILD_PROP_X,
35   CHILD_PROP_Y
36 };
37
38 static void gtk_fixed_realize       (GtkWidget        *widget);
39 static void gtk_fixed_size_request  (GtkWidget        *widget,
40                                      GtkRequisition   *requisition);
41 static void gtk_fixed_size_allocate (GtkWidget        *widget,
42                                      GtkAllocation    *allocation);
43 static void gtk_fixed_add           (GtkContainer     *container,
44                                      GtkWidget        *widget);
45 static void gtk_fixed_remove        (GtkContainer     *container,
46                                      GtkWidget        *widget);
47 static void gtk_fixed_forall        (GtkContainer     *container,
48                                      gboolean          include_internals,
49                                      GtkCallback       callback,
50                                      gpointer          callback_data);
51 static GType gtk_fixed_child_type   (GtkContainer     *container);
52
53 static void gtk_fixed_set_child_property (GtkContainer *container,
54                                           GtkWidget    *child,
55                                           guint         property_id,
56                                           const GValue *value,
57                                           GParamSpec   *pspec);
58 static void gtk_fixed_get_child_property (GtkContainer *container,
59                                           GtkWidget    *child,
60                                           guint         property_id,
61                                           GValue       *value,
62                                           GParamSpec   *pspec);
63
64 G_DEFINE_TYPE (GtkFixed, gtk_fixed, GTK_TYPE_CONTAINER)
65
66 static void
67 gtk_fixed_class_init (GtkFixedClass *class)
68 {
69   GtkWidgetClass *widget_class;
70   GtkContainerClass *container_class;
71
72   widget_class = (GtkWidgetClass*) class;
73   container_class = (GtkContainerClass*) class;
74
75   widget_class->realize = gtk_fixed_realize;
76   widget_class->size_request = gtk_fixed_size_request;
77   widget_class->size_allocate = gtk_fixed_size_allocate;
78
79   container_class->add = gtk_fixed_add;
80   container_class->remove = gtk_fixed_remove;
81   container_class->forall = gtk_fixed_forall;
82   container_class->child_type = gtk_fixed_child_type;
83
84   container_class->set_child_property = gtk_fixed_set_child_property;
85   container_class->get_child_property = gtk_fixed_get_child_property;
86
87   gtk_container_class_install_child_property (container_class,
88                                               CHILD_PROP_X,
89                                               g_param_spec_int ("x",
90                                                                 P_("X position"),
91                                                                 P_("X position of child widget"),
92                                                                 G_MININT,
93                                                                 G_MAXINT,
94                                                                 0,
95                                                                 GTK_PARAM_READWRITE));
96
97   gtk_container_class_install_child_property (container_class,
98                                               CHILD_PROP_Y,
99                                               g_param_spec_int ("y",
100                                                                 P_("Y position"),
101                                                                 P_("Y position of child widget"),
102                                                                 G_MININT,
103                                                                 G_MAXINT,
104                                                                 0,
105                                                                 GTK_PARAM_READWRITE));
106 }
107
108 static GType
109 gtk_fixed_child_type (GtkContainer     *container)
110 {
111   return GTK_TYPE_WIDGET;
112 }
113
114 static void
115 gtk_fixed_init (GtkFixed *fixed)
116 {
117   GTK_WIDGET_SET_FLAGS (fixed, GTK_NO_WINDOW);
118  
119   fixed->children = NULL;
120 }
121
122 GtkWidget*
123 gtk_fixed_new (void)
124 {
125   return g_object_new (GTK_TYPE_FIXED, NULL);
126 }
127
128 static GtkFixedChild*
129 get_child (GtkFixed  *fixed,
130            GtkWidget *widget)
131 {
132   GList *children;
133   
134   children = fixed->children;
135   while (children)
136     {
137       GtkFixedChild *child;
138       
139       child = children->data;
140       children = children->next;
141
142       if (child->widget == widget)
143         return child;
144     }
145
146   return NULL;
147 }
148
149 void
150 gtk_fixed_put (GtkFixed       *fixed,
151                GtkWidget      *widget,
152                gint            x,
153                gint            y)
154 {
155   GtkFixedChild *child_info;
156
157   g_return_if_fail (GTK_IS_FIXED (fixed));
158   g_return_if_fail (GTK_IS_WIDGET (widget));
159
160   child_info = g_new (GtkFixedChild, 1);
161   child_info->widget = widget;
162   child_info->x = x;
163   child_info->y = y;
164
165   gtk_widget_set_parent (widget, GTK_WIDGET (fixed));
166
167   fixed->children = g_list_append (fixed->children, child_info);
168 }
169
170 static void
171 gtk_fixed_move_internal (GtkFixed       *fixed,
172                          GtkWidget      *widget,
173                          gboolean        change_x,
174                          gint            x,
175                          gboolean        change_y,
176                          gint            y)
177 {
178   GtkFixedChild *child;
179   
180   g_return_if_fail (GTK_IS_FIXED (fixed));
181   g_return_if_fail (GTK_IS_WIDGET (widget));
182   g_return_if_fail (widget->parent == GTK_WIDGET (fixed));  
183   
184   child = get_child (fixed, widget);
185
186   g_assert (child);
187
188   gtk_widget_freeze_child_notify (widget);
189   
190   if (change_x)
191     {
192       child->x = x;
193       gtk_widget_child_notify (widget, "x");
194     }
195
196   if (change_y)
197     {
198       child->y = y;
199       gtk_widget_child_notify (widget, "y");
200     }
201
202   gtk_widget_thaw_child_notify (widget);
203   
204   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (fixed))
205     gtk_widget_queue_resize (GTK_WIDGET (fixed));
206 }
207
208 void
209 gtk_fixed_move (GtkFixed       *fixed,
210                 GtkWidget      *widget,
211                 gint            x,
212                 gint            y)
213 {
214   gtk_fixed_move_internal (fixed, widget, TRUE, x, TRUE, y);
215 }
216
217 static void
218 gtk_fixed_set_child_property (GtkContainer    *container,
219                               GtkWidget       *child,
220                               guint            property_id,
221                               const GValue    *value,
222                               GParamSpec      *pspec)
223 {
224   switch (property_id)
225     {
226     case CHILD_PROP_X:
227       gtk_fixed_move_internal (GTK_FIXED (container),
228                                child,
229                                TRUE, g_value_get_int (value),
230                                FALSE, 0);
231       break;
232     case CHILD_PROP_Y:
233       gtk_fixed_move_internal (GTK_FIXED (container),
234                                child,
235                                FALSE, 0,
236                                TRUE, g_value_get_int (value));
237       break;
238     default:
239       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
240       break;
241     }
242 }
243
244 static void
245 gtk_fixed_get_child_property (GtkContainer *container,
246                               GtkWidget    *child,
247                               guint         property_id,
248                               GValue       *value,
249                               GParamSpec   *pspec)
250 {
251   GtkFixedChild *fixed_child;
252
253   fixed_child = get_child (GTK_FIXED (container), child);
254   
255   switch (property_id)
256     {
257     case CHILD_PROP_X:
258       g_value_set_int (value, fixed_child->x);
259       break;
260     case CHILD_PROP_Y:
261       g_value_set_int (value, fixed_child->y);
262       break;
263     default:
264       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
265       break;
266     }
267 }
268
269 static void
270 gtk_fixed_realize (GtkWidget *widget)
271 {
272   GdkWindowAttr attributes;
273   gint attributes_mask;
274
275   if (GTK_WIDGET_NO_WINDOW (widget))
276     GTK_WIDGET_CLASS (gtk_fixed_parent_class)->realize (widget);
277   else
278     {
279       GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
280
281       attributes.window_type = GDK_WINDOW_CHILD;
282       attributes.x = widget->allocation.x;
283       attributes.y = widget->allocation.y;
284       attributes.width = widget->allocation.width;
285       attributes.height = widget->allocation.height;
286       attributes.wclass = GDK_INPUT_OUTPUT;
287       attributes.visual = gtk_widget_get_visual (widget);
288       attributes.colormap = gtk_widget_get_colormap (widget);
289       attributes.event_mask = gtk_widget_get_events (widget);
290       attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
291       
292       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
293       
294       widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, 
295                                        attributes_mask);
296       gdk_window_set_user_data (widget->window, widget);
297       
298       widget->style = gtk_style_attach (widget->style, widget->window);
299       gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
300     }
301 }
302
303 static void
304 gtk_fixed_size_request (GtkWidget      *widget,
305                         GtkRequisition *requisition)
306 {
307   GtkFixed *fixed;  
308   GtkFixedChild *child;
309   GList *children;
310   GtkRequisition child_requisition;
311
312   fixed = GTK_FIXED (widget);
313   requisition->width = 0;
314   requisition->height = 0;
315
316   children = fixed->children;
317   while (children)
318     {
319       child = children->data;
320       children = children->next;
321
322       if (GTK_WIDGET_VISIBLE (child->widget))
323         {
324           gtk_widget_size_request (child->widget, &child_requisition);
325
326           requisition->height = MAX (requisition->height,
327                                      child->y +
328                                      child_requisition.height);
329           requisition->width = MAX (requisition->width,
330                                     child->x +
331                                     child_requisition.width);
332         }
333     }
334
335   requisition->height += GTK_CONTAINER (fixed)->border_width * 2;
336   requisition->width += GTK_CONTAINER (fixed)->border_width * 2;
337 }
338
339 static void
340 gtk_fixed_size_allocate (GtkWidget     *widget,
341                          GtkAllocation *allocation)
342 {
343   GtkFixed *fixed;
344   GtkFixedChild *child;
345   GtkAllocation child_allocation;
346   GtkRequisition child_requisition;
347   GList *children;
348   guint16 border_width;
349
350   fixed = GTK_FIXED (widget);
351
352   widget->allocation = *allocation;
353
354   if (!GTK_WIDGET_NO_WINDOW (widget))
355     {
356       if (GTK_WIDGET_REALIZED (widget))
357         gdk_window_move_resize (widget->window,
358                                 allocation->x, 
359                                 allocation->y,
360                                 allocation->width, 
361                                 allocation->height);
362     }
363       
364   border_width = GTK_CONTAINER (fixed)->border_width;
365   
366   children = fixed->children;
367   while (children)
368     {
369       child = children->data;
370       children = children->next;
371       
372       if (GTK_WIDGET_VISIBLE (child->widget))
373         {
374           gtk_widget_get_child_requisition (child->widget, &child_requisition);
375           child_allocation.x = child->x + border_width;
376           child_allocation.y = child->y + border_width;
377
378           if (GTK_WIDGET_NO_WINDOW (widget))
379             {
380               child_allocation.x += widget->allocation.x;
381               child_allocation.y += widget->allocation.y;
382             }
383           
384           child_allocation.width = child_requisition.width;
385           child_allocation.height = child_requisition.height;
386           gtk_widget_size_allocate (child->widget, &child_allocation);
387         }
388     }
389 }
390
391 static void
392 gtk_fixed_add (GtkContainer *container,
393                GtkWidget    *widget)
394 {
395   gtk_fixed_put (GTK_FIXED (container), widget, 0, 0);
396 }
397
398 static void
399 gtk_fixed_remove (GtkContainer *container,
400                   GtkWidget    *widget)
401 {
402   GtkFixed *fixed;
403   GtkFixedChild *child;
404   GList *children;
405
406   fixed = GTK_FIXED (container);
407
408   children = fixed->children;
409   while (children)
410     {
411       child = children->data;
412
413       if (child->widget == widget)
414         {
415           gboolean was_visible = GTK_WIDGET_VISIBLE (widget);
416           
417           gtk_widget_unparent (widget);
418
419           fixed->children = g_list_remove_link (fixed->children, children);
420           g_list_free (children);
421           g_free (child);
422
423           if (was_visible && GTK_WIDGET_VISIBLE (container))
424             gtk_widget_queue_resize (GTK_WIDGET (container));
425
426           break;
427         }
428
429       children = children->next;
430     }
431 }
432
433 static void
434 gtk_fixed_forall (GtkContainer *container,
435                   gboolean      include_internals,
436                   GtkCallback   callback,
437                   gpointer      callback_data)
438 {
439   GtkFixed *fixed = GTK_FIXED (container);
440   GtkFixedChild *child;
441   GList *children;
442
443   children = fixed->children;
444   while (children)
445     {
446       child = children->data;
447       children = children->next;
448
449       (* callback) (child->widget, callback_data);
450     }
451 }
452
453 /**
454  * gtk_fixed_set_has_window:
455  * @fixed: a #GtkFixed
456  * @has_window: %TRUE if a separate window should be created
457  * 
458  * Sets whether a #GtkFixed widget is created with a separate
459  * #GdkWindow for @widget->window or not. (By default, it will be
460  * created with no separate #GdkWindow). This function must be called
461  * while the #GtkFixed is not realized, for instance, immediately after the
462  * window is created.
463  * 
464  * This function was added to provide an easy migration path for
465  * older applications which may expect #GtkFixed to have a separate window.
466  **/
467 void
468 gtk_fixed_set_has_window (GtkFixed *fixed,
469                           gboolean  has_window)
470 {
471   g_return_if_fail (GTK_IS_FIXED (fixed));
472   g_return_if_fail (!GTK_WIDGET_REALIZED (fixed));
473
474   if (!has_window != GTK_WIDGET_NO_WINDOW (fixed))
475     {
476       if (has_window)
477         GTK_WIDGET_UNSET_FLAGS (fixed, GTK_NO_WINDOW);
478       else
479         GTK_WIDGET_SET_FLAGS (fixed, GTK_NO_WINDOW);
480     }
481 }
482
483 /**
484  * gtk_fixed_get_has_window:
485  * @fixed: a #GtkWidget
486  * 
487  * Gets whether the #GtkFixed has its own #GdkWindow.
488  * See gtk_fixed_set_has_window().
489  * 
490  * Return value: %TRUE if @fixed has its own window.
491  **/
492 gboolean
493 gtk_fixed_get_has_window (GtkFixed *fixed)
494 {
495   g_return_val_if_fail (GTK_IS_FIXED (fixed), FALSE);
496
497   return !GTK_WIDGET_NO_WINDOW (fixed);
498 }
499
500 #define __GTK_FIXED_C__
501 #include "gtkaliasdef.c"