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