]> Pileus Git - ~andy/gtk/blob - gtk/gtkfixed.c
main part for GtkArgSetFunc/GtkArgGetFunc implementation.
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include "gtkfixed.h"
19
20
21 static void gtk_fixed_class_init    (GtkFixedClass    *klass);
22 static void gtk_fixed_init          (GtkFixed         *fixed);
23 static void gtk_fixed_destroy       (GtkObject        *object);
24 static void gtk_fixed_map           (GtkWidget        *widget);
25 static void gtk_fixed_unmap         (GtkWidget        *widget);
26 static void gtk_fixed_realize       (GtkWidget        *widget);
27 static void gtk_fixed_unrealize     (GtkWidget        *widget);
28 static void gtk_fixed_size_request  (GtkWidget        *widget,
29                                      GtkRequisition   *requisition);
30 static void gtk_fixed_size_allocate (GtkWidget        *widget,
31                                      GtkAllocation    *allocation);
32 static void gtk_fixed_paint         (GtkWidget        *widget,
33                                      GdkRectangle     *area);
34 static void gtk_fixed_draw          (GtkWidget        *widget,
35                                      GdkRectangle     *area);
36 static gint gtk_fixed_expose        (GtkWidget        *widget,
37                                      GdkEventExpose   *event);
38 static void gtk_fixed_add           (GtkContainer     *container,
39                                      GtkWidget        *widget);
40 static void gtk_fixed_remove        (GtkContainer     *container,
41                                      GtkWidget        *widget);
42 static void gtk_fixed_foreach       (GtkContainer     *container,
43                                      GtkCallback      callback,
44                                      gpointer         callback_data);
45
46
47 static GtkContainerClass *parent_class = NULL;
48
49
50 guint
51 gtk_fixed_get_type ()
52 {
53   static guint fixed_type = 0;
54
55   if (!fixed_type)
56     {
57       GtkTypeInfo fixed_info =
58       {
59         "GtkFixed",
60         sizeof (GtkFixed),
61         sizeof (GtkFixedClass),
62         (GtkClassInitFunc) gtk_fixed_class_init,
63         (GtkObjectInitFunc) gtk_fixed_init,
64         (GtkArgSetFunc) NULL,
65         (GtkArgGetFunc) NULL,
66       };
67
68       fixed_type = gtk_type_unique (gtk_container_get_type (), &fixed_info);
69     }
70
71   return fixed_type;
72 }
73
74 static void
75 gtk_fixed_class_init (GtkFixedClass *class)
76 {
77   GtkObjectClass *object_class;
78   GtkWidgetClass *widget_class;
79   GtkContainerClass *container_class;
80
81   object_class = (GtkObjectClass*) class;
82   widget_class = (GtkWidgetClass*) class;
83   container_class = (GtkContainerClass*) class;
84
85   parent_class = gtk_type_class (gtk_container_get_type ());
86
87   object_class->destroy = gtk_fixed_destroy;
88
89   widget_class->map = gtk_fixed_map;
90   widget_class->unmap = gtk_fixed_unmap;
91   widget_class->realize = gtk_fixed_realize;
92   widget_class->unrealize = gtk_fixed_unrealize;
93   widget_class->size_request = gtk_fixed_size_request;
94   widget_class->size_allocate = gtk_fixed_size_allocate;
95   widget_class->draw = gtk_fixed_draw;
96   widget_class->expose_event = gtk_fixed_expose;
97
98   container_class->add = gtk_fixed_add;
99   container_class->remove = gtk_fixed_remove;
100   container_class->foreach = gtk_fixed_foreach;
101 }
102
103 static void
104 gtk_fixed_init (GtkFixed *fixed)
105 {
106   GTK_WIDGET_UNSET_FLAGS (fixed, GTK_NO_WINDOW);
107   GTK_WIDGET_SET_FLAGS (fixed, GTK_BASIC);
108  
109   fixed->children = NULL;
110 }
111
112 GtkWidget*
113 gtk_fixed_new ()
114 {
115   GtkFixed *fixed;
116
117   fixed = gtk_type_new (gtk_fixed_get_type ());
118   return GTK_WIDGET (fixed);
119 }
120
121 void
122 gtk_fixed_put (GtkFixed       *fixed,
123                GtkWidget      *widget,
124                gint16         x,
125                gint16         y)
126 {
127   GtkFixedChild *child_info;
128
129   g_return_if_fail (fixed != NULL);
130   g_return_if_fail (GTK_IS_FIXED (fixed));
131   g_return_if_fail (widget != NULL);
132
133   child_info = g_new (GtkFixedChild, 1);
134   child_info->widget = widget;
135   child_info->x = x;
136   child_info->y = y;
137
138   gtk_widget_set_parent (widget, GTK_WIDGET (fixed));
139
140   fixed->children = g_list_append (fixed->children, child_info); 
141
142   if (GTK_WIDGET_REALIZED (fixed) && !GTK_WIDGET_REALIZED (widget))
143     gtk_widget_realize (widget);
144
145   if (GTK_WIDGET_MAPPED (fixed) && !GTK_WIDGET_MAPPED (widget))
146     gtk_widget_map (widget);
147
148   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (fixed))
149     gtk_widget_queue_resize (GTK_WIDGET (fixed));
150 }
151
152 void
153 gtk_fixed_move (GtkFixed       *fixed,
154                 GtkWidget      *widget,
155                 gint16         x,
156                 gint16         y)
157 {
158   GtkFixedChild *child;
159   GList *children;
160
161   g_return_if_fail (fixed != NULL);
162   g_return_if_fail (GTK_IS_FIXED (fixed));
163   g_return_if_fail (widget != NULL);
164
165   children = fixed->children;
166   while (children)
167     {
168       child = children->data;
169       children = children->next;
170
171       if (child->widget == widget)
172         {
173           child->x = x;
174           child->y = y;
175
176           if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (fixed))
177             gtk_widget_queue_resize (GTK_WIDGET (fixed));
178
179           break;
180         }
181     }
182 }
183
184 static void
185 gtk_fixed_destroy (GtkObject *object)
186 {
187   GtkFixed *fixed;
188   GtkFixedChild *child;
189   GList *children;
190
191   g_return_if_fail (object != NULL);
192   g_return_if_fail (GTK_IS_FIXED (object));
193
194   fixed = GTK_FIXED (object);
195
196   children = fixed->children;
197   while (children)
198     {
199       child = children->data;
200       children = children->next;
201
202       child->widget->parent = NULL;
203       gtk_object_unref (GTK_OBJECT (child->widget));
204       gtk_widget_destroy (child->widget);
205       g_free (child);
206     }
207
208   g_list_free (fixed->children);
209
210   if (GTK_OBJECT_CLASS (parent_class)->destroy)
211     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
212 }
213
214 static void
215 gtk_fixed_map (GtkWidget *widget)
216 {
217   GtkFixed *fixed;
218   GtkFixedChild *child;
219   GList *children;
220
221   g_return_if_fail (widget != NULL);
222   g_return_if_fail (GTK_IS_FIXED (widget));
223
224   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
225   fixed = GTK_FIXED (widget);
226
227   gdk_window_show (widget->window);
228
229   children = fixed->children;
230   while (children)
231     {
232       child = children->data;
233       children = children->next;
234
235       if (GTK_WIDGET_VISIBLE (child->widget) &&
236           !GTK_WIDGET_MAPPED (child->widget))
237         gtk_widget_map (child->widget);
238     }
239 }
240
241 static void
242 gtk_fixed_unmap (GtkWidget *widget)
243 {
244   g_return_if_fail (widget != NULL);
245   g_return_if_fail (GTK_IS_FIXED (widget));
246
247   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
248 }
249
250 static void
251 gtk_fixed_realize (GtkWidget *widget)
252 {
253   GdkWindowAttr attributes;
254   gint attributes_mask;
255
256   g_return_if_fail (widget != NULL);
257   g_return_if_fail (GTK_IS_FIXED (widget));
258
259   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
260
261   attributes.window_type = GDK_WINDOW_CHILD;
262   attributes.x = widget->allocation.x;
263   attributes.y = widget->allocation.y;
264   attributes.width = widget->allocation.width;
265   attributes.height = widget->allocation.height;
266   attributes.wclass = GDK_INPUT_OUTPUT;
267   attributes.visual = gtk_widget_get_visual (widget);
268   attributes.colormap = gtk_widget_get_colormap (widget);
269   attributes.event_mask = gtk_widget_get_events (widget);
270   attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
271
272   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
273
274   widget->window = gdk_window_new (widget->parent->window, &attributes, 
275                                    attributes_mask);
276   gdk_window_set_user_data (widget->window, widget);
277
278   widget->style = gtk_style_attach (widget->style, widget->window);
279   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
280 }
281
282 static void
283 gtk_fixed_unrealize (GtkWidget *widget)
284 {
285   g_return_if_fail (widget != NULL);
286   g_return_if_fail (GTK_IS_FIXED (widget));
287
288   GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED);
289
290   gtk_style_detach (widget->style);
291   gdk_window_destroy (widget->window);
292   widget->window = NULL;
293 }
294
295 static void
296 gtk_fixed_size_request (GtkWidget      *widget,
297                         GtkRequisition *requisition)
298 {
299   GtkFixed *fixed;  
300   GtkFixedChild *child;
301   GList *children;
302
303   g_return_if_fail (widget != NULL);
304   g_return_if_fail (GTK_IS_FIXED (widget));
305   g_return_if_fail (requisition != NULL);
306
307   fixed = GTK_FIXED (widget);
308   requisition->width = 0;
309   requisition->height = 0;
310
311   children = fixed->children;
312   while (children)
313     {
314       child = children->data;
315       children = children->next;
316
317       if (GTK_WIDGET_VISIBLE (child->widget))
318         {
319           gtk_widget_size_request (child->widget, &child->widget->requisition);
320
321           requisition->height = MAX (requisition->height,
322                                      child->y +
323                                      child->widget->requisition.height);
324           requisition->width = MAX (requisition->width,
325                                     child->x +
326                                     child->widget->requisition.width);
327         }
328     }
329
330   requisition->height += GTK_CONTAINER (fixed)->border_width * 2;
331   requisition->width += GTK_CONTAINER (fixed)->border_width * 2;
332 }
333
334 static void
335 gtk_fixed_size_allocate (GtkWidget     *widget,
336                          GtkAllocation *allocation)
337 {
338   GtkFixed *fixed;
339   GtkFixedChild *child;
340   GtkAllocation child_allocation;
341   GList *children;
342   guint16 border_width;
343
344   g_return_if_fail (widget != NULL);
345   g_return_if_fail (GTK_IS_FIXED(widget));
346   g_return_if_fail (allocation != NULL);
347
348   fixed = GTK_FIXED (widget);
349
350   widget->allocation = *allocation;
351   if (GTK_WIDGET_REALIZED (widget))
352     gdk_window_move_resize (widget->window,
353                             allocation->x, 
354                             allocation->y,
355                             allocation->width, 
356                             allocation->height);
357
358   border_width = GTK_CONTAINER (fixed)->border_width;
359   
360   children = fixed->children;
361   while (children)
362     {
363       child = children->data;
364       children = children->next;
365       
366       if (GTK_WIDGET_VISIBLE (child->widget))
367         {
368           child_allocation.x = child->x + border_width;
369           child_allocation.y = child->y + border_width;
370           child_allocation.width = child->widget->requisition.width;
371           child_allocation.height = child->widget->requisition.height;
372           gtk_widget_size_allocate (child->widget, &child_allocation);
373         }
374     }
375 }
376
377 static void
378 gtk_fixed_paint (GtkWidget    *widget,
379                  GdkRectangle *area)
380 {
381   g_return_if_fail (widget != NULL);
382   g_return_if_fail (GTK_IS_FIXED (widget));
383   g_return_if_fail (area != NULL);
384
385   if (GTK_WIDGET_DRAWABLE (widget))
386       gdk_window_clear_area (widget->window,
387                              area->x, area->y,
388                              area->width, area->height);
389 }
390
391 static void
392 gtk_fixed_draw (GtkWidget    *widget,
393                 GdkRectangle *area)
394 {
395   GtkFixed *fixed;
396   GtkFixedChild *child;
397   GdkRectangle child_area;
398   GList *children;
399
400   g_return_if_fail (widget != NULL);
401   g_return_if_fail (GTK_IS_FIXED (widget));
402
403   if (GTK_WIDGET_DRAWABLE (widget))
404     {
405       fixed = GTK_FIXED (widget);
406       gtk_fixed_paint (widget, area);
407
408       children = fixed->children;
409       while (children)
410         {
411           child = children->data;
412           children = children->next;
413
414           if (gtk_widget_intersect (child->widget, area, &child_area))
415             gtk_widget_draw (child->widget, &child_area);
416         }
417     }
418 }
419
420 static gint
421 gtk_fixed_expose (GtkWidget      *widget,
422                   GdkEventExpose *event)
423 {
424   GtkFixed *fixed;
425   GtkFixedChild *child;
426   GdkEventExpose child_event;
427   GList *children;
428
429   g_return_val_if_fail (widget != NULL, FALSE);
430   g_return_val_if_fail (GTK_IS_FIXED (widget), FALSE);
431   g_return_val_if_fail (event != NULL, FALSE);
432
433   if (GTK_WIDGET_DRAWABLE (widget))
434     {
435       fixed = GTK_FIXED (widget);
436
437       child_event = *event;
438
439       children = fixed->children;
440       while (children)
441         {
442           child = children->data;
443           children = children->next;
444
445           if (GTK_WIDGET_NO_WINDOW (child->widget) &&
446               gtk_widget_intersect (child->widget, &event->area, 
447                                     &child_event.area))
448             gtk_widget_event (child->widget, (GdkEvent*) &child_event);
449         }
450     }
451
452   return FALSE;
453 }
454
455 static void
456 gtk_fixed_add (GtkContainer *container,
457                GtkWidget    *widget)
458 {
459   g_return_if_fail (container != NULL);
460   g_return_if_fail (GTK_IS_FIXED (container));
461   g_return_if_fail (widget != NULL);
462
463   gtk_fixed_put (GTK_FIXED (container), widget, 0, 0);
464 }
465
466 static void
467 gtk_fixed_remove (GtkContainer *container,
468                   GtkWidget    *widget)
469 {
470   GtkFixed *fixed;
471   GtkFixedChild *child;
472   GList *children;
473
474   g_return_if_fail (container != NULL);
475   g_return_if_fail (GTK_IS_FIXED (container));
476   g_return_if_fail (widget != NULL);
477
478   fixed = GTK_FIXED (container);
479
480   children = fixed->children;
481   while (children)
482     {
483       child = children->data;
484
485       if (child->widget == widget)
486         {
487           gtk_widget_unparent (widget);
488
489           fixed->children = g_list_remove_link (fixed->children, children);
490           g_list_free (children);
491           g_free (child);
492
493           if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
494             gtk_widget_queue_resize (GTK_WIDGET (container));
495
496           break;
497         }
498
499       children = children->next;
500     }
501 }
502
503 static void
504 gtk_fixed_foreach (GtkContainer *container,
505                    GtkCallback   callback,
506                    gpointer      callback_data)
507 {
508   GtkFixed *fixed;
509   GtkFixedChild *child;
510   GList *children;
511
512   g_return_if_fail (container != NULL);
513   g_return_if_fail (GTK_IS_FIXED (container));
514   g_return_if_fail (callback != NULL);
515
516   fixed = GTK_FIXED (container);
517
518   children = fixed->children;
519   while (children)
520     {
521       child = children->data;
522       children = children->next;
523
524       (* callback) (child->widget, callback_data);
525     }
526 }