diff src/gui_gtk_f.c @ 7:3fc0f57ecb91 v7.0001

updated for version 7.0001
author vimboss
date Sun, 13 Jun 2004 20:20:40 +0000
parents
children 99064882c85b
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/gui_gtk_f.c
@@ -0,0 +1,942 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved		by Bram Moolenaar
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * (C) 1998,1999 by Marcin Dalecki <dalecki@cs.net.pl>
+ *
+ *	"I'm a one-man software company. If you have anything UNIX, net or
+ *	embedded systems related, which seems to cause some serious trouble for
+ *	your's in-house developers, maybe we need to talk badly with each other
+ *	:-) <dalecki@cs.net.pl> (My native language is polish and I speak
+ *	native grade german too. I'm living in Göttingen.de.)
+ *	--mdcki"
+ *
+ * Support for GTK+ 2 was added by:
+ *
+ * (C) 2002,2003  Jason Hildebrand  <jason@peaceworks.ca>
+ *		  Daniel Elstner  <daniel.elstner@gmx.net>
+ *
+ * This is a special purspose container widget, which manages arbitrary childs
+ * at arbitrary positions width arbitrary sizes.  This finally puts an end on
+ * our resizement problems with which we where struggling for such a long time.
+ */
+
+#include "vim.h"
+#include <gtk/gtk.h>	/* without this it compiles, but gives errors at
+			   runtime! */
+#include "gui_gtk_f.h"
+#include <gtk/gtksignal.h>
+#ifdef WIN3264
+# include <gdk/gdkwin32.h>
+#else
+# include <gdk/gdkx.h>
+#endif
+
+typedef struct _GtkFormChild GtkFormChild;
+
+struct _GtkFormChild
+{
+    GtkWidget *widget;
+    GdkWindow *window;
+    gint x;		/* relative subwidget x position */
+    gint y;		/* relative subwidget y position */
+    gint mapped;
+};
+
+
+static void gtk_form_class_init(GtkFormClass *klass);
+static void gtk_form_init(GtkForm *form);
+
+static void gtk_form_realize(GtkWidget *widget);
+static void gtk_form_unrealize(GtkWidget *widget);
+static void gtk_form_map(GtkWidget *widget);
+static void gtk_form_size_request(GtkWidget *widget,
+				  GtkRequisition *requisition);
+static void gtk_form_size_allocate(GtkWidget *widget,
+				   GtkAllocation *allocation);
+#ifndef HAVE_GTK2  /* this isn't needed in gtk2 */
+static void gtk_form_draw(GtkWidget *widget,
+			  GdkRectangle *area);
+#endif
+static gint gtk_form_expose(GtkWidget *widget,
+			    GdkEventExpose *event);
+
+static void gtk_form_remove(GtkContainer *container,
+			    GtkWidget *widget);
+static void gtk_form_forall(GtkContainer *container,
+			    gboolean include_internals,
+			    GtkCallback callback,
+			    gpointer callback_data);
+
+static void gtk_form_attach_child_window(GtkForm *form,
+					 GtkFormChild *child);
+static void gtk_form_realize_child(GtkForm *form,
+				   GtkFormChild *child);
+static void gtk_form_position_child(GtkForm *form,
+				    GtkFormChild *child,
+				    gboolean force_allocate);
+static void gtk_form_position_children(GtkForm *form);
+
+static GdkFilterReturn gtk_form_filter(GdkXEvent *gdk_xevent,
+				       GdkEvent *event,
+				       gpointer data);
+static GdkFilterReturn gtk_form_main_filter(GdkXEvent *gdk_xevent,
+					    GdkEvent *event,
+					    gpointer data);
+
+static void gtk_form_set_static_gravity(GdkWindow *window,
+					gboolean use_static);
+
+static void gtk_form_send_configure(GtkForm *form);
+
+static void gtk_form_child_map(GtkWidget *widget, gpointer user_data);
+static void gtk_form_child_unmap(GtkWidget *widget, gpointer user_data);
+
+static GtkWidgetClass *parent_class = NULL;
+
+/* Public interface
+ */
+
+    GtkWidget *
+gtk_form_new(void)
+{
+    GtkForm *form;
+
+    form = gtk_type_new(gtk_form_get_type());
+
+    return GTK_WIDGET(form);
+}
+
+    void
+gtk_form_put(GtkForm	*form,
+	     GtkWidget	*child_widget,
+	     gint	x,
+	     gint	y)
+{
+    GtkFormChild *child;
+
+    g_return_if_fail(GTK_IS_FORM(form));
+
+    child = g_new(GtkFormChild, 1);
+
+    child->widget = child_widget;
+    child->window = NULL;
+    child->x = x;
+    child->y = y;
+    child->widget->requisition.width = 0;
+    child->widget->requisition.height = 0;
+    child->mapped = FALSE;
+
+    form->children = g_list_append(form->children, child);
+
+    /* child->window must be created and attached to the widget _before_
+     * it has been realized, or else things will break with GTK2.  Note
+     * that gtk_widget_set_parent() realizes the widget if it's visible
+     * and its parent is mapped.
+     */
+    if (GTK_WIDGET_REALIZED(form))
+	gtk_form_attach_child_window(form, child);
+
+    gtk_widget_set_parent(child_widget, GTK_WIDGET(form));
+    gtk_widget_size_request(child->widget, NULL);
+
+    if (GTK_WIDGET_REALIZED(form) && !GTK_WIDGET_REALIZED(child_widget))
+	gtk_form_realize_child(form, child);
+
+    gtk_form_position_child(form, child, TRUE);
+}
+
+    void
+gtk_form_move(GtkForm	*form,
+	      GtkWidget	*child_widget,
+	      gint	x,
+	      gint	y)
+{
+    GList *tmp_list;
+    GtkFormChild *child;
+
+    g_return_if_fail(GTK_IS_FORM(form));
+
+    for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+    {
+	child = tmp_list->data;
+	if (child->widget == child_widget)
+	{
+	    child->x = x;
+	    child->y = y;
+
+	    gtk_form_position_child(form, child, TRUE);
+	    return;
+	}
+    }
+}
+
+    void
+gtk_form_set_size(GtkForm *form, guint width, guint height)
+{
+    g_return_if_fail(GTK_IS_FORM(form));
+
+    /* prevent unneccessary calls */
+    if (form->width == width && form->height == height)
+	return;
+    form->width = width;
+    form->height = height;
+
+    /* signal the change */
+#ifdef HAVE_GTK2
+    gtk_widget_queue_resize(gtk_widget_get_parent(GTK_WIDGET(form)));
+#else
+    gtk_container_queue_resize(GTK_CONTAINER(GTK_WIDGET(form)->parent));
+#endif
+}
+
+    void
+gtk_form_freeze(GtkForm *form)
+{
+    g_return_if_fail(GTK_IS_FORM(form));
+
+    ++form->freeze_count;
+}
+
+    void
+gtk_form_thaw(GtkForm *form)
+{
+    g_return_if_fail(GTK_IS_FORM(form));
+
+    if (form->freeze_count)
+    {
+	if (!(--form->freeze_count))
+	{
+	    gtk_form_position_children(form);
+#ifdef HAVE_GTK2
+	    gtk_widget_queue_draw(GTK_WIDGET(form));
+#else
+	    gtk_widget_draw(GTK_WIDGET(form), NULL);
+#endif
+	}
+    }
+}
+
+/* Basic Object handling procedures
+ */
+    GtkType
+gtk_form_get_type(void)
+{
+    static GtkType form_type = 0;
+
+    if (!form_type)
+    {
+	GtkTypeInfo form_info =
+	{
+	    "GtkForm",
+	    sizeof(GtkForm),
+	    sizeof(GtkFormClass),
+	    (GtkClassInitFunc) gtk_form_class_init,
+	    (GtkObjectInitFunc) gtk_form_init
+	};
+
+	form_type = gtk_type_unique(GTK_TYPE_CONTAINER, &form_info);
+    }
+    return form_type;
+}
+
+    static void
+gtk_form_class_init(GtkFormClass *klass)
+{
+    GtkWidgetClass *widget_class;
+    GtkContainerClass *container_class;
+
+    widget_class = (GtkWidgetClass *) klass;
+    container_class = (GtkContainerClass *) klass;
+
+    parent_class = gtk_type_class(gtk_container_get_type());
+
+    widget_class->realize = gtk_form_realize;
+    widget_class->unrealize = gtk_form_unrealize;
+    widget_class->map = gtk_form_map;
+    widget_class->size_request = gtk_form_size_request;
+    widget_class->size_allocate = gtk_form_size_allocate;
+#ifndef HAVE_GTK2 /* not needed for GTK2 */
+    widget_class->draw = gtk_form_draw;
+#endif
+    widget_class->expose_event = gtk_form_expose;
+
+    container_class->remove = gtk_form_remove;
+    container_class->forall = gtk_form_forall;
+}
+
+    static void
+gtk_form_init(GtkForm *form)
+{
+    form->children = NULL;
+
+    form->width = 1;
+    form->height = 1;
+
+    form->bin_window = NULL;
+
+    form->configure_serial = 0;
+    form->visibility = GDK_VISIBILITY_PARTIAL;
+
+    form->freeze_count = 0;
+}
+
+/*
+ * Widget methods
+ */
+
+    static void
+gtk_form_realize(GtkWidget *widget)
+{
+    GList *tmp_list;
+    GtkForm *form;
+    GdkWindowAttr attributes;
+    gint attributes_mask;
+
+    g_return_if_fail(GTK_IS_FORM(widget));
+
+    form = GTK_FORM(widget);
+    GTK_WIDGET_SET_FLAGS(form, GTK_REALIZED);
+
+    attributes.window_type = GDK_WINDOW_CHILD;
+    attributes.x = widget->allocation.x;
+    attributes.y = widget->allocation.y;
+    attributes.width = widget->allocation.width;
+    attributes.height = widget->allocation.height;
+    attributes.wclass = GDK_INPUT_OUTPUT;
+    attributes.visual = gtk_widget_get_visual(widget);
+    attributes.colormap = gtk_widget_get_colormap(widget);
+    attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
+
+    attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+    widget->window = gdk_window_new(gtk_widget_get_parent_window(widget),
+				    &attributes, attributes_mask);
+    gdk_window_set_user_data(widget->window, widget);
+
+    attributes.x = 0;
+    attributes.y = 0;
+    attributes.event_mask = gtk_widget_get_events(widget);
+
+    form->bin_window = gdk_window_new(widget->window,
+				      &attributes, attributes_mask);
+    gdk_window_set_user_data(form->bin_window, widget);
+
+    gtk_form_set_static_gravity(form->bin_window, TRUE);
+
+    widget->style = gtk_style_attach(widget->style, widget->window);
+    gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
+    gtk_style_set_background(widget->style, form->bin_window, GTK_STATE_NORMAL);
+
+    gdk_window_add_filter(widget->window, gtk_form_main_filter, form);
+    gdk_window_add_filter(form->bin_window, gtk_form_filter, form);
+
+    for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+    {
+	GtkFormChild *child = tmp_list->data;
+
+	gtk_form_attach_child_window(form, child);
+
+	if (GTK_WIDGET_VISIBLE(child->widget))
+	    gtk_form_realize_child(form, child);
+    }
+}
+
+
+/* After reading the documentation at
+ * http://developer.gnome.org/doc/API/2.0/gtk/gtk-changes-2-0.html
+ * I think it should be possible to remove this function when compiling
+ * against gtk-2.0.  It doesn't seem to cause problems, though.
+ *
+ * Well, I reckon at least the gdk_window_show(form->bin_window)
+ * is necessary.  GtkForm is anything but a usual container widget.
+ */
+    static void
+gtk_form_map(GtkWidget *widget)
+{
+    GList *tmp_list;
+    GtkForm *form;
+
+    g_return_if_fail(GTK_IS_FORM(widget));
+
+    form = GTK_FORM(widget);
+
+    GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED);
+
+    gdk_window_show(widget->window);
+    gdk_window_show(form->bin_window);
+
+    for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+    {
+	GtkFormChild *child = tmp_list->data;
+
+	if (GTK_WIDGET_VISIBLE(child->widget)
+		&& !GTK_WIDGET_MAPPED(child->widget))
+	    gtk_widget_map(child->widget);
+    }
+}
+
+    static void
+gtk_form_unrealize(GtkWidget *widget)
+{
+    GList *tmp_list;
+    GtkForm *form;
+
+    g_return_if_fail(GTK_IS_FORM(widget));
+
+    form = GTK_FORM(widget);
+
+    tmp_list = form->children;
+
+    gdk_window_set_user_data(form->bin_window, NULL);
+    gdk_window_destroy(form->bin_window);
+    form->bin_window = NULL;
+
+    while (tmp_list)
+    {
+	GtkFormChild *child = tmp_list->data;
+
+	if (child->window != NULL)
+	{
+	    gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget),
+					  GTK_SIGNAL_FUNC(gtk_form_child_map),
+					  child);
+	    gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget),
+					  GTK_SIGNAL_FUNC(gtk_form_child_unmap),
+					  child);
+
+	    gdk_window_set_user_data(child->window, NULL);
+	    gdk_window_destroy(child->window);
+
+	    child->window = NULL;
+	}
+
+	tmp_list = tmp_list->next;
+    }
+
+    if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+	 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+#ifndef HAVE_GTK2
+    static void
+gtk_form_draw(GtkWidget *widget, GdkRectangle *area)
+{
+    GtkForm		*form;
+    GList		*children;
+    GtkFormChild	*child;
+    GdkRectangle	child_area;
+
+    g_return_if_fail(GTK_IS_FORM(widget));
+
+    if (GTK_WIDGET_DRAWABLE(widget))
+    {
+	form = GTK_FORM(widget);
+
+	children = form->children;
+
+	while (children)
+	{
+	    child = children->data;
+
+	    if (GTK_WIDGET_DRAWABLE(child->widget)
+		    && gtk_widget_intersect(child->widget, area, &child_area))
+		gtk_widget_draw(child->widget, &child_area);
+
+	    children = children->next;
+	}
+    }
+}
+#endif /* !HAVE_GTK2 */
+
+    static void
+gtk_form_size_request(GtkWidget *widget, GtkRequisition *requisition)
+{
+    GList *tmp_list;
+    GtkForm *form;
+
+    g_return_if_fail(GTK_IS_FORM(widget));
+
+    form = GTK_FORM(widget);
+
+    requisition->width = form->width;
+    requisition->height = form->height;
+
+    tmp_list = form->children;
+
+    while (tmp_list)
+    {
+	GtkFormChild *child = tmp_list->data;
+	gtk_widget_size_request(child->widget, NULL);
+	tmp_list = tmp_list->next;
+    }
+}
+
+    static void
+gtk_form_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
+{
+    GList *tmp_list;
+    GtkForm *form;
+    gboolean need_reposition;
+
+    g_return_if_fail(GTK_IS_FORM(widget));
+
+    if (widget->allocation.x == allocation->x
+	    && widget->allocation.y == allocation->y
+	    && widget->allocation.width == allocation->width
+	    && widget->allocation.height == allocation->height)
+	return;
+
+    need_reposition = widget->allocation.width != allocation->width
+		   || widget->allocation.height != allocation->height;
+    form = GTK_FORM(widget);
+
+    if (need_reposition)
+    {
+	tmp_list = form->children;
+
+	while (tmp_list)
+	{
+	    GtkFormChild *child = tmp_list->data;
+	    gtk_form_position_child(form, child, TRUE);
+
+	    tmp_list = tmp_list->next;
+	}
+    }
+
+    if (GTK_WIDGET_REALIZED(widget))
+    {
+	gdk_window_move_resize(widget->window,
+			       allocation->x, allocation->y,
+			       allocation->width, allocation->height);
+	gdk_window_move_resize(GTK_FORM(widget)->bin_window,
+			       0, 0,
+			       allocation->width, allocation->height);
+    }
+    widget->allocation = *allocation;
+    if (need_reposition)
+	gtk_form_send_configure(form);
+}
+
+    static gint
+gtk_form_expose(GtkWidget *widget, GdkEventExpose *event)
+{
+    GList   *tmp_list;
+    GtkForm *form;
+
+    g_return_val_if_fail(GTK_IS_FORM(widget), FALSE);
+
+    form = GTK_FORM(widget);
+
+    if (event->window == form->bin_window)
+	return FALSE;
+
+    for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+    {
+#ifdef HAVE_GTK2
+	GtkFormChild	*formchild = tmp_list->data;
+	GtkWidget	*child	   = formchild->widget;
+	/*
+	 * The following chunk of code is taken from gtkcontainer.c.  The
+	 * gtk1.x code synthesized expose events directly on the child widgets,
+	 * which can't be done in gtk2
+	 */
+	if (GTK_WIDGET_DRAWABLE(child) && GTK_WIDGET_NO_WINDOW(child)
+		&& child->window == event->window)
+	{
+	    GdkEventExpose child_event;
+	    child_event = *event;
+
+	    child_event.region = gtk_widget_region_intersect(child, event->region);
+	    if (!gdk_region_empty(child_event.region))
+	    {
+		gdk_region_get_clipbox(child_event.region, &child_event.area);
+		gtk_widget_send_expose(child, (GdkEvent *)&child_event);
+	    }
+	}
+#else /* !HAVE_GTK2 */
+	GtkFormChild *child = tmp_list->data;
+
+	if (event->window == child->window)
+	    return gtk_widget_event(child->widget, (GdkEvent *) event);
+#endif /* !HAVE_GTK2 */
+    }
+
+    return FALSE;
+}
+
+/* Container method
+ */
+    static void
+gtk_form_remove(GtkContainer *container, GtkWidget *widget)
+{
+    GList *tmp_list;
+    GtkForm *form;
+    GtkFormChild *child = NULL;	    /* init for gcc */
+
+    g_return_if_fail(GTK_IS_FORM(container));
+
+    form = GTK_FORM(container);
+
+    tmp_list = form->children;
+    while (tmp_list)
+    {
+	child = tmp_list->data;
+	if (child->widget == widget)
+	    break;
+	tmp_list = tmp_list->next;
+    }
+
+    if (tmp_list)
+    {
+	if (child->window)
+	{
+	    gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget),
+					  GTK_SIGNAL_FUNC(&gtk_form_child_map), child);
+	    gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget),
+					  GTK_SIGNAL_FUNC(&gtk_form_child_unmap), child);
+
+	    /* FIXME: This will cause problems for reparenting NO_WINDOW
+	     * widgets out of a GtkForm
+	     */
+	    gdk_window_set_user_data(child->window, NULL);
+	    gdk_window_destroy(child->window);
+	}
+	gtk_widget_unparent(widget);
+
+	form->children = g_list_remove_link(form->children, tmp_list);
+	g_list_free_1(tmp_list);
+	g_free(child);
+    }
+}
+
+/*ARGSUSED1*/
+    static void
+gtk_form_forall(GtkContainer	*container,
+		gboolean	include_internals,
+		GtkCallback	callback,
+		gpointer	callback_data)
+{
+    GtkForm *form;
+    GtkFormChild *child;
+    GList *tmp_list;
+
+    g_return_if_fail(GTK_IS_FORM(container));
+    g_return_if_fail(callback != NULL);
+
+    form = GTK_FORM(container);
+
+    tmp_list = form->children;
+    while (tmp_list)
+    {
+	child = tmp_list->data;
+	tmp_list = tmp_list->next;
+
+	(*callback) (child->widget, callback_data);
+    }
+}
+
+/* Operations on children
+ */
+
+    static void
+gtk_form_attach_child_window(GtkForm *form, GtkFormChild *child)
+{
+    if (child->window != NULL)
+	return; /* been there, done that */
+
+    if (GTK_WIDGET_NO_WINDOW(child->widget))
+    {
+	GtkWidget	*widget;
+	GdkWindowAttr	attributes;
+	gint		attributes_mask;
+
+	widget = GTK_WIDGET(form);
+
+	attributes.window_type = GDK_WINDOW_CHILD;
+	attributes.x = child->x;
+	attributes.y = child->y;
+	attributes.width = child->widget->requisition.width;
+	attributes.height = child->widget->requisition.height;
+	attributes.wclass = GDK_INPUT_OUTPUT;
+	attributes.visual = gtk_widget_get_visual(widget);
+	attributes.colormap = gtk_widget_get_colormap(widget);
+	attributes.event_mask = GDK_EXPOSURE_MASK;
+
+	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+	child->window = gdk_window_new(form->bin_window,
+				       &attributes, attributes_mask);
+	gdk_window_set_user_data(child->window, widget);
+
+	gtk_style_set_background(widget->style,
+				 child->window,
+				 GTK_STATE_NORMAL);
+
+	gtk_widget_set_parent_window(child->widget, child->window);
+	gtk_form_set_static_gravity(child->window, TRUE);
+	/*
+	 * Install signal handlers to map/unmap child->window
+	 * alongside with the actual widget.
+	 */
+	gtk_signal_connect(GTK_OBJECT(child->widget), "map",
+			   GTK_SIGNAL_FUNC(&gtk_form_child_map), child);
+	gtk_signal_connect(GTK_OBJECT(child->widget), "unmap",
+			   GTK_SIGNAL_FUNC(&gtk_form_child_unmap), child);
+    }
+    else if (!GTK_WIDGET_REALIZED(child->widget))
+    {
+	gtk_widget_set_parent_window(child->widget, form->bin_window);
+    }
+}
+
+    static void
+gtk_form_realize_child(GtkForm *form, GtkFormChild *child)
+{
+    gtk_form_attach_child_window(form, child);
+    gtk_widget_realize(child->widget);
+
+    if (child->window == NULL) /* might be already set, see above */
+	gtk_form_set_static_gravity(child->widget->window, TRUE);
+}
+
+    static void
+gtk_form_position_child(GtkForm *form, GtkFormChild *child,
+			gboolean force_allocate)
+{
+    gint x;
+    gint y;
+
+    x = child->x;
+    y = child->y;
+
+    if ((x >= G_MINSHORT) && (x <= G_MAXSHORT) &&
+	(y >= G_MINSHORT) && (y <= G_MAXSHORT))
+    {
+	if (!child->mapped)
+	{
+	    if (GTK_WIDGET_MAPPED(form) && GTK_WIDGET_VISIBLE(child->widget))
+	    {
+		if (!GTK_WIDGET_MAPPED(child->widget))
+		    gtk_widget_map(child->widget);
+
+		child->mapped = TRUE;
+		force_allocate = TRUE;
+	    }
+	}
+
+	if (force_allocate)
+	{
+	    GtkAllocation allocation;
+
+	    if (GTK_WIDGET_NO_WINDOW(child->widget))
+	    {
+		if (child->window)
+		{
+		    gdk_window_move_resize(child->window,
+			    x, y,
+			    child->widget->requisition.width,
+			    child->widget->requisition.height);
+		}
+
+		allocation.x = 0;
+		allocation.y = 0;
+	    }
+	    else
+	    {
+		allocation.x = x;
+		allocation.y = y;
+	    }
+
+	    allocation.width = child->widget->requisition.width;
+	    allocation.height = child->widget->requisition.height;
+
+	    gtk_widget_size_allocate(child->widget, &allocation);
+	}
+    }
+    else
+    {
+	if (child->mapped)
+	{
+	    child->mapped = FALSE;
+
+	    if (GTK_WIDGET_MAPPED(child->widget))
+		gtk_widget_unmap(child->widget);
+	}
+    }
+}
+
+    static void
+gtk_form_position_children(GtkForm *form)
+{
+    GList *tmp_list;
+
+    for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+	gtk_form_position_child(form, tmp_list->data, FALSE);
+}
+
+/* Callbacks */
+
+/* The main event filter. Actually, we probably don't really need
+ * to install this as a filter at all, since we are calling it
+ * directly above in the expose-handling hack.
+ *
+ * This routine identifies expose events that are generated when
+ * we've temporarily moved the bin_window_origin, and translates
+ * them or discards them, depending on whether we are obscured
+ * or not.
+ */
+/*ARGSUSED1*/
+    static GdkFilterReturn
+gtk_form_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
+{
+    XEvent *xevent;
+    GtkForm *form;
+
+    xevent = (XEvent *) gdk_xevent;
+    form = GTK_FORM(data);
+
+    switch (xevent->type)
+    {
+    case Expose:
+	if (xevent->xexpose.serial == form->configure_serial)
+	{
+	    if (form->visibility == GDK_VISIBILITY_UNOBSCURED)
+		return GDK_FILTER_REMOVE;
+	    else
+		break;
+	}
+	break;
+
+    case ConfigureNotify:
+	if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0))
+	    form->configure_serial = xevent->xconfigure.serial;
+	break;
+    }
+
+    return GDK_FILTER_CONTINUE;
+}
+
+/* Although GDK does have a GDK_VISIBILITY_NOTIFY event,
+ * there is no corresponding event in GTK, so we have
+ * to get the events from a filter
+ */
+/*ARGSUSED1*/
+    static GdkFilterReturn
+gtk_form_main_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
+{
+    XEvent *xevent;
+    GtkForm *form;
+
+    xevent = (XEvent *) gdk_xevent;
+    form = GTK_FORM(data);
+
+    if (xevent->type == VisibilityNotify)
+    {
+	switch (xevent->xvisibility.state)
+	{
+	case VisibilityFullyObscured:
+	    form->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
+	    break;
+
+	case VisibilityPartiallyObscured:
+	    form->visibility = GDK_VISIBILITY_PARTIAL;
+	    break;
+
+	case VisibilityUnobscured:
+	    form->visibility = GDK_VISIBILITY_UNOBSCURED;
+	    break;
+	}
+
+	return GDK_FILTER_REMOVE;
+    }
+    return GDK_FILTER_CONTINUE;
+}
+
+/* Routines to set the window gravity, and check whether it is
+ * functional. Extra capabilities need to be added to GDK, so
+ * we don't have to use Xlib here.
+ */
+    static void
+gtk_form_set_static_gravity(GdkWindow *window, gboolean use_static)
+{
+#ifdef HAVE_GTK2
+    gboolean static_gravity_supported;
+
+    static_gravity_supported = gdk_window_set_static_gravities(window,
+							       use_static);
+    g_return_if_fail(static_gravity_supported);
+#else
+    XSetWindowAttributes xattributes;
+
+    xattributes.win_gravity = (use_static) ? StaticGravity : NorthWestGravity;
+    xattributes.bit_gravity = (use_static) ? StaticGravity : NorthWestGravity;
+
+    XChangeWindowAttributes(GDK_WINDOW_XDISPLAY(window),
+			    GDK_WINDOW_XWINDOW(window),
+			    CWBitGravity | CWWinGravity,
+			    &xattributes);
+#endif
+}
+
+    void
+gtk_form_move_resize(GtkForm *form, GtkWidget *widget,
+		     gint x, gint y, gint w, gint h)
+{
+    widget->requisition.width  = w;
+    widget->requisition.height = h;
+
+    gtk_form_move(form, widget, x, y);
+}
+
+    static void
+gtk_form_send_configure(GtkForm *form)
+{
+    GtkWidget *widget;
+    GdkEventConfigure event;
+
+    widget = GTK_WIDGET(form);
+
+    event.type = GDK_CONFIGURE;
+    event.window = widget->window;
+    event.x = widget->allocation.x;
+    event.y = widget->allocation.y;
+    event.width = widget->allocation.width;
+    event.height = widget->allocation.height;
+
+#ifdef HAVE_GTK2
+    gtk_main_do_event((GdkEvent*)&event);
+#else
+    gtk_widget_event(widget, (GdkEvent*)&event);
+#endif
+}
+
+/*ARGSUSED0*/
+    static void
+gtk_form_child_map(GtkWidget *widget, gpointer user_data)
+{
+    GtkFormChild *child;
+
+    child = (GtkFormChild *)user_data;
+
+    child->mapped = TRUE;
+    gdk_window_show(child->window);
+}
+
+/*ARGSUSED0*/
+    static void
+gtk_form_child_unmap(GtkWidget *widget, gpointer user_data)
+{
+    GtkFormChild *child;
+
+    child = (GtkFormChild *)user_data;
+
+    child->mapped = FALSE;
+    gdk_window_hide(child->window);
+}
+