1 | /* |
2 | * gtkoverlay.c |
3 | * This file is part of gtk |
4 | * |
5 | * Copyright (C) 2011 - Ignacio Casal Quinteiro, Mike Krüger |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | #include "config.h" |
22 | |
23 | #include "gtkoverlay.h" |
24 | |
25 | #include "gtkoverlaylayout.h" |
26 | #include "gtkbuildable.h" |
27 | #include "gtkintl.h" |
28 | #include "gtkmarshalers.h" |
29 | #include "gtkprivate.h" |
30 | #include "gtkscrolledwindow.h" |
31 | #include "gtksnapshot.h" |
32 | #include "gtkwidgetprivate.h" |
33 | |
34 | /** |
35 | * GtkOverlay |
36 | * |
37 | * `GtkOverlay` is a container which contains a single main child, on top |
38 | * of which it can place “overlay” widgets. |
39 | * |
40 | * ![An example GtkOverlay](overlay.png) |
41 | * |
42 | * The position of each overlay widget is determined by its |
43 | * [property@Gtk.Widget:halign] and [property@Gtk.Widget:valign] |
44 | * properties. E.g. a widget with both alignments set to %GTK_ALIGN_START |
45 | * will be placed at the top left corner of the `GtkOverlay` container, |
46 | * whereas an overlay with halign set to %GTK_ALIGN_CENTER and valign set |
47 | * to %GTK_ALIGN_END will be placed a the bottom edge of the `GtkOverlay`, |
48 | * horizontally centered. The position can be adjusted by setting the margin |
49 | * properties of the child to non-zero values. |
50 | * |
51 | * More complicated placement of overlays is possible by connecting |
52 | * to the [signal@Gtk.Overlay::get-child-position] signal. |
53 | * |
54 | * An overlay’s minimum and natural sizes are those of its main child. |
55 | * The sizes of overlay children are not considered when measuring these |
56 | * preferred sizes. |
57 | * |
58 | * # GtkOverlay as GtkBuildable |
59 | * |
60 | * The `GtkOverlay` implementation of the `GtkBuildable` interface |
61 | * supports placing a child as an overlay by specifying “overlay” as |
62 | * the “type” attribute of a `<child>` element. |
63 | * |
64 | * # CSS nodes |
65 | * |
66 | * `GtkOverlay` has a single CSS node with the name “overlay”. Overlay children |
67 | * whose alignments cause them to be positioned at an edge get the style classes |
68 | * “.left”, “.right”, “.top”, and/or “.bottom” according to their position. |
69 | */ |
70 | |
71 | enum { |
72 | GET_CHILD_POSITION, |
73 | LAST_SIGNAL |
74 | }; |
75 | |
76 | static guint signals[LAST_SIGNAL] = { 0 }; |
77 | |
78 | enum { |
79 | PROP_CHILD = 1 |
80 | }; |
81 | |
82 | static void gtk_overlay_buildable_init (GtkBuildableIface *iface); |
83 | |
84 | typedef struct _GtkOverlayClass GtkOverlayClass; |
85 | |
86 | struct _GtkOverlay |
87 | { |
88 | GtkWidget parent_instance; |
89 | |
90 | GtkWidget *child; |
91 | }; |
92 | |
93 | struct _GtkOverlayClass |
94 | { |
95 | GtkWidgetClass parent_class; |
96 | |
97 | gboolean (*get_child_position) (GtkOverlay *overlay, |
98 | GtkWidget *widget, |
99 | GtkAllocation *allocation); |
100 | }; |
101 | |
102 | G_DEFINE_TYPE_WITH_CODE (GtkOverlay, gtk_overlay, GTK_TYPE_WIDGET, |
103 | G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, |
104 | gtk_overlay_buildable_init)) |
105 | |
106 | static GtkAlign |
107 | effective_align (GtkAlign align, |
108 | GtkTextDirection direction) |
109 | { |
110 | switch (align) |
111 | { |
112 | case GTK_ALIGN_START: |
113 | return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START; |
114 | case GTK_ALIGN_END: |
115 | return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END; |
116 | case GTK_ALIGN_FILL: |
117 | case GTK_ALIGN_CENTER: |
118 | case GTK_ALIGN_BASELINE: |
119 | default: |
120 | return align; |
121 | } |
122 | } |
123 | |
124 | static gboolean |
125 | gtk_overlay_get_child_position (GtkOverlay *overlay, |
126 | GtkWidget *widget, |
127 | GtkAllocation *alloc) |
128 | { |
129 | GtkRequisition min, req; |
130 | GtkAlign halign; |
131 | GtkTextDirection direction; |
132 | int width, height; |
133 | |
134 | gtk_widget_get_preferred_size (widget, minimum_size: &min, natural_size: &req); |
135 | width = gtk_widget_get_width (GTK_WIDGET (overlay)); |
136 | height = gtk_widget_get_height (GTK_WIDGET (overlay)); |
137 | |
138 | alloc->x = 0; |
139 | alloc->width = MAX (min.width, MIN (width, req.width)); |
140 | |
141 | direction = _gtk_widget_get_direction (widget); |
142 | |
143 | halign = gtk_widget_get_halign (widget); |
144 | switch (effective_align (align: halign, direction)) |
145 | { |
146 | case GTK_ALIGN_START: |
147 | /* nothing to do */ |
148 | break; |
149 | case GTK_ALIGN_FILL: |
150 | alloc->width = MAX (alloc->width, width); |
151 | break; |
152 | case GTK_ALIGN_CENTER: |
153 | alloc->x += width / 2 - alloc->width / 2; |
154 | break; |
155 | case GTK_ALIGN_END: |
156 | alloc->x += width - alloc->width; |
157 | break; |
158 | case GTK_ALIGN_BASELINE: |
159 | default: |
160 | g_assert_not_reached (); |
161 | break; |
162 | } |
163 | |
164 | alloc->y = 0; |
165 | alloc->height = MAX (min.height, MIN (height, req.height)); |
166 | |
167 | switch (gtk_widget_get_valign (widget)) |
168 | { |
169 | case GTK_ALIGN_START: |
170 | /* nothing to do */ |
171 | break; |
172 | case GTK_ALIGN_FILL: |
173 | alloc->height = MAX (alloc->height, height); |
174 | break; |
175 | case GTK_ALIGN_CENTER: |
176 | alloc->y += height / 2 - alloc->height / 2; |
177 | break; |
178 | case GTK_ALIGN_END: |
179 | alloc->y += height - alloc->height; |
180 | break; |
181 | case GTK_ALIGN_BASELINE: |
182 | default: |
183 | g_assert_not_reached (); |
184 | break; |
185 | } |
186 | |
187 | return TRUE; |
188 | } |
189 | |
190 | static void |
191 | gtk_overlay_snapshot_child (GtkWidget *overlay, |
192 | GtkWidget *child, |
193 | GtkSnapshot *snapshot) |
194 | { |
195 | graphene_rect_t bounds; |
196 | gboolean clip_set; |
197 | |
198 | clip_set = gtk_overlay_get_clip_overlay (GTK_OVERLAY (overlay), widget: child); |
199 | |
200 | if (!clip_set) |
201 | { |
202 | gtk_widget_snapshot_child (widget: overlay, child, snapshot); |
203 | return; |
204 | } |
205 | |
206 | graphene_rect_init (r: &bounds, x: 0, y: 0, |
207 | width: gtk_widget_get_width (widget: overlay), |
208 | height: gtk_widget_get_height (widget: overlay)); |
209 | |
210 | gtk_snapshot_push_clip (snapshot, bounds: &bounds); |
211 | gtk_widget_snapshot_child (widget: overlay, child, snapshot); |
212 | gtk_snapshot_pop (snapshot); |
213 | } |
214 | |
215 | static void |
216 | gtk_overlay_snapshot (GtkWidget *widget, |
217 | GtkSnapshot *snapshot) |
218 | { |
219 | GtkWidget *child; |
220 | |
221 | for (child = _gtk_widget_get_first_child (widget); |
222 | child != NULL; |
223 | child = _gtk_widget_get_next_sibling (widget: child)) |
224 | { |
225 | gtk_overlay_snapshot_child (overlay: widget, child, snapshot); |
226 | } |
227 | } |
228 | |
229 | static void |
230 | gtk_overlay_get_property (GObject *object, |
231 | guint prop_id, |
232 | GValue *value, |
233 | GParamSpec *pspec) |
234 | { |
235 | GtkOverlay *overlay = GTK_OVERLAY (object); |
236 | |
237 | switch (prop_id) |
238 | { |
239 | case PROP_CHILD: |
240 | g_value_set_object (value, v_object: gtk_overlay_get_child (overlay)); |
241 | break; |
242 | |
243 | default: |
244 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
245 | break; |
246 | } |
247 | } |
248 | |
249 | static void |
250 | gtk_overlay_set_property (GObject *object, |
251 | guint prop_id, |
252 | const GValue *value, |
253 | GParamSpec *pspec) |
254 | { |
255 | GtkOverlay *overlay = GTK_OVERLAY (object); |
256 | |
257 | switch (prop_id) |
258 | { |
259 | case PROP_CHILD: |
260 | gtk_overlay_set_child (overlay, child: g_value_get_object (value)); |
261 | break; |
262 | |
263 | default: |
264 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
265 | break; |
266 | } |
267 | } |
268 | |
269 | static void |
270 | gtk_overlay_dispose (GObject *object) |
271 | { |
272 | GtkOverlay *overlay = GTK_OVERLAY (object); |
273 | GtkWidget *child; |
274 | |
275 | g_clear_pointer (&overlay->child, gtk_widget_unparent); |
276 | |
277 | while ((child = gtk_widget_get_first_child (GTK_WIDGET (overlay)))) |
278 | gtk_widget_unparent (widget: child); |
279 | |
280 | G_OBJECT_CLASS (gtk_overlay_parent_class)->dispose (object); |
281 | } |
282 | |
283 | static void |
284 | gtk_overlay_compute_expand (GtkWidget *widget, |
285 | gboolean *hexpand, |
286 | gboolean *vexpand) |
287 | { |
288 | GtkOverlay *overlay = GTK_OVERLAY (widget); |
289 | |
290 | if (overlay->child) |
291 | { |
292 | *hexpand = gtk_widget_compute_expand (widget: overlay->child, orientation: GTK_ORIENTATION_HORIZONTAL); |
293 | *vexpand = gtk_widget_compute_expand (widget: overlay->child, orientation: GTK_ORIENTATION_VERTICAL); |
294 | } |
295 | else |
296 | { |
297 | *hexpand = FALSE; |
298 | *vexpand = FALSE; |
299 | } |
300 | } |
301 | |
302 | static void |
303 | gtk_overlay_class_init (GtkOverlayClass *klass) |
304 | { |
305 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
306 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
307 | |
308 | object_class->dispose = gtk_overlay_dispose; |
309 | |
310 | object_class->get_property = gtk_overlay_get_property; |
311 | object_class->set_property = gtk_overlay_set_property; |
312 | |
313 | widget_class->snapshot = gtk_overlay_snapshot; |
314 | widget_class->compute_expand = gtk_overlay_compute_expand; |
315 | |
316 | klass->get_child_position = gtk_overlay_get_child_position; |
317 | |
318 | g_object_class_install_property (oclass: object_class, |
319 | property_id: PROP_CHILD, |
320 | pspec: g_param_spec_object (name: "child" , |
321 | P_("Child" ), |
322 | P_("The child widget" ), |
323 | GTK_TYPE_WIDGET, |
324 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); |
325 | |
326 | /** |
327 | * GtkOverlay::get-child-position: |
328 | * @overlay: the `GtkOverlay` |
329 | * @widget: the child widget to position |
330 | * @allocation: (type Gdk.Rectangle) (out caller-allocates): return |
331 | * location for the allocation |
332 | * |
333 | * Emitted to determine the position and size of any overlay |
334 | * child widgets. |
335 | * |
336 | * A handler for this signal should fill @allocation with |
337 | * the desired position and size for @widget, relative to |
338 | * the 'main' child of @overlay. |
339 | * |
340 | * The default handler for this signal uses the @widget's |
341 | * halign and valign properties to determine the position |
342 | * and gives the widget its natural size (except that an |
343 | * alignment of %GTK_ALIGN_FILL will cause the overlay to |
344 | * be full-width/height). If the main child is a |
345 | * `GtkScrolledWindow`, the overlays are placed relative |
346 | * to its contents. |
347 | * |
348 | * Returns: %TRUE if the @allocation has been filled |
349 | */ |
350 | signals[GET_CHILD_POSITION] = |
351 | g_signal_new (I_("get-child-position" ), |
352 | G_TYPE_FROM_CLASS (object_class), |
353 | signal_flags: G_SIGNAL_RUN_LAST, |
354 | G_STRUCT_OFFSET (GtkOverlayClass, get_child_position), |
355 | accumulator: _gtk_boolean_handled_accumulator, NULL, |
356 | c_marshaller: _gtk_marshal_BOOLEAN__OBJECT_BOXED, |
357 | G_TYPE_BOOLEAN, n_params: 2, |
358 | GTK_TYPE_WIDGET, |
359 | GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE); |
360 | g_signal_set_va_marshaller (signal_id: signals[GET_CHILD_POSITION], |
361 | G_TYPE_FROM_CLASS (object_class), |
362 | va_marshaller: _gtk_marshal_BOOLEAN__OBJECT_BOXEDv); |
363 | |
364 | gtk_widget_class_set_css_name (widget_class, I_("overlay" )); |
365 | |
366 | gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_OVERLAY_LAYOUT); |
367 | } |
368 | |
369 | static void |
370 | gtk_overlay_init (GtkOverlay *overlay) |
371 | { |
372 | } |
373 | |
374 | static GtkBuildableIface *parent_buildable_iface; |
375 | |
376 | static void |
377 | gtk_overlay_buildable_add_child (GtkBuildable *buildable, |
378 | GtkBuilder *builder, |
379 | GObject *child, |
380 | const char *type) |
381 | { |
382 | if (GTK_IS_WIDGET (child)) |
383 | { |
384 | if (type && strcmp (s1: type, s2: "overlay" ) == 0) |
385 | gtk_overlay_add_overlay (GTK_OVERLAY (buildable), GTK_WIDGET (child)); |
386 | else if (!type) |
387 | gtk_overlay_set_child (GTK_OVERLAY (buildable), GTK_WIDGET (child)); |
388 | else |
389 | GTK_BUILDER_WARN_INVALID_CHILD_TYPE (buildable, type); |
390 | } |
391 | else |
392 | { |
393 | parent_buildable_iface->add_child (buildable, builder, child, type); |
394 | } |
395 | } |
396 | |
397 | static void |
398 | gtk_overlay_buildable_init (GtkBuildableIface *iface) |
399 | { |
400 | parent_buildable_iface = g_type_interface_peek_parent (g_iface: iface); |
401 | |
402 | iface->add_child = gtk_overlay_buildable_add_child; |
403 | } |
404 | |
405 | /** |
406 | * gtk_overlay_new: |
407 | * |
408 | * Creates a new `GtkOverlay`. |
409 | * |
410 | * Returns: a new `GtkOverlay` object. |
411 | */ |
412 | GtkWidget * |
413 | gtk_overlay_new (void) |
414 | { |
415 | return g_object_new (GTK_TYPE_OVERLAY, NULL); |
416 | } |
417 | |
418 | /** |
419 | * gtk_overlay_add_overlay: |
420 | * @overlay: a `GtkOverlay` |
421 | * @widget: a `GtkWidget` to be added to the container |
422 | * |
423 | * Adds @widget to @overlay. |
424 | * |
425 | * The widget will be stacked on top of the main widget |
426 | * added with [method@Gtk.Overlay.set_child]. |
427 | * |
428 | * The position at which @widget is placed is determined |
429 | * from its [property@Gtk.Widget:halign] and |
430 | * [property@Gtk.Widget:valign] properties. |
431 | */ |
432 | void |
433 | gtk_overlay_add_overlay (GtkOverlay *overlay, |
434 | GtkWidget *widget) |
435 | { |
436 | g_return_if_fail (GTK_IS_OVERLAY (overlay)); |
437 | g_return_if_fail (GTK_IS_WIDGET (widget)); |
438 | g_return_if_fail (widget != overlay->child); |
439 | |
440 | gtk_widget_insert_before (widget, GTK_WIDGET (overlay), NULL); |
441 | } |
442 | |
443 | /** |
444 | * gtk_overlay_remove_overlay: |
445 | * @overlay: a `GtkOverlay` |
446 | * @widget: a `GtkWidget` to be removed |
447 | * |
448 | * Removes an overlay that was added with gtk_overlay_add_overlay(). |
449 | */ |
450 | void |
451 | gtk_overlay_remove_overlay (GtkOverlay *overlay, |
452 | GtkWidget *widget) |
453 | { |
454 | g_return_if_fail (GTK_IS_OVERLAY (overlay)); |
455 | g_return_if_fail (GTK_IS_WIDGET (widget)); |
456 | g_return_if_fail (gtk_widget_get_parent (widget) == GTK_WIDGET (overlay)); |
457 | g_return_if_fail (widget != overlay->child); |
458 | |
459 | gtk_widget_unparent (widget); |
460 | } |
461 | |
462 | /** |
463 | * gtk_overlay_set_measure_overlay: |
464 | * @overlay: a `GtkOverlay` |
465 | * @widget: an overlay child of `GtkOverlay` |
466 | * @measure: whether the child should be measured |
467 | * |
468 | * Sets whether @widget is included in the measured size of @overlay. |
469 | * |
470 | * The overlay will request the size of the largest child that has |
471 | * this property set to %TRUE. Children who are not included may |
472 | * be drawn outside of @overlay's allocation if they are too large. |
473 | */ |
474 | void |
475 | gtk_overlay_set_measure_overlay (GtkOverlay *overlay, |
476 | GtkWidget *widget, |
477 | gboolean measure) |
478 | { |
479 | GtkLayoutManager *layout; |
480 | GtkOverlayLayoutChild *child; |
481 | |
482 | g_return_if_fail (GTK_IS_OVERLAY (overlay)); |
483 | g_return_if_fail (GTK_IS_WIDGET (widget)); |
484 | |
485 | layout = gtk_widget_get_layout_manager (GTK_WIDGET (overlay)); |
486 | child = GTK_OVERLAY_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: layout, child: widget)); |
487 | gtk_overlay_layout_child_set_measure (child, measure); |
488 | } |
489 | |
490 | /** |
491 | * gtk_overlay_get_measure_overlay: |
492 | * @overlay: a `GtkOverlay` |
493 | * @widget: an overlay child of `GtkOverlay` |
494 | * |
495 | * Gets whether @widget's size is included in the measurement of |
496 | * @overlay. |
497 | * |
498 | * Returns: whether the widget is measured |
499 | */ |
500 | gboolean |
501 | gtk_overlay_get_measure_overlay (GtkOverlay *overlay, |
502 | GtkWidget *widget) |
503 | { |
504 | GtkLayoutManager *layout; |
505 | GtkOverlayLayoutChild *child; |
506 | |
507 | g_return_val_if_fail (GTK_IS_OVERLAY (overlay), FALSE); |
508 | g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); |
509 | |
510 | layout = gtk_widget_get_layout_manager (GTK_WIDGET (overlay)); |
511 | child = GTK_OVERLAY_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: layout, child: widget)); |
512 | return gtk_overlay_layout_child_get_measure (child); |
513 | } |
514 | |
515 | /** |
516 | * gtk_overlay_set_clip_overlay: |
517 | * @overlay: a `GtkOverlay` |
518 | * @widget: an overlay child of `GtkOverlay` |
519 | * @clip_overlay: whether the child should be clipped |
520 | * |
521 | * Sets whether @widget should be clipped within the parent. |
522 | */ |
523 | void |
524 | gtk_overlay_set_clip_overlay (GtkOverlay *overlay, |
525 | GtkWidget *widget, |
526 | gboolean clip_overlay) |
527 | { |
528 | GtkLayoutManager *layout; |
529 | GtkOverlayLayoutChild *child; |
530 | |
531 | g_return_if_fail (GTK_IS_OVERLAY (overlay)); |
532 | g_return_if_fail (GTK_IS_WIDGET (widget)); |
533 | |
534 | layout = gtk_widget_get_layout_manager (GTK_WIDGET (overlay)); |
535 | child = GTK_OVERLAY_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: layout, child: widget)); |
536 | gtk_overlay_layout_child_set_clip_overlay (child, clip_overlay); |
537 | } |
538 | |
539 | /** |
540 | * gtk_overlay_get_clip_overlay: |
541 | * @overlay: a `GtkOverlay` |
542 | * @widget: an overlay child of `GtkOverlay` |
543 | * |
544 | * Gets whether @widget should be clipped within the parent. |
545 | * |
546 | * Returns: whether the widget is clipped within the parent. |
547 | */ |
548 | gboolean |
549 | gtk_overlay_get_clip_overlay (GtkOverlay *overlay, |
550 | GtkWidget *widget) |
551 | { |
552 | GtkLayoutManager *layout; |
553 | GtkOverlayLayoutChild *child; |
554 | |
555 | g_return_val_if_fail (GTK_IS_OVERLAY (overlay), FALSE); |
556 | g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); |
557 | |
558 | layout = gtk_widget_get_layout_manager (GTK_WIDGET (overlay)); |
559 | child = GTK_OVERLAY_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: layout, child: widget)); |
560 | |
561 | return gtk_overlay_layout_child_get_clip_overlay (child); |
562 | } |
563 | |
564 | /** |
565 | * gtk_overlay_set_child: |
566 | * @overlay: a `GtkOverlay` |
567 | * @child: (nullable): the child widget |
568 | * |
569 | * Sets the child widget of @overlay. |
570 | */ |
571 | void |
572 | gtk_overlay_set_child (GtkOverlay *overlay, |
573 | GtkWidget *child) |
574 | { |
575 | g_return_if_fail (GTK_IS_OVERLAY (overlay)); |
576 | g_return_if_fail (child == NULL || GTK_IS_WIDGET (child)); |
577 | |
578 | g_clear_pointer (&overlay->child, gtk_widget_unparent); |
579 | |
580 | overlay->child = child; |
581 | |
582 | if (child) |
583 | { |
584 | /* Make sure the main-child node is the first one */ |
585 | gtk_widget_insert_after (widget: child, GTK_WIDGET (overlay), NULL); |
586 | } |
587 | |
588 | g_object_notify (G_OBJECT (overlay), property_name: "child" ); |
589 | } |
590 | |
591 | /** |
592 | * gtk_overlay_get_child: |
593 | * @overlay: a `GtkOverlay` |
594 | * |
595 | * Gets the child widget of @overlay. |
596 | * |
597 | * Returns: (nullable) (transfer none): the child widget of @overlay |
598 | */ |
599 | GtkWidget * |
600 | gtk_overlay_get_child (GtkOverlay *overlay) |
601 | { |
602 | g_return_val_if_fail (GTK_IS_OVERLAY (overlay), NULL); |
603 | |
604 | return overlay->child; |
605 | } |
606 | |