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