]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unix/gtkpanel.c
Fiddly things involving pruning .svn directories, not mentioning
[PuTTY.git] / unix / gtkpanel.c
1 /*
2  * gtkpanel.c - implementation of the `Panels' GTK layout container.
3  */
4
5 #include "gtkpanel.h"
6
7 static void panels_init(Panels *panels);
8 static void panels_class_init(PanelsClass *klass);
9 static void panels_map(GtkWidget *widget);
10 static void panels_unmap(GtkWidget *widget);
11 static void panels_draw(GtkWidget *widget, GdkRectangle *area);
12 static gint panels_expose(GtkWidget *widget, GdkEventExpose *event);
13 static void panels_base_add(GtkContainer *container, GtkWidget *widget);
14 static void panels_remove(GtkContainer *container, GtkWidget *widget);
15 static void panels_forall(GtkContainer *container, gboolean include_internals,
16                            GtkCallback callback, gpointer callback_data);
17 static GtkType panels_child_type(GtkContainer *container);
18 static void panels_size_request(GtkWidget *widget, GtkRequisition *req);
19 static void panels_size_allocate(GtkWidget *widget, GtkAllocation *alloc);
20
21 static GtkContainerClass *parent_class = NULL;
22
23 GtkType panels_get_type(void)
24 {
25     static GtkType panels_type = 0;
26
27     if (!panels_type) {
28         static const GtkTypeInfo panels_info = {
29             "Panels",
30             sizeof(Panels),
31             sizeof(PanelsClass),
32             (GtkClassInitFunc) panels_class_init,
33             (GtkObjectInitFunc) panels_init,
34             /* reserved_1 */ NULL,
35             /* reserved_2 */ NULL,
36             (GtkClassInitFunc) NULL,
37         };
38
39         panels_type = gtk_type_unique(GTK_TYPE_CONTAINER, &panels_info);
40     }
41
42     return panels_type;
43 }
44
45 static void panels_class_init(PanelsClass *klass)
46 {
47     GtkObjectClass *object_class;
48     GtkWidgetClass *widget_class;
49     GtkContainerClass *container_class;
50
51     object_class = (GtkObjectClass *)klass;
52     widget_class = (GtkWidgetClass *)klass;
53     container_class = (GtkContainerClass *)klass;
54
55     parent_class = gtk_type_class(GTK_TYPE_CONTAINER);
56
57     /*
58      * FIXME: do we have to do all this faffing with set_arg,
59      * get_arg and child_arg_type? Ick.
60      */
61
62     widget_class->map = panels_map;
63     widget_class->unmap = panels_unmap;
64     widget_class->draw = panels_draw;
65     widget_class->expose_event = panels_expose;
66     widget_class->size_request = panels_size_request;
67     widget_class->size_allocate = panels_size_allocate;
68
69     container_class->add = panels_base_add;
70     container_class->remove = panels_remove;
71     container_class->forall = panels_forall;
72     container_class->child_type = panels_child_type;
73 }
74
75 static void panels_init(Panels *panels)
76 {
77     GTK_WIDGET_SET_FLAGS(panels, GTK_NO_WINDOW);
78
79     panels->children = NULL;
80 }
81
82 /*
83  * These appear to be thoroughly tedious functions; the only reason
84  * we have to reimplement them at all is because we defined our own
85  * format for our GList of children...
86  */
87 static void panels_map(GtkWidget *widget)
88 {
89     Panels *panels;
90     GtkWidget *child;
91     GList *children;
92
93     g_return_if_fail(widget != NULL);
94     g_return_if_fail(IS_PANELS(widget));
95
96     panels = PANELS(widget);
97     GTK_WIDGET_SET_FLAGS(panels, GTK_MAPPED);
98
99     for (children = panels->children;
100          children && (child = children->data);
101          children = children->next) {
102         if (child &&
103             GTK_WIDGET_VISIBLE(child) &&
104             !GTK_WIDGET_MAPPED(child))
105             gtk_widget_map(child);
106     }
107 }
108 static void panels_unmap(GtkWidget *widget)
109 {
110     Panels *panels;
111     GtkWidget *child;
112     GList *children;
113
114     g_return_if_fail(widget != NULL);
115     g_return_if_fail(IS_PANELS(widget));
116
117     panels = PANELS(widget);
118     GTK_WIDGET_UNSET_FLAGS(panels, GTK_MAPPED);
119
120     for (children = panels->children;
121          children && (child = children->data);
122          children = children->next) {
123         if (child &&
124             GTK_WIDGET_VISIBLE(child) &&
125             GTK_WIDGET_MAPPED(child))
126             gtk_widget_unmap(child);
127     }
128 }
129 static void panels_draw(GtkWidget *widget, GdkRectangle *area)
130 {
131     Panels *panels;
132     GtkWidget *child;
133     GList *children;
134     GdkRectangle child_area;
135
136     g_return_if_fail(widget != NULL);
137     g_return_if_fail(IS_PANELS(widget));
138
139     if (GTK_WIDGET_DRAWABLE(widget)) {
140         panels = PANELS(widget);
141
142         for (children = panels->children;
143              children && (child = children->data);
144              children = children->next) {
145             if (child &&
146                 GTK_WIDGET_DRAWABLE(child) &&
147                 gtk_widget_intersect(child, area, &child_area))
148                 gtk_widget_draw(child, &child_area);
149         }
150     }
151 }
152 static gint panels_expose(GtkWidget *widget, GdkEventExpose *event)
153 {
154     Panels *panels;
155     GtkWidget *child;
156     GList *children;
157     GdkEventExpose child_event;
158
159     g_return_val_if_fail(widget != NULL, FALSE);
160     g_return_val_if_fail(IS_PANELS(widget), FALSE);
161     g_return_val_if_fail(event != NULL, FALSE);
162
163     if (GTK_WIDGET_DRAWABLE(widget)) {
164         panels = PANELS(widget);
165         child_event = *event;
166
167         for (children = panels->children;
168              children && (child = children->data);
169              children = children->next) {
170             if (child &&
171                 GTK_WIDGET_DRAWABLE(child) &&
172                 GTK_WIDGET_NO_WINDOW(child) &&
173                 gtk_widget_intersect(child, &event->area,
174                                      &child_event.area))
175                 gtk_widget_event(child, (GdkEvent *)&child_event);
176         }
177     }
178     return FALSE;
179 }
180
181 static void panels_base_add(GtkContainer *container, GtkWidget *widget)
182 {
183     Panels *panels;
184
185     g_return_if_fail(container != NULL);
186     g_return_if_fail(IS_PANELS(container));
187     g_return_if_fail(widget != NULL);
188
189     panels = PANELS(container);
190
191     panels_add(panels, widget);
192 }
193
194 static void panels_remove(GtkContainer *container, GtkWidget *widget)
195 {
196     Panels *panels;
197     GtkWidget *child;
198     GList *children;
199     gboolean was_visible;
200
201     g_return_if_fail(container != NULL);
202     g_return_if_fail(IS_PANELS(container));
203     g_return_if_fail(widget != NULL);
204
205     panels = PANELS(container);
206
207     for (children = panels->children;
208          children && (child = children->data);
209          children = children->next) {
210         if (child != widget)
211             continue;
212
213         was_visible = GTK_WIDGET_VISIBLE(widget);
214         gtk_widget_unparent(widget);
215         panels->children = g_list_remove_link(panels->children, children);
216         g_list_free(children);
217         if (was_visible)
218             gtk_widget_queue_resize(GTK_WIDGET(container));
219         break;
220     }
221 }
222
223 static void panels_forall(GtkContainer *container, gboolean include_internals,
224                            GtkCallback callback, gpointer callback_data)
225 {
226     Panels *panels;
227     GtkWidget *child;
228     GList *children, *next;
229
230     g_return_if_fail(container != NULL);
231     g_return_if_fail(IS_PANELS(container));
232     g_return_if_fail(callback != NULL);
233
234     panels = PANELS(container);
235
236     for (children = panels->children;
237          children && (child = children->data);
238          children = next) {
239         /*
240          * We can't wait until after the callback to assign
241          * `children = children->next', because the callback might
242          * be gtk_widget_destroy, which would remove the link
243          * `children' from the list! So instead we must get our
244          * hands on the value of the `next' pointer _before_ the
245          * callback.
246          */
247         next = children->next;
248         if (child)
249             callback(child, callback_data);
250     }
251 }
252
253 static GtkType panels_child_type(GtkContainer *container)
254 {
255     return GTK_TYPE_WIDGET;
256 }
257
258 GtkWidget *panels_new(void)
259 {
260     Panels *panels;
261
262     panels = gtk_type_new(panels_get_type());
263
264     return GTK_WIDGET(panels);
265 }
266
267 void panels_add(Panels *panels, GtkWidget *child)
268 {
269     g_return_if_fail(panels != NULL);
270     g_return_if_fail(IS_PANELS(panels));
271     g_return_if_fail(child != NULL);
272     g_return_if_fail(child->parent == NULL);
273
274     panels->children = g_list_append(panels->children, child);
275
276     gtk_widget_set_parent(child, GTK_WIDGET(panels));
277
278     if (GTK_WIDGET_REALIZED(panels))
279         gtk_widget_realize(child);
280
281     if (GTK_WIDGET_VISIBLE(panels)) {
282         if (GTK_WIDGET_MAPPED(panels))
283             gtk_widget_map(child);
284         gtk_widget_queue_resize(child);
285     }
286 }
287
288 void panels_switch_to(Panels *panels, GtkWidget *target)
289 {
290     GtkWidget *child = NULL;
291     GList *children;
292     gboolean changed = FALSE;
293
294     g_return_if_fail(panels != NULL);
295     g_return_if_fail(IS_PANELS(panels));
296     g_return_if_fail(target != NULL);
297     g_return_if_fail(target->parent == GTK_WIDGET(panels));
298
299     for (children = panels->children;
300          children && (child = children->data);
301          children = children->next) {
302
303         if (!child)
304             continue;
305
306         if (child == target) {
307             if (!GTK_WIDGET_VISIBLE(child)) {
308                 gtk_widget_show(child);
309                 changed = TRUE;
310             }
311         } else {
312             if (GTK_WIDGET_VISIBLE(child)) {
313                 gtk_widget_hide(child);
314                 changed = TRUE;
315             }
316         }
317     }
318     if (changed)
319         gtk_widget_queue_resize(child);
320 }
321
322 /*
323  * Now here comes the interesting bit. The actual layout part is
324  * done in the following two functions:
325  * 
326  * panels_size_request() examines the list of widgets held in the
327  * Panels, and returns a requisition stating the absolute minimum
328  * size it can bear to be.
329  * 
330  * panels_size_allocate() is given an allocation telling it what
331  * size the whole container is going to be, and it calls
332  * gtk_widget_size_allocate() on all of its (visible) children to
333  * set their size and position relative to the top left of the
334  * container.
335  */
336
337 static void panels_size_request(GtkWidget *widget, GtkRequisition *req)
338 {
339     Panels *panels;
340     GtkWidget *child;
341     GList *children;
342
343     g_return_if_fail(widget != NULL);
344     g_return_if_fail(IS_PANELS(widget));
345     g_return_if_fail(req != NULL);
346
347     panels = PANELS(widget);
348
349     req->width = 0;
350     req->height = 0;
351
352     for (children = panels->children;
353          children && (child = children->data);
354          children = children->next) {
355         GtkRequisition creq;
356
357         gtk_widget_size_request(child, &creq);
358         if (req->width < creq.width)
359             req->width = creq.width;
360         if (req->height < creq.height)
361             req->height = creq.height;
362     }
363
364     req->width += 2*GTK_CONTAINER(panels)->border_width;
365     req->height += 2*GTK_CONTAINER(panels)->border_width;
366 }
367
368 static void panels_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
369 {
370     Panels *panels;
371     GtkWidget *child;
372     GList *children;
373     gint border;
374
375     g_return_if_fail(widget != NULL);
376     g_return_if_fail(IS_PANELS(widget));
377     g_return_if_fail(alloc != NULL);
378
379     panels = PANELS(widget);
380     widget->allocation = *alloc;
381     border = GTK_CONTAINER(panels)->border_width;
382
383     for (children = panels->children;
384          children && (child = children->data);
385          children = children->next) {
386         GtkAllocation call;
387
388         call.x = alloc->x + border;
389         call.width = alloc->width - 2*border;
390         call.y = alloc->y + border;
391         call.height = alloc->height - 2*border;
392
393         gtk_widget_size_allocate(child, &call);
394     }
395 }