Add a NO_HTMLHELP option, and enable it by default in the Cygwin Makefile,
[u/mdw/putty] / unix / gtkpanel.c
CommitLineData
d9b15094 1/*
2 * gtkpanel.c - implementation of the `Panels' GTK layout container.
3 */
4
5#include "gtkpanel.h"
6
7static void panels_init(Panels *panels);
8static void panels_class_init(PanelsClass *klass);
9static void panels_map(GtkWidget *widget);
10static void panels_unmap(GtkWidget *widget);
11static void panels_draw(GtkWidget *widget, GdkRectangle *area);
12static gint panels_expose(GtkWidget *widget, GdkEventExpose *event);
13static void panels_base_add(GtkContainer *container, GtkWidget *widget);
14static void panels_remove(GtkContainer *container, GtkWidget *widget);
15static void panels_forall(GtkContainer *container, gboolean include_internals,
16 GtkCallback callback, gpointer callback_data);
17static GtkType panels_child_type(GtkContainer *container);
18static void panels_size_request(GtkWidget *widget, GtkRequisition *req);
19static void panels_size_allocate(GtkWidget *widget, GtkAllocation *alloc);
20
21static GtkContainerClass *parent_class = NULL;
22
23GtkType 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
45static 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
75static 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 */
87static 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}
108static 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}
129static 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}
152static 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
181static 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
194static 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
223static void panels_forall(GtkContainer *container, gboolean include_internals,
224 GtkCallback callback, gpointer callback_data)
225{
226 Panels *panels;
227 GtkWidget *child;
39016687 228 GList *children, *next;
d9b15094 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);
39016687 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;
d9b15094 248 if (child)
249 callback(child, callback_data);
39016687 250 }
d9b15094 251}
252
253static GtkType panels_child_type(GtkContainer *container)
254{
255 return GTK_TYPE_WIDGET;
256}
257
258GtkWidget *panels_new(void)
259{
260 Panels *panels;
261
262 panels = gtk_type_new(panels_get_type());
263
264 return GTK_WIDGET(panels);
265}
266
267void 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
288void panels_switch_to(Panels *panels, GtkWidget *target)
289{
7ffdbc1a 290 GtkWidget *child = NULL;
d9b15094 291 GList *children;
7ffdbc1a 292 gboolean changed = FALSE;
d9b15094 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
337static 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
368static 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
d9b15094 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}