home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / gui_gtk_f.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-04-25  |  22.8 KB  |  939 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  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 <dalecki@cs.net.pl>
  12.  *
  13.  *    "I'm a one-man software company. If you have anything UNIX, net or
  14.  *    embedded systems related, which seems to cause some serious trouble for
  15.  *    your's in-house developers, maybe we need to talk badly with each other
  16.  *    :-) <dalecki@cs.net.pl> (My native language is polish and I speak
  17.  *    native grade german too. I'm living in G├╢ttingen.de.)
  18.  *    --mdcki"
  19.  *
  20.  * Support for GTK+ 2 was added by:
  21.  *
  22.  * (C) 2002,2003  Jason Hildebrand  <jason@peaceworks.ca>
  23.  *          Daniel Elstner  <daniel.elstner@gmx.net>
  24.  *
  25.  * This is a special purspose container widget, which manages arbitrary childs
  26.  * at arbitrary positions width arbitrary sizes.  This finally puts an end on
  27.  * our resizement problems with which we where struggling for such a long time.
  28.  */
  29.  
  30. #include "vim.h"
  31. #include <gtk/gtk.h>    /* without this it compiles, but gives errors at
  32.                runtime! */
  33. #include "gui_gtk_f.h"
  34. #include <gtk/gtksignal.h>
  35. #include <gdk/gdkx.h>
  36.  
  37. typedef struct _GtkFormChild GtkFormChild;
  38.  
  39. struct _GtkFormChild
  40. {
  41.     GtkWidget *widget;
  42.     GdkWindow *window;
  43.     gint x;        /* relative subwidget x position */
  44.     gint y;        /* relative subwidget y position */
  45.     gint mapped;
  46. };
  47.  
  48.  
  49. static void gtk_form_class_init(GtkFormClass *klass);
  50. static void gtk_form_init(GtkForm *form);
  51.  
  52. static void gtk_form_realize(GtkWidget *widget);
  53. static void gtk_form_unrealize(GtkWidget *widget);
  54. static void gtk_form_map(GtkWidget *widget);
  55. static void gtk_form_size_request(GtkWidget *widget,
  56.                   GtkRequisition *requisition);
  57. static void gtk_form_size_allocate(GtkWidget *widget,
  58.                    GtkAllocation *allocation);
  59. #ifndef HAVE_GTK2  /* this isn't needed in gtk2 */
  60. static void gtk_form_draw(GtkWidget *widget,
  61.               GdkRectangle *area);
  62. #endif
  63. static gint gtk_form_expose(GtkWidget *widget,
  64.                 GdkEventExpose *event);
  65.  
  66. static void gtk_form_remove(GtkContainer *container,
  67.                 GtkWidget *widget);
  68. static void gtk_form_forall(GtkContainer *container,
  69.                 gboolean include_internals,
  70.                 GtkCallback callback,
  71.                 gpointer callback_data);
  72.  
  73. static void gtk_form_attach_child_window(GtkForm *form,
  74.                      GtkFormChild *child);
  75. static void gtk_form_realize_child(GtkForm *form,
  76.                    GtkFormChild *child);
  77. static void gtk_form_position_child(GtkForm *form,
  78.                     GtkFormChild *child,
  79.                     gboolean force_allocate);
  80. static void gtk_form_position_children(GtkForm *form);
  81.  
  82. static GdkFilterReturn gtk_form_filter(GdkXEvent *gdk_xevent,
  83.                        GdkEvent *event,
  84.                        gpointer data);
  85. static GdkFilterReturn gtk_form_main_filter(GdkXEvent *gdk_xevent,
  86.                         GdkEvent *event,
  87.                         gpointer data);
  88.  
  89. static void gtk_form_set_static_gravity(GdkWindow *window,
  90.                     gboolean use_static);
  91.  
  92. static void gtk_form_send_configure(GtkForm *form);
  93.  
  94. static void gtk_form_child_map(GtkWidget *widget, gpointer user_data);
  95. static void gtk_form_child_unmap(GtkWidget *widget, gpointer user_data);
  96.  
  97. static GtkWidgetClass *parent_class = NULL;
  98.  
  99. /* Public interface
  100.  */
  101.  
  102.     GtkWidget *
  103. gtk_form_new(void)
  104. {
  105.     GtkForm *form;
  106.  
  107.     form = gtk_type_new(gtk_form_get_type());
  108.  
  109.     return GTK_WIDGET(form);
  110. }
  111.  
  112.     void
  113. gtk_form_put(GtkForm    *form,
  114.          GtkWidget    *child_widget,
  115.          gint    x,
  116.          gint    y)
  117. {
  118.     GtkFormChild *child;
  119.  
  120.     g_return_if_fail(GTK_IS_FORM(form));
  121.  
  122.     child = g_new(GtkFormChild, 1);
  123.  
  124.     child->widget = child_widget;
  125.     child->window = NULL;
  126.     child->x = x;
  127.     child->y = y;
  128.     child->widget->requisition.width = 0;
  129.     child->widget->requisition.height = 0;
  130.     child->mapped = FALSE;
  131.  
  132.     form->children = g_list_append(form->children, child);
  133.  
  134.     /* child->window must be created and attached to the widget _before_
  135.      * it has been realized, or else things will break with GTK2.  Note
  136.      * that gtk_widget_set_parent() realizes the widget if it's visible
  137.      * and its parent is mapped.
  138.      */
  139.     if (GTK_WIDGET_REALIZED(form))
  140.     gtk_form_attach_child_window(form, child);
  141.  
  142.     gtk_widget_set_parent(child_widget, GTK_WIDGET(form));
  143.     gtk_widget_size_request(child->widget, NULL);
  144.  
  145.     if (GTK_WIDGET_REALIZED(form) && !GTK_WIDGET_REALIZED(child_widget))
  146.     gtk_form_realize_child(form, child);
  147.  
  148.     gtk_form_position_child(form, child, TRUE);
  149. }
  150.  
  151.     void
  152. gtk_form_move(GtkForm    *form,
  153.           GtkWidget    *child_widget,
  154.           gint    x,
  155.           gint    y)
  156. {
  157.     GList *tmp_list;
  158.     GtkFormChild *child;
  159.  
  160.     g_return_if_fail(GTK_IS_FORM(form));
  161.  
  162.     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
  163.     {
  164.     child = tmp_list->data;
  165.     if (child->widget == child_widget)
  166.     {
  167.         child->x = x;
  168.         child->y = y;
  169.  
  170.         gtk_form_position_child(form, child, TRUE);
  171.         return;
  172.     }
  173.     }
  174. }
  175.  
  176.     void
  177. gtk_form_set_size(GtkForm *form, guint width, guint height)
  178. {
  179.     g_return_if_fail(GTK_IS_FORM(form));
  180.  
  181.     /* prevent unneccessary calls */
  182.     if (form->width == width && form->height == height)
  183.     return;
  184.     form->width = width;
  185.     form->height = height;
  186.  
  187.     /* signal the change */
  188. #ifdef HAVE_GTK2
  189.     gtk_widget_queue_resize(gtk_widget_get_parent(GTK_WIDGET(form)));
  190. #else
  191.     gtk_container_queue_resize(GTK_CONTAINER(GTK_WIDGET(form)->parent));
  192. #endif
  193. }
  194.  
  195.     void
  196. gtk_form_freeze(GtkForm *form)
  197. {
  198.     g_return_if_fail(GTK_IS_FORM(form));
  199.  
  200.     ++form->freeze_count;
  201. }
  202.  
  203.     void
  204. gtk_form_thaw(GtkForm *form)
  205. {
  206.     g_return_if_fail(GTK_IS_FORM(form));
  207.  
  208.     if (form->freeze_count)
  209.     {
  210.     if (!(--form->freeze_count))
  211.     {
  212.         gtk_form_position_children(form);
  213. #ifdef HAVE_GTK2
  214.         gtk_widget_queue_draw(GTK_WIDGET(form));
  215. #else
  216.         gtk_widget_draw(GTK_WIDGET(form), NULL);
  217. #endif
  218.     }
  219.     }
  220. }
  221.  
  222. /* Basic Object handling procedures
  223.  */
  224.     GtkType
  225. gtk_form_get_type(void)
  226. {
  227.     static GtkType form_type = 0;
  228.  
  229.     if (!form_type)
  230.     {
  231.     GtkTypeInfo form_info =
  232.     {
  233.         "GtkForm",
  234.         sizeof(GtkForm),
  235.         sizeof(GtkFormClass),
  236.         (GtkClassInitFunc) gtk_form_class_init,
  237.         (GtkObjectInitFunc) gtk_form_init
  238.     };
  239.  
  240.     form_type = gtk_type_unique(GTK_TYPE_CONTAINER, &form_info);
  241.     }
  242.     return form_type;
  243. }
  244.  
  245.     static void
  246. gtk_form_class_init(GtkFormClass *klass)
  247. {
  248.     GtkWidgetClass *widget_class;
  249.     GtkContainerClass *container_class;
  250.  
  251.     widget_class = (GtkWidgetClass *) klass;
  252.     container_class = (GtkContainerClass *) klass;
  253.  
  254.     parent_class = gtk_type_class(gtk_container_get_type());
  255.  
  256.     widget_class->realize = gtk_form_realize;
  257.     widget_class->unrealize = gtk_form_unrealize;
  258.     widget_class->map = gtk_form_map;
  259.     widget_class->size_request = gtk_form_size_request;
  260.     widget_class->size_allocate = gtk_form_size_allocate;
  261. #ifndef HAVE_GTK2 /* not needed for GTK2 */
  262.     widget_class->draw = gtk_form_draw;
  263. #endif
  264.     widget_class->expose_event = gtk_form_expose;
  265.  
  266.     container_class->remove = gtk_form_remove;
  267.     container_class->forall = gtk_form_forall;
  268. }
  269.  
  270.     static void
  271. gtk_form_init(GtkForm *form)
  272. {
  273.     form->children = NULL;
  274.  
  275.     form->width = 1;
  276.     form->height = 1;
  277.  
  278.     form->bin_window = NULL;
  279.  
  280.     form->configure_serial = 0;
  281.     form->visibility = GDK_VISIBILITY_PARTIAL;
  282.  
  283.     form->freeze_count = 0;
  284. }
  285.  
  286. /*
  287.  * Widget methods
  288.  */
  289.  
  290.     static void
  291. gtk_form_realize(GtkWidget *widget)
  292. {
  293.     GList *tmp_list;
  294.     GtkForm *form;
  295.     GdkWindowAttr attributes;
  296.     gint attributes_mask;
  297.  
  298.     g_return_if_fail(GTK_IS_FORM(widget));
  299.  
  300.     form = GTK_FORM(widget);
  301.     GTK_WIDGET_SET_FLAGS(form, GTK_REALIZED);
  302.  
  303.     attributes.window_type = GDK_WINDOW_CHILD;
  304.     attributes.x = widget->allocation.x;
  305.     attributes.y = widget->allocation.y;
  306.     attributes.width = widget->allocation.width;
  307.     attributes.height = widget->allocation.height;
  308.     attributes.wclass = GDK_INPUT_OUTPUT;
  309.     attributes.visual = gtk_widget_get_visual(widget);
  310.     attributes.colormap = gtk_widget_get_colormap(widget);
  311.     attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
  312.  
  313.     attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
  314.  
  315.     widget->window = gdk_window_new(gtk_widget_get_parent_window(widget),
  316.                     &attributes, attributes_mask);
  317.     gdk_window_set_user_data(widget->window, widget);
  318.  
  319.     attributes.x = 0;
  320.     attributes.y = 0;
  321.     attributes.event_mask = gtk_widget_get_events(widget);
  322.  
  323.     form->bin_window = gdk_window_new(widget->window,
  324.                       &attributes, attributes_mask);
  325.     gdk_window_set_user_data(form->bin_window, widget);
  326.  
  327.     gtk_form_set_static_gravity(form->bin_window, TRUE);
  328.  
  329.     widget->style = gtk_style_attach(widget->style, widget->window);
  330.     gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
  331.     gtk_style_set_background(widget->style, form->bin_window, GTK_STATE_NORMAL);
  332.  
  333.     gdk_window_add_filter(widget->window, gtk_form_main_filter, form);
  334.     gdk_window_add_filter(form->bin_window, gtk_form_filter, form);
  335.  
  336.     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
  337.     {
  338.     GtkFormChild *child = tmp_list->data;
  339.  
  340.     gtk_form_attach_child_window(form, child);
  341.  
  342.     if (GTK_WIDGET_VISIBLE(child->widget))
  343.         gtk_form_realize_child(form, child);
  344.     }
  345. }
  346.  
  347.  
  348. /* After reading the documentation at
  349.  * http://developer.gnome.org/doc/API/2.0/gtk/gtk-changes-2-0.html
  350.  * I think it should be possible to remove this function when compiling
  351.  * against gtk-2.0.  It doesn't seem to cause problems, though.
  352.  *
  353.  * Well, I reckon at least the gdk_window_show(form->bin_window)
  354.  * is necessary.  GtkForm is anything but a usual container widget.
  355.  */
  356.     static void
  357. gtk_form_map(GtkWidget *widget)
  358. {
  359.     GList *tmp_list;
  360.     GtkForm *form;
  361.  
  362.     g_return_if_fail(GTK_IS_FORM(widget));
  363.  
  364.     form = GTK_FORM(widget);
  365.  
  366.     GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED);
  367.  
  368.     gdk_window_show(widget->window);
  369.     gdk_window_show(form->bin_window);
  370.  
  371.     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
  372.     {
  373.     GtkFormChild *child = tmp_list->data;
  374.  
  375.     if (GTK_WIDGET_VISIBLE(child->widget)
  376.         && !GTK_WIDGET_MAPPED(child->widget))
  377.         gtk_widget_map(child->widget);
  378.     }
  379. }
  380.  
  381.     static void
  382. gtk_form_unrealize(GtkWidget *widget)
  383. {
  384.     GList *tmp_list;
  385.     GtkForm *form;
  386.  
  387.     g_return_if_fail(GTK_IS_FORM(widget));
  388.  
  389.     form = GTK_FORM(widget);
  390.  
  391.     tmp_list = form->children;
  392.  
  393.     gdk_window_set_user_data(form->bin_window, NULL);
  394.     gdk_window_destroy(form->bin_window);
  395.     form->bin_window = NULL;
  396.  
  397.     while (tmp_list)
  398.     {
  399.     GtkFormChild *child = tmp_list->data;
  400.  
  401.     if (child->window != NULL)
  402.     {
  403.         gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget),
  404.                       GTK_SIGNAL_FUNC(gtk_form_child_map),
  405.                       child);
  406.         gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget),
  407.                       GTK_SIGNAL_FUNC(gtk_form_child_unmap),
  408.                       child);
  409.  
  410.         gdk_window_set_user_data(child->window, NULL);
  411.         gdk_window_destroy(child->window);
  412.  
  413.         child->window = NULL;
  414.     }
  415.  
  416.     tmp_list = tmp_list->next;
  417.     }
  418.  
  419.     if (GTK_WIDGET_CLASS (parent_class)->unrealize)
  420.      (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
  421. }
  422.  
  423. #ifndef HAVE_GTK2
  424.     static void
  425. gtk_form_draw(GtkWidget *widget, GdkRectangle *area)
  426. {
  427.     GtkForm        *form;
  428.     GList        *children;
  429.     GtkFormChild    *child;
  430.     GdkRectangle    child_area;
  431.  
  432.     g_return_if_fail(GTK_IS_FORM(widget));
  433.  
  434.     if (GTK_WIDGET_DRAWABLE(widget))
  435.     {
  436.     form = GTK_FORM(widget);
  437.  
  438.     children = form->children;
  439.  
  440.     while (children)
  441.     {
  442.         child = children->data;
  443.  
  444.         if (GTK_WIDGET_DRAWABLE(child->widget)
  445.             && gtk_widget_intersect(child->widget, area, &child_area))
  446.         gtk_widget_draw(child->widget, &child_area);
  447.  
  448.         children = children->next;
  449.     }
  450.     }
  451. }
  452. #endif /* !HAVE_GTK2 */
  453.  
  454.     static void
  455. gtk_form_size_request(GtkWidget *widget, GtkRequisition *requisition)
  456. {
  457.     GList *tmp_list;
  458.     GtkForm *form;
  459.  
  460.     g_return_if_fail(GTK_IS_FORM(widget));
  461.  
  462.     form = GTK_FORM(widget);
  463.  
  464.     requisition->width = form->width;
  465.     requisition->height = form->height;
  466.  
  467.     tmp_list = form->children;
  468.  
  469.     while (tmp_list)
  470.     {
  471.     GtkFormChild *child = tmp_list->data;
  472.     gtk_widget_size_request(child->widget, NULL);
  473.     tmp_list = tmp_list->next;
  474.     }
  475. }
  476.  
  477.     static void
  478. gtk_form_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
  479. {
  480.     GList *tmp_list;
  481.     GtkForm *form;
  482.     gboolean need_reposition;
  483.  
  484.     g_return_if_fail(GTK_IS_FORM(widget));
  485.  
  486.     if (widget->allocation.x == allocation->x
  487.         && widget->allocation.y == allocation->y
  488.         && widget->allocation.width == allocation->width
  489.         && widget->allocation.height == allocation->height)
  490.     return;
  491.  
  492.     need_reposition = widget->allocation.width != allocation->width
  493.            || widget->allocation.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.         gtk_form_position_child(form, child, TRUE);
  504.  
  505.         tmp_list = tmp_list->next;
  506.     }
  507.     }
  508.  
  509.     if (GTK_WIDGET_REALIZED(widget))
  510.     {
  511.     gdk_window_move_resize(widget->window,
  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.     widget->allocation = *allocation;
  519.     if (need_reposition)
  520.     gtk_form_send_configure(form);
  521. }
  522.  
  523.     static gint
  524. gtk_form_expose(GtkWidget *widget, GdkEventExpose *event)
  525. {
  526.     GList   *tmp_list;
  527.     GtkForm *form;
  528.  
  529.     g_return_val_if_fail(GTK_IS_FORM(widget), FALSE);
  530.  
  531.     form = GTK_FORM(widget);
  532.  
  533.     if (event->window == form->bin_window)
  534.     return FALSE;
  535.  
  536.     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
  537.     {
  538. #ifdef HAVE_GTK2
  539.     GtkFormChild    *formchild = tmp_list->data;
  540.     GtkWidget    *child       = formchild->widget;
  541.     /*
  542.      * The following chunk of code is taken from gtkcontainer.c.  The
  543.      * gtk1.x code synthesized expose events directly on the child widgets,
  544.      * which can't be done in gtk2
  545.      */
  546.     if (GTK_WIDGET_DRAWABLE(child) && GTK_WIDGET_NO_WINDOW(child)
  547.         && child->window == event->window)
  548.     {
  549.         GdkEventExpose child_event;
  550.         child_event = *event;
  551.  
  552.         child_event.region = gtk_widget_region_intersect(child, event->region);
  553.         if (!gdk_region_empty(child_event.region))
  554.         {
  555.         gdk_region_get_clipbox(child_event.region, &child_event.area);
  556.         gtk_widget_send_expose(child, (GdkEvent *)&child_event);
  557.         }
  558.     }
  559. #else /* !HAVE_GTK2 */
  560.     GtkFormChild *child = tmp_list->data;
  561.  
  562.     if (event->window == child->window)
  563.         return gtk_widget_event(child->widget, (GdkEvent *) event);
  564. #endif /* !HAVE_GTK2 */
  565.     }
  566.  
  567.     return FALSE;
  568. }
  569.  
  570. /* Container method
  571.  */
  572.     static void
  573. gtk_form_remove(GtkContainer *container, GtkWidget *widget)
  574. {
  575.     GList *tmp_list;
  576.     GtkForm *form;
  577.     GtkFormChild *child = NULL;        /* init for gcc */
  578.  
  579.     g_return_if_fail(GTK_IS_FORM(container));
  580.  
  581.     form = GTK_FORM(container);
  582.  
  583.     tmp_list = form->children;
  584.     while (tmp_list)
  585.     {
  586.     child = tmp_list->data;
  587.     if (child->widget == widget)
  588.         break;
  589.     tmp_list = tmp_list->next;
  590.     }
  591.  
  592.     if (tmp_list)
  593.     {
  594.     if (child->window)
  595.     {
  596.         gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget),
  597.                       GTK_SIGNAL_FUNC(>k_form_child_map), child);
  598.         gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget),
  599.                       GTK_SIGNAL_FUNC(>k_form_child_unmap), child);
  600.  
  601.         /* FIXME: This will cause problems for reparenting NO_WINDOW
  602.          * widgets out of a GtkForm
  603.          */
  604.         gdk_window_set_user_data(child->window, NULL);
  605.         gdk_window_destroy(child->window);
  606.     }
  607.     gtk_widget_unparent(widget);
  608.  
  609.     form->children = g_list_remove_link(form->children, tmp_list);
  610.     g_list_free_1(tmp_list);
  611.     g_free(child);
  612.     }
  613. }
  614.  
  615. /*ARGSUSED1*/
  616.     static void
  617. gtk_form_forall(GtkContainer    *container,
  618.         gboolean    include_internals,
  619.         GtkCallback    callback,
  620.         gpointer    callback_data)
  621. {
  622.     GtkForm *form;
  623.     GtkFormChild *child;
  624.     GList *tmp_list;
  625.  
  626.     g_return_if_fail(GTK_IS_FORM(container));
  627.     g_return_if_fail(callback != NULL);
  628.  
  629.     form = GTK_FORM(container);
  630.  
  631.     tmp_list = form->children;
  632.     while (tmp_list)
  633.     {
  634.     child = tmp_list->data;
  635.     tmp_list = tmp_list->next;
  636.  
  637.     (*callback) (child->widget, callback_data);
  638.     }
  639. }
  640.  
  641. /* Operations on children
  642.  */
  643.  
  644.     static void
  645. gtk_form_attach_child_window(GtkForm *form, GtkFormChild *child)
  646. {
  647.     if (child->window != NULL)
  648.     return; /* been there, done that */
  649.  
  650.     if (GTK_WIDGET_NO_WINDOW(child->widget))
  651.     {
  652.     GtkWidget    *widget;
  653.     GdkWindowAttr    attributes;
  654.     gint        attributes_mask;
  655.  
  656.     widget = GTK_WIDGET(form);
  657.  
  658.     attributes.window_type = GDK_WINDOW_CHILD;
  659.     attributes.x = child->x;
  660.     attributes.y = child->y;
  661.     attributes.width = child->widget->requisition.width;
  662.     attributes.height = child->widget->requisition.height;
  663.     attributes.wclass = GDK_INPUT_OUTPUT;
  664.     attributes.visual = gtk_widget_get_visual(widget);
  665.     attributes.colormap = gtk_widget_get_colormap(widget);
  666.     attributes.event_mask = GDK_EXPOSURE_MASK;
  667.  
  668.     attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
  669.     child->window = gdk_window_new(form->bin_window,
  670.                        &attributes, attributes_mask);
  671.     gdk_window_set_user_data(child->window, widget);
  672.  
  673.     gtk_style_set_background(widget->style,
  674.                  child->window,
  675.                  GTK_STATE_NORMAL);
  676.  
  677.     gtk_widget_set_parent_window(child->widget, child->window);
  678.     gtk_form_set_static_gravity(child->window, TRUE);
  679.     /*
  680.      * Install signal handlers to map/unmap child->window
  681.      * alongside with the actual widget.
  682.      */
  683.     gtk_signal_connect(GTK_OBJECT(child->widget), "map",
  684.                GTK_SIGNAL_FUNC(>k_form_child_map), child);
  685.     gtk_signal_connect(GTK_OBJECT(child->widget), "unmap",
  686.                GTK_SIGNAL_FUNC(>k_form_child_unmap), child);
  687.     }
  688.     else if (!GTK_WIDGET_REALIZED(child->widget))
  689.     {
  690.     gtk_widget_set_parent_window(child->widget, form->bin_window);
  691.     }
  692. }
  693.  
  694.     static void
  695. gtk_form_realize_child(GtkForm *form, GtkFormChild *child)
  696. {
  697.     gtk_form_attach_child_window(form, child);
  698.     gtk_widget_realize(child->widget);
  699.  
  700.     if (child->window == NULL) /* might be already set, see above */
  701.     gtk_form_set_static_gravity(child->widget->window, TRUE);
  702. }
  703.  
  704.     static void
  705. gtk_form_position_child(GtkForm *form, GtkFormChild *child,
  706.             gboolean force_allocate)
  707. {
  708.     gint x;
  709.     gint y;
  710.  
  711.     x = child->x;
  712.     y = child->y;
  713.  
  714.     if ((x >= G_MINSHORT) && (x <= G_MAXSHORT) &&
  715.     (y >= G_MINSHORT) && (y <= G_MAXSHORT))
  716.     {
  717.     if (!child->mapped)
  718.     {
  719.         if (GTK_WIDGET_MAPPED(form) && GTK_WIDGET_VISIBLE(child->widget))
  720.         {
  721.         if (!GTK_WIDGET_MAPPED(child->widget))
  722.             gtk_widget_map(child->widget);
  723.  
  724.         child->mapped = TRUE;
  725.         force_allocate = TRUE;
  726.         }
  727.     }
  728.  
  729.     if (force_allocate)
  730.     {
  731.         GtkAllocation allocation;
  732.  
  733.         if (GTK_WIDGET_NO_WINDOW(child->widget))
  734.         {
  735.         if (child->window)
  736.         {
  737.             gdk_window_move_resize(child->window,
  738.                 x, y,
  739.                 child->widget->requisition.width,
  740.                 child->widget->requisition.height);
  741.         }
  742.  
  743.         allocation.x = 0;
  744.         allocation.y = 0;
  745.         }
  746.         else
  747.         {
  748.         allocation.x = x;
  749.         allocation.y = y;
  750.         }
  751.  
  752.         allocation.width = child->widget->requisition.width;
  753.         allocation.height = child->widget->requisition.height;
  754.  
  755.         gtk_widget_size_allocate(child->widget, &allocation);
  756.     }
  757.     }
  758.     else
  759.     {
  760.     if (child->mapped)
  761.     {
  762.         child->mapped = FALSE;
  763.  
  764.         if (GTK_WIDGET_MAPPED(child->widget))
  765.         gtk_widget_unmap(child->widget);
  766.     }
  767.     }
  768. }
  769.  
  770.     static void
  771. gtk_form_position_children(GtkForm *form)
  772. {
  773.     GList *tmp_list;
  774.  
  775.     for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
  776.     gtk_form_position_child(form, tmp_list->data, FALSE);
  777. }
  778.  
  779. /* Callbacks */
  780.  
  781. /* The main event filter. Actually, we probably don't really need
  782.  * to install this as a filter at all, since we are calling it
  783.  * directly above in the expose-handling hack.
  784.  *
  785.  * This routine identifies expose events that are generated when
  786.  * we've temporarily moved the bin_window_origin, and translates
  787.  * them or discards them, depending on whether we are obscured
  788.  * or not.
  789.  */
  790. /*ARGSUSED1*/
  791.     static GdkFilterReturn
  792. gtk_form_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
  793. {
  794.     XEvent *xevent;
  795.     GtkForm *form;
  796.  
  797.     xevent = (XEvent *) gdk_xevent;
  798.     form = GTK_FORM(data);
  799.  
  800.     switch (xevent->type)
  801.     {
  802.     case Expose:
  803.     if (xevent->xexpose.serial == form->configure_serial)
  804.     {
  805.         if (form->visibility == GDK_VISIBILITY_UNOBSCURED)
  806.         return GDK_FILTER_REMOVE;
  807.         else
  808.         break;
  809.     }
  810.     break;
  811.  
  812.     case ConfigureNotify:
  813.     if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0))
  814.         form->configure_serial = xevent->xconfigure.serial;
  815.     break;
  816.     }
  817.  
  818.     return GDK_FILTER_CONTINUE;
  819. }
  820.  
  821. /* Although GDK does have a GDK_VISIBILITY_NOTIFY event,
  822.  * there is no corresponding event in GTK, so we have
  823.  * to get the events from a filter
  824.  */
  825. /*ARGSUSED1*/
  826.     static GdkFilterReturn
  827. gtk_form_main_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
  828. {
  829.     XEvent *xevent;
  830.     GtkForm *form;
  831.  
  832.     xevent = (XEvent *) gdk_xevent;
  833.     form = GTK_FORM(data);
  834.  
  835.     if (xevent->type == VisibilityNotify)
  836.     {
  837.     switch (xevent->xvisibility.state)
  838.     {
  839.     case VisibilityFullyObscured:
  840.         form->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
  841.         break;
  842.  
  843.     case VisibilityPartiallyObscured:
  844.         form->visibility = GDK_VISIBILITY_PARTIAL;
  845.         break;
  846.  
  847.     case VisibilityUnobscured:
  848.         form->visibility = GDK_VISIBILITY_UNOBSCURED;
  849.         break;
  850.     }
  851.  
  852.     return GDK_FILTER_REMOVE;
  853.     }
  854.     return GDK_FILTER_CONTINUE;
  855. }
  856.  
  857. /* Routines to set the window gravity, and check whether it is
  858.  * functional. Extra capabilities need to be added to GDK, so
  859.  * we don't have to use Xlib here.
  860.  */
  861.     static void
  862. gtk_form_set_static_gravity(GdkWindow *window, gboolean use_static)
  863. {
  864. #ifdef HAVE_GTK2
  865.     gboolean static_gravity_supported;
  866.  
  867.     static_gravity_supported = gdk_window_set_static_gravities(window,
  868.                                    use_static);
  869.     g_return_if_fail(static_gravity_supported);
  870. #else
  871.     XSetWindowAttributes xattributes;
  872.  
  873.     xattributes.win_gravity = (use_static) ? StaticGravity : NorthWestGravity;
  874.     xattributes.bit_gravity = (use_static) ? StaticGravity : NorthWestGravity;
  875.  
  876.     XChangeWindowAttributes(GDK_WINDOW_XDISPLAY(window),
  877.                 GDK_WINDOW_XWINDOW(window),
  878.                 CWBitGravity | CWWinGravity,
  879.                 &xattributes);
  880. #endif
  881. }
  882.  
  883.     void
  884. gtk_form_move_resize(GtkForm *form, GtkWidget *widget,
  885.              gint x, gint y, gint w, gint h)
  886. {
  887.     widget->requisition.width  = w;
  888.     widget->requisition.height = h;
  889.  
  890.     gtk_form_move(form, widget, x, y);
  891. }
  892.  
  893.     static void
  894. gtk_form_send_configure(GtkForm *form)
  895. {
  896.     GtkWidget *widget;
  897.     GdkEventConfigure event;
  898.  
  899.     widget = GTK_WIDGET(form);
  900.  
  901.     event.type = GDK_CONFIGURE;
  902.     event.window = widget->window;
  903.     event.x = widget->allocation.x;
  904.     event.y = widget->allocation.y;
  905.     event.width = widget->allocation.width;
  906.     event.height = widget->allocation.height;
  907.  
  908. #ifdef HAVE_GTK2
  909.     gtk_main_do_event((GdkEvent*)&event);
  910. #else
  911.     gtk_widget_event(widget, (GdkEvent*)&event);
  912. #endif
  913. }
  914.  
  915. /*ARGSUSED0*/
  916.     static void
  917. gtk_form_child_map(GtkWidget *widget, gpointer user_data)
  918. {
  919.     GtkFormChild *child;
  920.  
  921.     child = (GtkFormChild *)user_data;
  922.  
  923.     child->mapped = TRUE;
  924.     gdk_window_show(child->window);
  925. }
  926.  
  927. /*ARGSUSED0*/
  928.     static void
  929. gtk_form_child_unmap(GtkWidget *widget, gpointer user_data)
  930. {
  931.     GtkFormChild *child;
  932.  
  933.     child = (GtkFormChild *)user_data;
  934.  
  935.     child->mapped = FALSE;
  936.     gdk_window_hide(child->window);
  937. }
  938.  
  939.