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