2 * gtkpanel.c - implementation of the `Panels' GTK layout container.
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
);
21 static GtkContainerClass
*parent_class
= NULL
;
23 GtkType
panels_get_type(void)
25 static GtkType panels_type
= 0;
28 static const GtkTypeInfo panels_info
= {
32 (GtkClassInitFunc
) panels_class_init
,
33 (GtkObjectInitFunc
) panels_init
,
34 /* reserved_1 */ NULL
,
35 /* reserved_2 */ NULL
,
36 (GtkClassInitFunc
) NULL
,
39 panels_type
= gtk_type_unique(GTK_TYPE_CONTAINER
, &panels_info
);
45 static void panels_class_init(PanelsClass
*klass
)
47 GtkObjectClass
*object_class
;
48 GtkWidgetClass
*widget_class
;
49 GtkContainerClass
*container_class
;
51 object_class
= (GtkObjectClass
*)klass
;
52 widget_class
= (GtkWidgetClass
*)klass
;
53 container_class
= (GtkContainerClass
*)klass
;
55 parent_class
= gtk_type_class(GTK_TYPE_CONTAINER
);
58 * FIXME: do we have to do all this faffing with set_arg,
59 * get_arg and child_arg_type? Ick.
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
;
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
;
75 static void panels_init(Panels
*panels
)
77 GTK_WIDGET_SET_FLAGS(panels
, GTK_NO_WINDOW
);
79 panels
->children
= NULL
;
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...
87 static void panels_map(GtkWidget
*widget
)
93 g_return_if_fail(widget
!= NULL
);
94 g_return_if_fail(IS_PANELS(widget
));
96 panels
= PANELS(widget
);
97 GTK_WIDGET_SET_FLAGS(panels
, GTK_MAPPED
);
99 for (children
= panels
->children
;
100 children
&& (child
= children
->data
);
101 children
= children
->next
) {
103 GTK_WIDGET_VISIBLE(child
) &&
104 !GTK_WIDGET_MAPPED(child
))
105 gtk_widget_map(child
);
108 static void panels_unmap(GtkWidget
*widget
)
114 g_return_if_fail(widget
!= NULL
);
115 g_return_if_fail(IS_PANELS(widget
));
117 panels
= PANELS(widget
);
118 GTK_WIDGET_UNSET_FLAGS(panels
, GTK_MAPPED
);
120 for (children
= panels
->children
;
121 children
&& (child
= children
->data
);
122 children
= children
->next
) {
124 GTK_WIDGET_VISIBLE(child
) &&
125 GTK_WIDGET_MAPPED(child
))
126 gtk_widget_unmap(child
);
129 static void panels_draw(GtkWidget
*widget
, GdkRectangle
*area
)
134 GdkRectangle child_area
;
136 g_return_if_fail(widget
!= NULL
);
137 g_return_if_fail(IS_PANELS(widget
));
139 if (GTK_WIDGET_DRAWABLE(widget
)) {
140 panels
= PANELS(widget
);
142 for (children
= panels
->children
;
143 children
&& (child
= children
->data
);
144 children
= children
->next
) {
146 GTK_WIDGET_DRAWABLE(child
) &&
147 gtk_widget_intersect(child
, area
, &child_area
))
148 gtk_widget_draw(child
, &child_area
);
152 static gint
panels_expose(GtkWidget
*widget
, GdkEventExpose
*event
)
157 GdkEventExpose child_event
;
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
);
163 if (GTK_WIDGET_DRAWABLE(widget
)) {
164 panels
= PANELS(widget
);
165 child_event
= *event
;
167 for (children
= panels
->children
;
168 children
&& (child
= children
->data
);
169 children
= children
->next
) {
171 GTK_WIDGET_DRAWABLE(child
) &&
172 GTK_WIDGET_NO_WINDOW(child
) &&
173 gtk_widget_intersect(child
, &event
->area
,
175 gtk_widget_event(child
, (GdkEvent
*)&child_event
);
181 static void panels_base_add(GtkContainer
*container
, GtkWidget
*widget
)
185 g_return_if_fail(container
!= NULL
);
186 g_return_if_fail(IS_PANELS(container
));
187 g_return_if_fail(widget
!= NULL
);
189 panels
= PANELS(container
);
191 panels_add(panels
, widget
);
194 static void panels_remove(GtkContainer
*container
, GtkWidget
*widget
)
199 gboolean was_visible
;
201 g_return_if_fail(container
!= NULL
);
202 g_return_if_fail(IS_PANELS(container
));
203 g_return_if_fail(widget
!= NULL
);
205 panels
= PANELS(container
);
207 for (children
= panels
->children
;
208 children
&& (child
= children
->data
);
209 children
= children
->next
) {
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
);
218 gtk_widget_queue_resize(GTK_WIDGET(container
));
223 static void panels_forall(GtkContainer
*container
, gboolean include_internals
,
224 GtkCallback callback
, gpointer callback_data
)
228 GList
*children
, *next
;
230 g_return_if_fail(container
!= NULL
);
231 g_return_if_fail(IS_PANELS(container
));
232 g_return_if_fail(callback
!= NULL
);
234 panels
= PANELS(container
);
236 for (children
= panels
->children
;
237 children
&& (child
= children
->data
);
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
247 next
= children
->next
;
249 callback(child
, callback_data
);
253 static GtkType
panels_child_type(GtkContainer
*container
)
255 return GTK_TYPE_WIDGET
;
258 GtkWidget
*panels_new(void)
262 panels
= gtk_type_new(panels_get_type());
264 return GTK_WIDGET(panels
);
267 void panels_add(Panels
*panels
, GtkWidget
*child
)
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
);
274 panels
->children
= g_list_append(panels
->children
, child
);
276 gtk_widget_set_parent(child
, GTK_WIDGET(panels
));
278 if (GTK_WIDGET_REALIZED(panels
))
279 gtk_widget_realize(child
);
281 if (GTK_WIDGET_VISIBLE(panels
)) {
282 if (GTK_WIDGET_MAPPED(panels
))
283 gtk_widget_map(child
);
284 gtk_widget_queue_resize(child
);
288 void panels_switch_to(Panels
*panels
, GtkWidget
*target
)
290 GtkWidget
*child
= NULL
;
292 gboolean changed
= FALSE
;
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
));
299 for (children
= panels
->children
;
300 children
&& (child
= children
->data
);
301 children
= children
->next
) {
306 if (child
== target
) {
307 if (!GTK_WIDGET_VISIBLE(child
)) {
308 gtk_widget_show(child
);
312 if (GTK_WIDGET_VISIBLE(child
)) {
313 gtk_widget_hide(child
);
319 gtk_widget_queue_resize(child
);
323 * Now here comes the interesting bit. The actual layout part is
324 * done in the following two functions:
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.
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
337 static void panels_size_request(GtkWidget
*widget
, GtkRequisition
*req
)
343 g_return_if_fail(widget
!= NULL
);
344 g_return_if_fail(IS_PANELS(widget
));
345 g_return_if_fail(req
!= NULL
);
347 panels
= PANELS(widget
);
352 for (children
= panels
->children
;
353 children
&& (child
= children
->data
);
354 children
= children
->next
) {
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
;
364 req
->width
+= 2*GTK_CONTAINER(panels
)->border_width
;
365 req
->height
+= 2*GTK_CONTAINER(panels
)->border_width
;
368 static void panels_size_allocate(GtkWidget
*widget
, GtkAllocation
*alloc
)
375 g_return_if_fail(widget
!= NULL
);
376 g_return_if_fail(IS_PANELS(widget
));
377 g_return_if_fail(alloc
!= NULL
);
379 panels
= PANELS(widget
);
380 widget
->allocation
= *alloc
;
381 border
= GTK_CONTAINER(panels
)->border_width
;
383 for (children
= panels
->children
;
384 children
&& (child
= children
->data
);
385 children
= children
->next
) {
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
;
393 gtk_widget_size_allocate(child
, &call
);