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