xref: /vim-8.2.3635/src/gui_gtk_f.c (revision 94688b8a)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved		by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * (C) 1998,1999 by Marcin Dalecki <[email protected]>
12  *
13  * Support for GTK+ 2 was added by:
14  *
15  * (C) 2002,2003  Jason Hildebrand  <[email protected]>
16  *		  Daniel Elstner  <[email protected]>
17  *
18  * This is a special purpose container widget, which manages arbitrary
19  * children at arbitrary positions width arbitrary sizes.  This finally puts
20  * an end on our resize problems with which we where struggling for such a
21  * long time.
22  *
23  * Support for GTK+ 3 was added by:
24  *
25  * 2016  Kazunobu Kuriyama  <[email protected]>
26  */
27 
28 #include "vim.h"
29 #include <gtk/gtk.h>	/* without this it compiles, but gives errors at
30 			   runtime! */
31 #include "gui_gtk_f.h"
32 #if !GTK_CHECK_VERSION(3,0,0)
33 # include <gtk/gtksignal.h>
34 #endif
35 #ifdef WIN3264
36 # include <gdk/gdkwin32.h>
37 #else
38 # include <gdk/gdkx.h>
39 #endif
40 
41 typedef struct _GtkFormChild GtkFormChild;
42 
43 struct _GtkFormChild
44 {
45     GtkWidget *widget;
46     GdkWindow *window;
47     gint x;		/* relative subwidget x position */
48     gint y;		/* relative subwidget y position */
49     gint mapped;
50 };
51 
52 
53 static void gtk_form_class_init(GtkFormClass *klass);
54 static void gtk_form_init(GtkForm *form);
55 
56 static void gtk_form_realize(GtkWidget *widget);
57 static void gtk_form_unrealize(GtkWidget *widget);
58 static void gtk_form_map(GtkWidget *widget);
59 static void gtk_form_size_request(GtkWidget *widget,
60 				  GtkRequisition *requisition);
61 #if GTK_CHECK_VERSION(3,0,0)
62 static void gtk_form_get_preferred_width(GtkWidget *widget,
63 					 gint *minimal_width,
64 					 gint *natural_width);
65 static void gtk_form_get_preferred_height(GtkWidget *widget,
66 					  gint *minimal_height,
67 					  gint *natural_height);
68 #endif
69 static void gtk_form_size_allocate(GtkWidget *widget,
70 				   GtkAllocation *allocation);
71 #if GTK_CHECK_VERSION(3,0,0)
72 static gboolean gtk_form_draw(GtkWidget *widget,
73 			      cairo_t *cr);
74 #else
75 static gint gtk_form_expose(GtkWidget *widget,
76 			    GdkEventExpose *event);
77 #endif
78 
79 static void gtk_form_remove(GtkContainer *container,
80 			    GtkWidget *widget);
81 static void gtk_form_forall(GtkContainer *container,
82 			    gboolean include_internals,
83 			    GtkCallback callback,
84 			    gpointer callback_data);
85 
86 static void gtk_form_attach_child_window(GtkForm *form,
87 					 GtkFormChild *child);
88 static void gtk_form_realize_child(GtkForm *form,
89 				   GtkFormChild *child);
90 static void gtk_form_position_child(GtkForm *form,
91 				    GtkFormChild *child,
92 				    gboolean force_allocate);
93 static void gtk_form_position_children(GtkForm *form);
94 
95 static void gtk_form_send_configure(GtkForm *form);
96 
97 static void gtk_form_child_map(GtkWidget *widget, gpointer user_data);
98 static void gtk_form_child_unmap(GtkWidget *widget, gpointer user_data);
99 
100 #if !GTK_CHECK_VERSION(3,0,0)
101 static GtkWidgetClass *parent_class = NULL;
102 #endif
103 
104 /* Public interface
105  */
106 
107     GtkWidget *
108 gtk_form_new(void)
109 {
110     GtkForm *form;
111 
112 #if GTK_CHECK_VERSION(3,0,0)
113     form = g_object_new(GTK_TYPE_FORM, NULL);
114 #else
115     form = gtk_type_new(gtk_form_get_type());
116 #endif
117 
118     return GTK_WIDGET(form);
119 }
120 
121     void
122 gtk_form_put(GtkForm	*form,
123 	     GtkWidget	*child_widget,
124 	     gint	x,
125 	     gint	y)
126 {
127     GtkFormChild *child;
128 
129     g_return_if_fail(GTK_IS_FORM(form));
130 
131     /* LINTED: avoid warning: conversion to 'unsigned long' */
132     child = g_new(GtkFormChild, 1);
133 
134     child->widget = child_widget;
135     child->window = NULL;
136     child->x = x;
137     child->y = y;
138 #if GTK_CHECK_VERSION(3,0,0)
139     gtk_widget_set_size_request(child->widget, -1, -1);
140 #else
141     child->widget->requisition.width = 0;
142     child->widget->requisition.height = 0;
143 #endif
144     child->mapped = FALSE;
145 
146     form->children = g_list_append(form->children, child);
147 
148     /* child->window must be created and attached to the widget _before_
149      * it has been realized, or else things will break with GTK2.  Note
150      * that gtk_widget_set_parent() realizes the widget if it's visible
151      * and its parent is mapped.
152      */
153     if (gtk_widget_get_realized(GTK_WIDGET(form)))
154 	gtk_form_attach_child_window(form, child);
155 
156     gtk_widget_set_parent(child_widget, GTK_WIDGET(form));
157 
158     if (gtk_widget_get_realized(GTK_WIDGET(form))
159 	    && !gtk_widget_get_realized(child_widget))
160 	gtk_form_realize_child(form, child);
161 
162     gtk_form_position_child(form, child, TRUE);
163 }
164 
165     void
166 gtk_form_move(GtkForm	*form,
167 	      GtkWidget	*child_widget,
168 	      gint	x,
169 	      gint	y)
170 {
171     GList *tmp_list;
172     GtkFormChild *child;
173 
174     g_return_if_fail(GTK_IS_FORM(form));
175 
176     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
177     {
178 	child = tmp_list->data;
179 	if (child->widget == child_widget)
180 	{
181 	    child->x = x;
182 	    child->y = y;
183 
184 	    gtk_form_position_child(form, child, TRUE);
185 	    return;
186 	}
187     }
188 }
189 
190     void
191 gtk_form_freeze(GtkForm *form)
192 {
193     g_return_if_fail(GTK_IS_FORM(form));
194 
195     ++form->freeze_count;
196 }
197 
198     void
199 gtk_form_thaw(GtkForm *form)
200 {
201     g_return_if_fail(GTK_IS_FORM(form));
202 
203     if (form->freeze_count)
204     {
205 	if (!(--form->freeze_count))
206 	{
207 	    gtk_form_position_children(form);
208 	    gtk_widget_queue_draw(GTK_WIDGET(form));
209 	}
210     }
211 }
212 
213 /* Basic Object handling procedures
214  */
215 #if GTK_CHECK_VERSION(3,0,0)
216 G_DEFINE_TYPE(GtkForm, gtk_form, GTK_TYPE_CONTAINER)
217 #else
218     GtkType
219 gtk_form_get_type(void)
220 {
221     static GtkType form_type = 0;
222 
223     if (!form_type)
224     {
225 	GtkTypeInfo form_info;
226 
227 	vim_memset(&form_info, 0, sizeof(form_info));
228 	form_info.type_name = "GtkForm";
229 	form_info.object_size = sizeof(GtkForm);
230 	form_info.class_size = sizeof(GtkFormClass);
231 	form_info.class_init_func = (GtkClassInitFunc)gtk_form_class_init;
232 	form_info.object_init_func = (GtkObjectInitFunc)gtk_form_init;
233 
234 	form_type = gtk_type_unique(GTK_TYPE_CONTAINER, &form_info);
235     }
236     return form_type;
237 }
238 #endif /* !GTK_CHECK_VERSION(3,0,0) */
239 
240     static void
241 gtk_form_class_init(GtkFormClass *klass)
242 {
243     GtkWidgetClass *widget_class;
244     GtkContainerClass *container_class;
245 
246     widget_class = (GtkWidgetClass *) klass;
247     container_class = (GtkContainerClass *) klass;
248 
249 #if !GTK_CHECK_VERSION(3,0,0)
250     parent_class = gtk_type_class(gtk_container_get_type());
251 #endif
252 
253     widget_class->realize = gtk_form_realize;
254     widget_class->unrealize = gtk_form_unrealize;
255     widget_class->map = gtk_form_map;
256 #if GTK_CHECK_VERSION(3,0,0)
257     widget_class->get_preferred_width = gtk_form_get_preferred_width;
258     widget_class->get_preferred_height = gtk_form_get_preferred_height;
259 #else
260     widget_class->size_request = gtk_form_size_request;
261 #endif
262     widget_class->size_allocate = gtk_form_size_allocate;
263 #if GTK_CHECK_VERSION(3,0,0)
264     widget_class->draw = gtk_form_draw;
265 #else
266     widget_class->expose_event = gtk_form_expose;
267 #endif
268 
269     container_class->remove = gtk_form_remove;
270     container_class->forall = gtk_form_forall;
271 }
272 
273     static void
274 gtk_form_init(GtkForm *form)
275 {
276 #if GTK_CHECK_VERSION(3,0,0)
277     gtk_widget_set_has_window(GTK_WIDGET(form), TRUE);
278 #endif
279     form->children = NULL;
280     form->bin_window = NULL;
281     form->freeze_count = 0;
282 }
283 
284 /*
285  * Widget methods
286  */
287 
288     static void
289 gtk_form_realize(GtkWidget *widget)
290 {
291     GList *tmp_list;
292     GtkForm *form;
293     GdkWindowAttr attributes;
294     gint attributes_mask;
295     GtkAllocation allocation;
296 
297     g_return_if_fail(GTK_IS_FORM(widget));
298 
299     form = GTK_FORM(widget);
300     gtk_widget_set_realized(widget, TRUE);
301 
302     gtk_widget_get_allocation(widget, &allocation);
303     attributes.window_type = GDK_WINDOW_CHILD;
304     attributes.x = allocation.x;
305     attributes.y = allocation.y;
306     attributes.width = allocation.width;
307     attributes.height = allocation.height;
308     attributes.wclass = GDK_INPUT_OUTPUT;
309     attributes.visual = gtk_widget_get_visual(widget);
310 #if GTK_CHECK_VERSION(3,0,0)
311     attributes.event_mask = GDK_EXPOSURE_MASK;
312 #else
313     attributes.colormap = gtk_widget_get_colormap(widget);
314     attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
315 #endif
316 
317 #if GTK_CHECK_VERSION(3,0,0)
318     attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
319 #else
320     attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
321 #endif
322 
323     gtk_widget_set_window(widget,
324 			  gdk_window_new(gtk_widget_get_parent_window(widget),
325 					 &attributes, attributes_mask));
326     gdk_window_set_user_data(gtk_widget_get_window(widget), widget);
327 
328     attributes.x = 0;
329     attributes.y = 0;
330     attributes.event_mask = gtk_widget_get_events(widget);
331 
332     form->bin_window = gdk_window_new(gtk_widget_get_window(widget),
333 				      &attributes, attributes_mask);
334     gdk_window_set_user_data(form->bin_window, widget);
335 
336 #if GTK_CHECK_VERSION(3,0,0)
337     {
338 	GtkStyleContext * const sctx = gtk_widget_get_style_context(widget);
339 
340 	gtk_style_context_add_class(sctx, "gtk-form");
341 	gtk_style_context_set_state(sctx, GTK_STATE_FLAG_NORMAL);
342 # if !GTK_CHECK_VERSION(3,18,0)
343 	gtk_style_context_set_background(sctx, gtk_widget_get_window(widget));
344 	gtk_style_context_set_background(sctx, form->bin_window);
345 # endif
346     }
347 #else
348     widget->style = gtk_style_attach(widget->style, widget->window);
349     gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
350     gtk_style_set_background(widget->style, form->bin_window, GTK_STATE_NORMAL);
351 #endif
352 
353     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
354     {
355 	GtkFormChild *child = tmp_list->data;
356 
357 	gtk_form_attach_child_window(form, child);
358 
359 	if (gtk_widget_get_visible(child->widget))
360 	    gtk_form_realize_child(form, child);
361     }
362 }
363 
364 
365 /* After reading the documentation at
366  * http://developer.gnome.org/doc/API/2.0/gtk/gtk-changes-2-0.html
367  * I think it should be possible to remove this function when compiling
368  * against gtk-2.0.  It doesn't seem to cause problems, though.
369  *
370  * Well, I reckon at least the gdk_window_show(form->bin_window)
371  * is necessary.  GtkForm is anything but a usual container widget.
372  */
373     static void
374 gtk_form_map(GtkWidget *widget)
375 {
376     GList *tmp_list;
377     GtkForm *form;
378 
379     g_return_if_fail(GTK_IS_FORM(widget));
380 
381     form = GTK_FORM(widget);
382 
383     gtk_widget_set_mapped(widget, TRUE);
384 
385     gdk_window_show(gtk_widget_get_window(widget));
386     gdk_window_show(form->bin_window);
387 
388     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
389     {
390 	GtkFormChild *child = tmp_list->data;
391 
392 	if (gtk_widget_get_visible(child->widget)
393 		&& !gtk_widget_get_mapped(child->widget))
394 	    gtk_widget_map(child->widget);
395     }
396 }
397 
398     static void
399 gtk_form_unrealize(GtkWidget *widget)
400 {
401     GList *tmp_list;
402     GtkForm *form;
403 
404     g_return_if_fail(GTK_IS_FORM(widget));
405 
406     form = GTK_FORM(widget);
407 
408     tmp_list = form->children;
409 
410     gdk_window_set_user_data(form->bin_window, NULL);
411     gdk_window_destroy(form->bin_window);
412     form->bin_window = NULL;
413 
414     while (tmp_list)
415     {
416 	GtkFormChild *child = tmp_list->data;
417 
418 	if (child->window != NULL)
419 	{
420 	    g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget),
421 		    FUNC2GENERIC(gtk_form_child_map),
422 		    child);
423 	    g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget),
424 		    FUNC2GENERIC(gtk_form_child_unmap),
425 		    child);
426 
427 	    gdk_window_set_user_data(child->window, NULL);
428 	    gdk_window_destroy(child->window);
429 
430 	    child->window = NULL;
431 	}
432 
433 	tmp_list = tmp_list->next;
434     }
435 
436 #if GTK_CHECK_VERSION(3,0,0)
437     if (GTK_WIDGET_CLASS (gtk_form_parent_class)->unrealize)
438 	 (* GTK_WIDGET_CLASS (gtk_form_parent_class)->unrealize) (widget);
439 #else
440     if (GTK_WIDGET_CLASS (parent_class)->unrealize)
441 	 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
442 #endif
443 }
444 
445     static void
446 gtk_form_size_request(GtkWidget *widget, GtkRequisition *requisition)
447 {
448     g_return_if_fail(GTK_IS_FORM(widget));
449     g_return_if_fail(requisition != NULL);
450 
451     requisition->width = 1;
452     requisition->height = 1;
453 }
454 
455 #if GTK_CHECK_VERSION(3,0,0)
456     static void
457 gtk_form_get_preferred_width(GtkWidget *widget,
458 			     gint      *minimal_width,
459 			     gint      *natural_width)
460 {
461     GtkRequisition requisition;
462 
463     gtk_form_size_request(widget, &requisition);
464 
465     *minimal_width = requisition.width;
466     *natural_width = requisition.width;
467 }
468 
469     static void
470 gtk_form_get_preferred_height(GtkWidget *widget,
471 			      gint	*minimal_height,
472 			      gint	*natural_height)
473 {
474     GtkRequisition requisition;
475 
476     gtk_form_size_request(widget, &requisition);
477 
478     *minimal_height = requisition.height;
479     *natural_height = requisition.height;
480 }
481 #endif /* GTK_CHECK_VERSION(3,0,0) */
482 
483     static void
484 gtk_form_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
485 {
486     GList *tmp_list;
487     GtkForm *form;
488     gboolean need_reposition;
489     GtkAllocation cur_alloc;
490 
491     g_return_if_fail(GTK_IS_FORM(widget));
492 
493     gtk_widget_get_allocation(widget, &cur_alloc);
494 
495     if (cur_alloc.x == allocation->x
496 	    && cur_alloc.y == allocation->y
497 	    && cur_alloc.width == allocation->width
498 	    && cur_alloc.height == allocation->height)
499 	return;
500 
501     need_reposition = cur_alloc.width != allocation->width
502 		   || cur_alloc.height != allocation->height;
503     form = GTK_FORM(widget);
504 
505     if (need_reposition)
506     {
507 	tmp_list = form->children;
508 
509 	while (tmp_list)
510 	{
511 	    GtkFormChild *child = tmp_list->data;
512 	    gtk_form_position_child(form, child, TRUE);
513 
514 	    tmp_list = tmp_list->next;
515 	}
516     }
517 
518     if (gtk_widget_get_realized(widget))
519     {
520 	gdk_window_move_resize(gtk_widget_get_window(widget),
521 			       allocation->x, allocation->y,
522 			       allocation->width, allocation->height);
523 	gdk_window_move_resize(GTK_FORM(widget)->bin_window,
524 			       0, 0,
525 			       allocation->width, allocation->height);
526     }
527     gtk_widget_set_allocation(widget, allocation);
528     if (need_reposition)
529 	gtk_form_send_configure(form);
530 }
531 
532 #if GTK_CHECK_VERSION(3,0,0)
533     static void
534 gtk_form_render_background(GtkWidget *widget, cairo_t *cr)
535 {
536     gtk_render_background(gtk_widget_get_style_context(widget), cr,
537 			  0, 0,
538 			  gtk_widget_get_allocated_width(widget),
539 			  gtk_widget_get_allocated_height(widget));
540 }
541 
542     static gboolean
543 gtk_form_draw(GtkWidget *widget, cairo_t *cr)
544 {
545     GList   *tmp_list = NULL;
546     GtkForm *form     = NULL;
547 
548     g_return_val_if_fail(GTK_IS_FORM(widget), FALSE);
549 
550     gtk_form_render_background(widget, cr);
551 
552     form = GTK_FORM(widget);
553     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
554     {
555 	GtkFormChild * const formchild = tmp_list->data;
556 
557 	if (!gtk_widget_get_has_window(formchild->widget) &&
558 		gtk_cairo_should_draw_window(cr, formchild->window))
559 	{
560 	    /* To get gtk_widget_draw() to work, it is required to call
561 	     * gtk_widget_size_allocate() in advance with a well-posed
562 	     * allocation for a given child widget in order to set a
563 	     * certain private GtkWidget variable, called
564 	     * widget->priv->alloc_need, to the proper value; othewise,
565 	     * gtk_widget_draw() fails and the relevant scrollbar won't
566 	     * appear on the screen.
567 	     *
568 	     * Calling gtk_form_position_child() like this is one of ways
569 	     * to make sure of that. */
570 	    gtk_form_position_child(form, formchild, TRUE);
571 
572 	    gtk_form_render_background(formchild->widget, cr);
573 	}
574     }
575 
576     return GTK_WIDGET_CLASS(gtk_form_parent_class)->draw(widget, cr);
577 }
578 #else /* !GTK_CHECK_VERSION(3,0,0) */
579     static gint
580 gtk_form_expose(GtkWidget *widget, GdkEventExpose *event)
581 {
582     GList   *tmp_list;
583     GtkForm *form;
584 
585     g_return_val_if_fail(GTK_IS_FORM(widget), FALSE);
586 
587     form = GTK_FORM(widget);
588 
589     if (event->window == form->bin_window)
590 	return FALSE;
591 
592     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
593 	gtk_container_propagate_expose(GTK_CONTAINER(widget),
594 		GTK_WIDGET(((GtkFormChild *)tmp_list->data)->widget),
595 		event);
596 
597     return FALSE;
598 }
599 #endif /* !GTK_CHECK_VERSION(3,0,0) */
600 
601 /* Container method
602  */
603     static void
604 gtk_form_remove(GtkContainer *container, GtkWidget *widget)
605 {
606     GList *tmp_list;
607     GtkForm *form;
608     GtkFormChild *child = NULL;	    /* init for gcc */
609 
610     g_return_if_fail(GTK_IS_FORM(container));
611 
612     form = GTK_FORM(container);
613 
614     tmp_list = form->children;
615     while (tmp_list)
616     {
617 	child = tmp_list->data;
618 	if (child->widget == widget)
619 	    break;
620 	tmp_list = tmp_list->next;
621     }
622 
623     if (tmp_list)
624     {
625 #if GTK_CHECK_VERSION(3,0,0)
626 	const gboolean was_visible = gtk_widget_get_visible(widget);
627 #endif
628 	if (child->window)
629 	{
630 	    g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget),
631 		    FUNC2GENERIC(&gtk_form_child_map), child);
632 	    g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget),
633 		    FUNC2GENERIC(&gtk_form_child_unmap), child);
634 
635 	    /* FIXME: This will cause problems for reparenting NO_WINDOW
636 	     * widgets out of a GtkForm
637 	     */
638 	    gdk_window_set_user_data(child->window, NULL);
639 	    gdk_window_destroy(child->window);
640 	}
641 	gtk_widget_unparent(widget);
642 #if GTK_CHECK_VERSION(3,0,0)
643 	if (was_visible)
644 	    gtk_widget_queue_resize(GTK_WIDGET(container));
645 #endif
646 	form->children = g_list_remove_link(form->children, tmp_list);
647 	g_list_free_1(tmp_list);
648 	g_free(child);
649     }
650 }
651 
652     static void
653 gtk_form_forall(GtkContainer	*container,
654 		gboolean	include_internals UNUSED,
655 		GtkCallback	callback,
656 		gpointer	callback_data)
657 {
658     GtkForm *form;
659     GtkFormChild *child;
660     GList *tmp_list;
661 
662     g_return_if_fail(GTK_IS_FORM(container));
663     g_return_if_fail(callback != NULL);
664 
665     form = GTK_FORM(container);
666 
667     tmp_list = form->children;
668     while (tmp_list)
669     {
670 	child = tmp_list->data;
671 	tmp_list = tmp_list->next;
672 
673 	(*callback) (child->widget, callback_data);
674     }
675 }
676 
677 /* Operations on children
678  */
679 
680     static void
681 gtk_form_attach_child_window(GtkForm *form, GtkFormChild *child)
682 {
683     if (child->window != NULL)
684 	return; /* been there, done that */
685 
686     if (!gtk_widget_get_has_window(child->widget))
687     {
688 	GtkWidget	*widget;
689 	GdkWindowAttr	attributes;
690 	gint		attributes_mask;
691 	GtkRequisition	requisition;
692 
693 	widget = GTK_WIDGET(form);
694 
695 #if GTK_CHECK_VERSION(3,0,0)
696 	gtk_widget_get_preferred_size(child->widget, &requisition, NULL);
697 #else
698 	requisition = child->widget->requisition;
699 #endif
700 	attributes.window_type = GDK_WINDOW_CHILD;
701 	attributes.x = child->x;
702 	attributes.y = child->y;
703 	attributes.width = requisition.width;
704 	attributes.height = requisition.height;
705 	attributes.wclass = GDK_INPUT_OUTPUT;
706 	attributes.visual = gtk_widget_get_visual(widget);
707 #if !GTK_CHECK_VERSION(3,0,0)
708 	attributes.colormap = gtk_widget_get_colormap(widget);
709 #endif
710 	attributes.event_mask = GDK_EXPOSURE_MASK;
711 
712 #if GTK_CHECK_VERSION(3,0,0)
713 	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
714 #else
715 	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
716 #endif
717 	child->window = gdk_window_new(form->bin_window,
718 				       &attributes, attributes_mask);
719 	gdk_window_set_user_data(child->window, widget);
720 
721 #if GTK_CHECK_VERSION(3,0,0)
722 	{
723 	    GtkStyleContext * const sctx = gtk_widget_get_style_context(widget);
724 
725 	    gtk_style_context_set_state(sctx, GTK_STATE_FLAG_NORMAL);
726 # if !GTK_CHECK_VERSION(3,18,0)
727 	    gtk_style_context_set_background(sctx, child->window);
728 # endif
729 	}
730 #else
731 	gtk_style_set_background(widget->style,
732 				 child->window,
733 				 GTK_STATE_NORMAL);
734 #endif
735 
736 	gtk_widget_set_parent_window(child->widget, child->window);
737 	/*
738 	 * Install signal handlers to map/unmap child->window
739 	 * alongside with the actual widget.
740 	 */
741 	g_signal_connect(G_OBJECT(child->widget), "map",
742 			 G_CALLBACK(&gtk_form_child_map), child);
743 	g_signal_connect(G_OBJECT(child->widget), "unmap",
744 			 G_CALLBACK(&gtk_form_child_unmap), child);
745     }
746     else if (!gtk_widget_get_realized(child->widget))
747     {
748 	gtk_widget_set_parent_window(child->widget, form->bin_window);
749     }
750 }
751 
752     static void
753 gtk_form_realize_child(GtkForm *form, GtkFormChild *child)
754 {
755     gtk_form_attach_child_window(form, child);
756     gtk_widget_realize(child->widget);
757 }
758 
759     static void
760 gtk_form_position_child(GtkForm *form, GtkFormChild *child,
761 			gboolean force_allocate)
762 {
763     gint x;
764     gint y;
765 
766     x = child->x;
767     y = child->y;
768 
769     if ((x >= G_MINSHORT) && (x <= G_MAXSHORT) &&
770 	(y >= G_MINSHORT) && (y <= G_MAXSHORT))
771     {
772 	if (!child->mapped)
773 	{
774 	    if (gtk_widget_get_mapped(GTK_WIDGET(form))
775 		    && gtk_widget_get_visible(child->widget))
776 	    {
777 		if (!gtk_widget_get_mapped(child->widget))
778 		    gtk_widget_map(child->widget);
779 
780 		child->mapped = TRUE;
781 		force_allocate = TRUE;
782 	    }
783 	}
784 
785 	if (force_allocate)
786 	{
787 	    GtkAllocation allocation;
788 	    GtkRequisition requisition;
789 
790 #if GTK_CHECK_VERSION(3,0,0)
791 	    gtk_widget_get_preferred_size(child->widget, &requisition, NULL);
792 #else
793 	    requisition = child->widget->requisition;
794 #endif
795 
796 	    if (!gtk_widget_get_has_window(child->widget))
797 	    {
798 		if (child->window)
799 		{
800 		    gdk_window_move_resize(child->window,
801 			    x, y,
802 			    requisition.width,
803 			    requisition.height);
804 		}
805 
806 		allocation.x = 0;
807 		allocation.y = 0;
808 	    }
809 	    else
810 	    {
811 		allocation.x = x;
812 		allocation.y = y;
813 	    }
814 
815 	    allocation.width = requisition.width;
816 	    allocation.height = requisition.height;
817 
818 	    gtk_widget_size_allocate(child->widget, &allocation);
819 	}
820     }
821     else
822     {
823 	if (child->mapped)
824 	{
825 	    child->mapped = FALSE;
826 
827 	    if (gtk_widget_get_mapped(child->widget))
828 		gtk_widget_unmap(child->widget);
829 	}
830     }
831 }
832 
833     static void
834 gtk_form_position_children(GtkForm *form)
835 {
836     GList *tmp_list;
837 
838     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
839 	gtk_form_position_child(form, tmp_list->data, FALSE);
840 }
841 
842     void
843 gtk_form_move_resize(GtkForm *form, GtkWidget *widget,
844 		     gint x, gint y, gint w, gint h)
845 {
846 #if GTK_CHECK_VERSION(3,0,0)
847     gtk_widget_set_size_request(widget, w, h);
848 #else
849     widget->requisition.width  = w;
850     widget->requisition.height = h;
851 #endif
852 
853     gtk_form_move(form, widget, x, y);
854 }
855 
856     static void
857 gtk_form_send_configure(GtkForm *form)
858 {
859     GtkWidget *widget;
860     GdkEventConfigure event;
861     GtkAllocation allocation;
862 
863     widget = GTK_WIDGET(form);
864 
865     gtk_widget_get_allocation(widget, &allocation);
866     event.type = GDK_CONFIGURE;
867     event.window = gtk_widget_get_window(widget);
868     event.x = allocation.x;
869     event.y = allocation.y;
870     event.width = allocation.width;
871     event.height = allocation.height;
872 
873     gtk_main_do_event((GdkEvent*)&event);
874 }
875 
876     static void
877 gtk_form_child_map(GtkWidget *widget UNUSED, gpointer user_data)
878 {
879     GtkFormChild *child;
880 
881     child = (GtkFormChild *)user_data;
882 
883     child->mapped = TRUE;
884     gdk_window_show(child->window);
885 }
886 
887     static void
888 gtk_form_child_unmap(GtkWidget *widget UNUSED, gpointer user_data)
889 {
890     GtkFormChild *child;
891 
892     child = (GtkFormChild *)user_data;
893 
894     child->mapped = FALSE;
895     gdk_window_hide(child->window);
896 }
897