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(>k_form_child_map), child); 632 g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget), 633 FUNC2GENERIC(>k_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(>k_form_child_map), child); 743 g_signal_connect(G_OBJECT(child->widget), "unmap", 744 G_CALLBACK(>k_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