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