summaryrefslogtreecommitdiff
path: root/src/gui_gtk_f.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
committerBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
commit071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch)
tree221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/gui_gtk_f.c
parentb4210b3bc14e2918f153a7307530fbe6eba659e1 (diff)
downloadvim-git-071d4279d6ab81b7187b48f3a0fc61e587b6db6c.tar.gz
updated for version 7.0001v7.0001
Diffstat (limited to 'src/gui_gtk_f.c')
-rw-r--r--src/gui_gtk_f.c942
1 files changed, 942 insertions, 0 deletions
diff --git a/src/gui_gtk_f.c b/src/gui_gtk_f.c
new file mode 100644
index 000000000..2cb82d646
--- /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);
+}
+