summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--ChangeLog.pre-2-014
-rw-r--r--ChangeLog.pre-2-1014
-rw-r--r--ChangeLog.pre-2-214
-rw-r--r--ChangeLog.pre-2-414
-rw-r--r--ChangeLog.pre-2-614
-rw-r--r--ChangeLog.pre-2-814
-rw-r--r--Makefile.am2
-rw-r--r--TODO4
-rw-r--r--gtk/Makefile.am6
-rw-r--r--gtk/gtk.h3
-rw-r--r--gtk/gtklayout.c1207
-rw-r--r--gtk/gtklayout.h104
-rw-r--r--gtk/gtkplug.c409
-rw-r--r--gtk/gtkplug.h65
-rw-r--r--gtk/gtksocket.c688
-rw-r--r--gtk/gtksocket.h68
-rw-r--r--gtk/gtkwindow.c52
-rw-r--r--gtk/gtkwindow.h3
-rw-r--r--gtk/testgtk.c89
-rw-r--r--tests/testgtk.c89
21 files changed, 2882 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index d3f6796867..3936d9a007 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Mon Nov 23 22:10:09 1998 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/Makefile.am gtk/gtk.h gtk/gtklayout.[ch]
+ gtk/gtkplug.[ch] gtk/gtksocket.[ch] gtk/gtk.h:
+
+ Added layout widget for scrolling arbitrarily big areas.
+ Added plug/socket widgets for interprocess embedding.
+
+ These widgets still, at some point, need to be
+ made more pure in their use of GDK, as opposed
+ to raw X.
+
+ * gtk/testgtk.c: Added test for layout widget.
+
1998-11-23 Jeff Garzik <jgarzik@pobox.com>
* gtk/gtkclist.c: (gtk_clist_swap_rows): Bugfix from
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index d3f6796867..3936d9a007 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -1,3 +1,17 @@
+Mon Nov 23 22:10:09 1998 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/Makefile.am gtk/gtk.h gtk/gtklayout.[ch]
+ gtk/gtkplug.[ch] gtk/gtksocket.[ch] gtk/gtk.h:
+
+ Added layout widget for scrolling arbitrarily big areas.
+ Added plug/socket widgets for interprocess embedding.
+
+ These widgets still, at some point, need to be
+ made more pure in their use of GDK, as opposed
+ to raw X.
+
+ * gtk/testgtk.c: Added test for layout widget.
+
1998-11-23 Jeff Garzik <jgarzik@pobox.com>
* gtk/gtkclist.c: (gtk_clist_swap_rows): Bugfix from
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index d3f6796867..3936d9a007 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,17 @@
+Mon Nov 23 22:10:09 1998 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/Makefile.am gtk/gtk.h gtk/gtklayout.[ch]
+ gtk/gtkplug.[ch] gtk/gtksocket.[ch] gtk/gtk.h:
+
+ Added layout widget for scrolling arbitrarily big areas.
+ Added plug/socket widgets for interprocess embedding.
+
+ These widgets still, at some point, need to be
+ made more pure in their use of GDK, as opposed
+ to raw X.
+
+ * gtk/testgtk.c: Added test for layout widget.
+
1998-11-23 Jeff Garzik <jgarzik@pobox.com>
* gtk/gtkclist.c: (gtk_clist_swap_rows): Bugfix from
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index d3f6796867..3936d9a007 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -1,3 +1,17 @@
+Mon Nov 23 22:10:09 1998 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/Makefile.am gtk/gtk.h gtk/gtklayout.[ch]
+ gtk/gtkplug.[ch] gtk/gtksocket.[ch] gtk/gtk.h:
+
+ Added layout widget for scrolling arbitrarily big areas.
+ Added plug/socket widgets for interprocess embedding.
+
+ These widgets still, at some point, need to be
+ made more pure in their use of GDK, as opposed
+ to raw X.
+
+ * gtk/testgtk.c: Added test for layout widget.
+
1998-11-23 Jeff Garzik <jgarzik@pobox.com>
* gtk/gtkclist.c: (gtk_clist_swap_rows): Bugfix from
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index d3f6796867..3936d9a007 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -1,3 +1,17 @@
+Mon Nov 23 22:10:09 1998 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/Makefile.am gtk/gtk.h gtk/gtklayout.[ch]
+ gtk/gtkplug.[ch] gtk/gtksocket.[ch] gtk/gtk.h:
+
+ Added layout widget for scrolling arbitrarily big areas.
+ Added plug/socket widgets for interprocess embedding.
+
+ These widgets still, at some point, need to be
+ made more pure in their use of GDK, as opposed
+ to raw X.
+
+ * gtk/testgtk.c: Added test for layout widget.
+
1998-11-23 Jeff Garzik <jgarzik@pobox.com>
* gtk/gtkclist.c: (gtk_clist_swap_rows): Bugfix from
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index d3f6796867..3936d9a007 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,3 +1,17 @@
+Mon Nov 23 22:10:09 1998 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/Makefile.am gtk/gtk.h gtk/gtklayout.[ch]
+ gtk/gtkplug.[ch] gtk/gtksocket.[ch] gtk/gtk.h:
+
+ Added layout widget for scrolling arbitrarily big areas.
+ Added plug/socket widgets for interprocess embedding.
+
+ These widgets still, at some point, need to be
+ made more pure in their use of GDK, as opposed
+ to raw X.
+
+ * gtk/testgtk.c: Added test for layout widget.
+
1998-11-23 Jeff Garzik <jgarzik@pobox.com>
* gtk/gtkclist.c: (gtk_clist_swap_rows): Bugfix from
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index d3f6796867..3936d9a007 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,17 @@
+Mon Nov 23 22:10:09 1998 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/Makefile.am gtk/gtk.h gtk/gtklayout.[ch]
+ gtk/gtkplug.[ch] gtk/gtksocket.[ch] gtk/gtk.h:
+
+ Added layout widget for scrolling arbitrarily big areas.
+ Added plug/socket widgets for interprocess embedding.
+
+ These widgets still, at some point, need to be
+ made more pure in their use of GDK, as opposed
+ to raw X.
+
+ * gtk/testgtk.c: Added test for layout widget.
+
1998-11-23 Jeff Garzik <jgarzik@pobox.com>
* gtk/gtkclist.c: (gtk_clist_swap_rows): Bugfix from
diff --git a/Makefile.am b/Makefile.am
index 9df27bcd09..3e7c998203 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,7 @@
SRC_SUBDIRS = gdk gtk
SUBDIRS = $(SRC_SUBDIRS) docs
-bin_SCRIPTS = gtk-config
+bbin_SCRIPTS = gtk-config
EXTRA_DIST = \
HACKING \
diff --git a/TODO b/TODO
index 098c544e13..9cb2cffada 100644
--- a/TODO
+++ b/TODO
@@ -110,10 +110,6 @@ Additions:
gtk_widget_dnd_data_set (should be guchar * with a copy?
shouldn't be there at all...)
- * gtk_rc_add_[name/class]_style are broken for bg pixmaps, because
- styles are broken for bg pixmaps, and RC styles only hack around
- that.
-
* Try to rationally deal with someone else deleting one of our
windows??? This would mean keeping track of our window heirarchy
ourselves, for one thing, and will never be safe, because of
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index fd06f46168..6e64f95b29 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -55,6 +55,7 @@ static_sources = \
gtkitem.c \
gtkitemfactory.c \
gtklabel.c \
+ gtklayout.c \
gtklist.c \
gtklistitem.c \
gtkmain.c \
@@ -70,6 +71,7 @@ static_sources = \
gtkpacker.c \
gtkpaned.c \
gtkpixmap.c \
+ gtkplug.c \
gtkpreview.c \
gtkprogress.c \
gtkprogressbar.c \
@@ -84,6 +86,7 @@ static_sources = \
gtkselection.c \
gtkseparator.c \
gtksignal.c \
+ gtksocket.c \
gtkspinbutton.c \
gtkstyle.c \
gtkstatusbar.c \
@@ -169,6 +172,7 @@ source_headers = \
gtkitem.h \
gtkitemfactory.h \
gtklabel.h \
+ gtklayout.h \
gtklist.h \
gtklistitem.h \
gtkmain.h \
@@ -184,6 +188,7 @@ source_headers = \
gtkpacker.h \
gtkpaned.h \
gtkpixmap.h \
+ gtkplug.h \
gtkpreview.h \
gtkprivate.h \
gtkprogress.h \
@@ -199,6 +204,7 @@ source_headers = \
gtkselection.h \
gtkseparator.h \
gtksignal.h \
+ gtksocket.h \
gtkspinbutton.h \
gtkstyle.h \
gtkstatusbar.h \
diff --git a/gtk/gtk.h b/gtk/gtk.h
index b59c5c4937..abad5ed614 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -71,6 +71,7 @@
#include <gtk/gtkitem.h>
#include <gtk/gtkitemfactory.h>
#include <gtk/gtklabel.h>
+#include <gtk/gtklayout.h>
#include <gtk/gtklist.h>
#include <gtk/gtklistitem.h>
#include <gtk/gtkmain.h>
@@ -86,6 +87,7 @@
#include <gtk/gtkpacker.h>
#include <gtk/gtkpaned.h>
#include <gtk/gtkpixmap.h>
+#include <gtk/gtkplug.h>
#include <gtk/gtkpreview.h>
#include <gtk/gtkprogress.h>
#include <gtk/gtkprogressbar.h>
@@ -100,6 +102,7 @@
#include <gtk/gtkselection.h>
#include <gtk/gtkseparator.h>
#include <gtk/gtksignal.h>
+#include <gtk/gtksocket.h>
#include <gtk/gtkspinbutton.h>
#include <gtk/gtkstyle.h>
#include <gtk/gtkstatusbar.h>
diff --git a/gtk/gtklayout.c b/gtk/gtklayout.c
new file mode 100644
index 0000000000..0c9c2be789
--- /dev/null
+++ b/gtk/gtklayout.c
@@ -0,0 +1,1207 @@
+/* Copyright Owen Taylor, 1998
+ *
+ * This file may be distributed under either the terms of the
+ * Netscape Public License, or the GNU Library General Public License
+ *
+ * Note: No GTK+ or Mozilla code should be added to this file.
+ * The coding style should be that of the the GTK core.
+ */
+
+#include "gtklayout.h"
+#include "gtksignal.h"
+#include "gdk/gdkx.h"
+
+
+static void gtk_layout_class_init (GtkLayoutClass *class);
+static void gtk_layout_init (GtkLayout *layout);
+
+static void gtk_layout_realize (GtkWidget *widget);
+static void gtk_layout_unrealize (GtkWidget *widget);
+static void gtk_layout_map (GtkWidget *widget);
+static void gtk_layout_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+static void gtk_layout_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static void gtk_layout_draw (GtkWidget *widget,
+ GdkRectangle *area);
+static gint gtk_layout_expose (GtkWidget *widget,
+ GdkEventExpose *event);
+
+static void gtk_layout_remove (GtkContainer *container,
+ GtkWidget *widget);
+static void gtk_layout_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data);
+static void gtk_layout_set_adjustments (GtkLayout *layout,
+ GtkAdjustment *hadj,
+ GtkAdjustment *vadj);
+
+static void gtk_layout_realize_child (GtkLayout *layout,
+ GtkLayoutChild *child);
+static void gtk_layout_position_child (GtkLayout *layout,
+ GtkLayoutChild *child,
+ gboolean force_allocate);
+static void gtk_layout_position_children (GtkLayout *layout);
+
+static void gtk_layout_expose_area (GtkLayout *layout,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
+static void gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
+ GtkLayout *layout);
+static GdkFilterReturn gtk_layout_filter (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data);
+static GdkFilterReturn gtk_layout_main_filter (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data);
+
+static gboolean gtk_layout_gravity_works (void);
+static void gtk_layout_set_static_gravity (GdkWindow *win,
+ gboolean op);
+
+static GtkWidgetClass *parent_class = NULL;
+static gboolean gravity_works;
+
+/* Public interface
+ */
+
+GtkWidget*
+gtk_layout_new (GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment)
+{
+ GtkLayout *layout;
+
+ layout = gtk_type_new (gtk_layout_get_type());
+
+ gtk_layout_set_hadjustment (layout, hadjustment);
+ gtk_layout_set_vadjustment (layout, vadjustment);
+
+ return GTK_WIDGET (layout);
+}
+
+GtkAdjustment*
+gtk_layout_get_hadjustment (GtkLayout *layout)
+{
+ g_return_val_if_fail (layout != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
+
+ return layout->hadjustment;
+}
+GtkAdjustment*
+gtk_layout_get_vadjustment (GtkLayout *layout)
+{
+ g_return_val_if_fail (layout != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
+
+ return layout->vadjustment;
+}
+
+static void
+gtk_layout_set_adjustments (GtkLayout *layout,
+ GtkAdjustment *hadj,
+ GtkAdjustment *vadj)
+{
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (layout));
+
+ if (hadj)
+ g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
+ else
+ hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+ if (vadj)
+ g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
+ else
+ vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+
+ if (layout->hadjustment && (layout->hadjustment != hadj))
+ {
+ gtk_signal_disconnect_by_data (GTK_OBJECT (layout->hadjustment), layout);
+ gtk_object_unref (GTK_OBJECT (layout->hadjustment));
+ }
+
+ if (layout->vadjustment && (layout->vadjustment != vadj))
+ {
+ gtk_signal_disconnect_by_data (GTK_OBJECT (layout->vadjustment), layout);
+ gtk_object_unref (GTK_OBJECT (layout->vadjustment));
+ }
+
+ if (layout->hadjustment != hadj)
+ {
+ layout->hadjustment = hadj;
+ gtk_object_ref (GTK_OBJECT (layout->hadjustment));
+ gtk_object_sink (GTK_OBJECT (layout->hadjustment));
+
+ gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed",
+ (GtkSignalFunc) gtk_layout_adjustment_changed,
+ layout);
+ gtk_layout_adjustment_changed (hadj, layout);
+ }
+
+ if (layout->vadjustment != vadj)
+ {
+ layout->vadjustment = vadj;
+ gtk_object_ref (GTK_OBJECT (layout->vadjustment));
+ gtk_object_sink (GTK_OBJECT (layout->vadjustment));
+
+ gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed",
+ (GtkSignalFunc) gtk_layout_adjustment_changed,
+ layout);
+ gtk_layout_adjustment_changed (vadj, layout);
+ }
+}
+
+void
+gtk_layout_set_hadjustment (GtkLayout *layout,
+ GtkAdjustment *adjustment)
+{
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (layout));
+
+ if (layout->hadjustment)
+ gtk_object_unref (GTK_OBJECT (layout->hadjustment));
+
+ if (!adjustment)
+ adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 10.0, 0.0, 0.0));
+ else
+ gtk_object_ref (GTK_OBJECT (adjustment));
+
+ gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+ GTK_SIGNAL_FUNC (gtk_layout_adjustment_changed),
+ layout);
+
+ layout->hadjustment = adjustment;
+}
+
+
+void
+gtk_layout_set_vadjustment (GtkLayout *layout,
+ GtkAdjustment *adjustment)
+{
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (layout));
+
+ if (layout->vadjustment)
+ gtk_object_unref (GTK_OBJECT (layout->hadjustment));
+
+ if (!adjustment)
+ adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 10.0, 0.0, 0.0));
+ else
+ gtk_object_ref (GTK_OBJECT (adjustment));
+
+ gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+ GTK_SIGNAL_FUNC (gtk_layout_adjustment_changed),
+ layout);
+
+ layout->vadjustment = adjustment;
+}
+
+
+void
+gtk_layout_put (GtkLayout *layout,
+ GtkWidget *child_widget,
+ gint x,
+ gint y)
+{
+ GtkLayoutChild *child;
+
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (layout));
+
+ child = g_new (GtkLayoutChild, 1);
+
+ child->widget = child_widget;
+ child->window = NULL;
+ child->x = x;
+ child->y = y;
+ child->widget->requisition.width = 0;
+ child->widget->requisition.height = 0;
+
+ layout->children = g_list_append (layout->children, child);
+
+ gtk_widget_set_parent (child_widget, GTK_WIDGET (layout));
+
+ gtk_widget_size_request (child->widget, &child->widget->requisition);
+
+ if (GTK_WIDGET_REALIZED (layout) &&
+ !GTK_WIDGET_REALIZED (child_widget))
+ gtk_layout_realize_child (layout, child);
+
+ gtk_layout_position_child (layout, child, TRUE);
+}
+
+void
+gtk_layout_move (GtkLayout *layout,
+ GtkWidget *child_widget,
+ gint x,
+ gint y)
+{
+ GList *tmp_list;
+ GtkLayoutChild *child;
+
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (layout));
+
+ tmp_list = layout->children;
+ while (tmp_list)
+ {
+ child = tmp_list->data;
+ if (child->widget == child_widget)
+ {
+ child->x = x;
+ child->y = y;
+
+ gtk_layout_position_child (layout, child, TRUE);
+ return;
+ }
+ tmp_list = tmp_list->next;
+ }
+}
+
+void
+gtk_layout_set_size (GtkLayout *layout,
+ guint width,
+ guint height)
+{
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (layout));
+
+ layout->width = width;
+ layout->height = height;
+
+ layout->hadjustment->upper = layout->width;
+ gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
+
+ layout->vadjustment->upper = layout->height;
+ gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
+}
+
+void
+gtk_layout_freeze (GtkLayout *layout)
+{
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (layout));
+
+ layout->frozen = TRUE;
+}
+
+void
+gtk_layout_thaw (GtkLayout *layout)
+{
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (layout));
+
+ if (!layout->frozen)
+ return;
+
+ layout->frozen = FALSE;
+ gtk_layout_position_children (layout);
+ gtk_widget_draw (GTK_WIDGET (layout), NULL);
+}
+
+/* Basic Object handling procedures
+ */
+guint
+gtk_layout_get_type (void)
+{
+ static guint layout_type = 0;
+
+ if (!layout_type)
+ {
+ GtkTypeInfo layout_info =
+ {
+ "GtkLayout",
+ sizeof (GtkLayout),
+ sizeof (GtkLayoutClass),
+ (GtkClassInitFunc) gtk_layout_class_init,
+ (GtkObjectInitFunc) gtk_layout_init,
+ (GtkArgSetFunc) NULL,
+ (GtkArgGetFunc) NULL,
+ };
+
+ layout_type = gtk_type_unique (gtk_container_get_type (), &layout_info);
+ }
+
+ return layout_type;
+}
+
+static void
+gtk_layout_class_init (GtkLayoutClass *class)
+{
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkContainerClass *container_class;
+
+ object_class = (GtkObjectClass*) class;
+ widget_class = (GtkWidgetClass*) class;
+ container_class = (GtkContainerClass*) class;
+
+ parent_class = gtk_type_class (gtk_container_get_type ());
+
+ widget_class->realize = gtk_layout_realize;
+ widget_class->unrealize = gtk_layout_unrealize;
+ widget_class->map = gtk_layout_map;
+ widget_class->size_request = gtk_layout_size_request;
+ widget_class->size_allocate = gtk_layout_size_allocate;
+ widget_class->draw = gtk_layout_draw;
+ widget_class->expose_event = gtk_layout_expose;
+
+ widget_class->scroll_adjustments_signal =
+ gtk_signal_new ("scroll_adjustments",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (GtkLayoutClass, scroll_adjustments),
+ gtk_marshal_NONE__POINTER_POINTER,
+ GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
+
+ gravity_works = gtk_layout_gravity_works ();
+
+ container_class->remove = gtk_layout_remove;
+ container_class->forall = gtk_layout_forall;
+
+ class->scroll_adjustments = gtk_layout_set_adjustments;
+}
+
+static void
+gtk_layout_init (GtkLayout *layout)
+{
+ layout->children = NULL;
+
+ layout->width = 100;
+ layout->height = 100;
+
+ layout->hadjustment = NULL;
+ layout->vadjustment = NULL;
+
+ layout->bin_window = NULL;
+
+ layout->configure_serial = 0;
+ layout->scroll_x = 0;
+ layout->scroll_y = 0;
+ layout->visibility = GDK_VISIBILITY_PARTIAL;
+}
+
+/* Widget methods
+ */
+
+static void
+gtk_layout_realize (GtkWidget *widget)
+{
+ GList *tmp_list;
+ GtkLayout *layout;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (widget));
+
+ layout = GTK_LAYOUT (widget);
+ GTK_WIDGET_SET_FLAGS (layout, 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);
+
+ layout->bin_window = gdk_window_new (widget->window,
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (layout->bin_window, widget);
+
+ if (gravity_works)
+ gtk_layout_set_static_gravity (layout->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, layout->bin_window, GTK_STATE_NORMAL);
+
+ gdk_window_add_filter (widget->window, gtk_layout_main_filter, layout);
+ gdk_window_add_filter (layout->bin_window, gtk_layout_filter, layout);
+
+ tmp_list = layout->children;
+ while (tmp_list)
+ {
+ GtkLayoutChild *child = tmp_list->data;
+
+ if (GTK_WIDGET_VISIBLE (child->widget))
+ gtk_layout_realize_child (layout, child);
+
+ tmp_list = tmp_list->next;
+ }
+}
+
+static void
+gtk_layout_map (GtkWidget *widget)
+{
+ GList *tmp_list;
+ GtkLayout *layout;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (widget));
+
+ layout = GTK_LAYOUT (widget);
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+
+ gdk_window_show (widget->window);
+ gdk_window_show (layout->bin_window);
+
+ tmp_list = layout->children;
+ while (tmp_list)
+ {
+ GtkLayoutChild *child = tmp_list->data;
+
+ if (GTK_WIDGET_VISIBLE (child->widget) &&
+ !GTK_WIDGET_MAPPED (child->widget))
+ gtk_widget_map (child->widget);
+
+ if (child->window)
+ gdk_window_show (child->window);
+
+ tmp_list = tmp_list->next;
+ }
+
+}
+
+static void
+gtk_layout_unrealize (GtkWidget *widget)
+{
+ GList *tmp_list;
+ GtkLayout *layout;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (widget));
+
+ layout = GTK_LAYOUT (widget);
+
+ tmp_list = layout->children;
+
+ gdk_window_set_user_data (layout->bin_window, NULL);
+ gdk_window_destroy (layout->bin_window);
+ layout->bin_window = NULL;
+
+ while (tmp_list)
+ {
+ GtkLayoutChild *child = tmp_list->data;
+
+ if (child->window)
+ {
+ gdk_window_set_user_data (child->window, NULL);
+ gdk_window_destroy (child->window);
+ }
+
+ tmp_list = tmp_list->next;
+ }
+}
+
+static void
+gtk_layout_draw (GtkWidget *widget, GdkRectangle *area)
+{
+ GtkLayout *layout;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (widget));
+
+ layout = GTK_LAYOUT (widget);
+}
+
+static void
+gtk_layout_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GList *tmp_list;
+ GtkLayout *layout;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (widget));
+
+ layout = GTK_LAYOUT (widget);
+
+ tmp_list = layout->children;
+
+ while (tmp_list)
+ {
+ GtkLayoutChild *child = tmp_list->data;
+ gtk_widget_size_request (child->widget, &child->widget->requisition);
+
+ tmp_list = tmp_list->next;
+ }
+}
+
+static void
+gtk_layout_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GList *tmp_list;
+ GtkLayout *layout;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (widget));
+
+ widget->allocation = *allocation;
+
+ layout = GTK_LAYOUT (widget);
+
+ tmp_list = layout->children;
+
+ while (tmp_list)
+ {
+ GtkLayoutChild *child = tmp_list->data;
+ gtk_layout_position_child (layout, 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_LAYOUT(widget)->bin_window,
+ 0, 0,
+ allocation->width, allocation->height);
+ }
+
+ layout->hadjustment->page_size = allocation->width;
+ layout->hadjustment->page_increment = allocation->width / 2;
+ gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
+
+ layout->vadjustment->page_size = allocation->height;
+ layout->vadjustment->page_increment = allocation->height / 2;
+ gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
+}
+
+static gint
+gtk_layout_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+ GList *tmp_list;
+ GtkLayout *layout;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_LAYOUT (widget), FALSE);
+
+ layout = GTK_LAYOUT (widget);
+
+ if (event->window == layout->bin_window)
+ return FALSE;
+
+ tmp_list = layout->children;
+ while (tmp_list)
+ {
+ GtkLayoutChild *child = tmp_list->data;
+
+ if (event->window == child->window)
+ return gtk_widget_event (child->widget, (GdkEvent *)event);
+
+ tmp_list = tmp_list->next;
+ }
+
+ return FALSE;
+}
+
+/* Container method
+ */
+static void
+gtk_layout_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ GList *tmp_list;
+ GtkLayout *layout;
+ GtkLayoutChild *child;
+
+ g_return_if_fail (container != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (container));
+
+ layout = GTK_LAYOUT (container);
+
+ tmp_list = layout->children;
+ while (tmp_list)
+ {
+ child = tmp_list->data;
+ if (child->widget == widget)
+ break;
+ tmp_list = tmp_list->next;
+ }
+
+ if (tmp_list)
+ {
+ if (child->window)
+ {
+ /* FIXME: This will cause problems for reparenting NO_WINDOW
+ * widgets out of a GtkLayout
+ */
+ gdk_window_set_user_data (child->window, NULL);
+ gdk_window_destroy (child->window);
+ }
+
+ gtk_widget_unparent (widget);
+
+ layout->children = g_list_remove_link (layout->children, tmp_list);
+ g_list_free_1 (tmp_list);
+ g_free (child);
+ }
+}
+
+static void
+gtk_layout_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ GtkLayout *layout;
+ GtkLayoutChild *child;
+ GList *tmp_list;
+
+ g_return_if_fail (container != NULL);
+ g_return_if_fail (GTK_IS_LAYOUT (container));
+ g_return_if_fail (callback != NULL);
+
+ layout = GTK_LAYOUT (container);
+
+ tmp_list = layout->children;
+ while (tmp_list)
+ {
+ child = tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ (* callback) (child->widget, callback_data);
+ }
+}
+
+/* Operations on children
+ */
+
+static void
+gtk_layout_realize_child (GtkLayout *layout,
+ GtkLayoutChild *child)
+{
+ GtkWidget *widget;
+ gint attributes_mask;
+
+ widget = GTK_WIDGET (layout);
+
+ if (GTK_WIDGET_NO_WINDOW (child->widget))
+ {
+ GdkWindowAttr attributes;
+
+ gint x = child->x - layout->xoffset;
+ gint y = child->y - layout->xoffset;
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = x;
+ attributes.y = 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 (layout->bin_window,
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (child->window, widget);
+
+ if (child->window)
+ gtk_style_set_background (widget->style,
+ child->window,
+ GTK_STATE_NORMAL);
+ }
+
+ gtk_widget_set_parent_window (child->widget,
+ child->window ? child->window : layout->bin_window);
+
+ gtk_widget_realize (child->widget);
+
+ if (gravity_works)
+ gtk_layout_set_static_gravity (child->window ? child->window : child->widget->window, TRUE);
+}
+
+static void
+gtk_layout_position_child (GtkLayout *layout,
+ GtkLayoutChild *child,
+ gboolean force_allocate)
+{
+ gint x;
+ gint y;
+
+ x = child->x - layout->xoffset;
+ y = child->y - layout->yoffset;
+
+ if ((x >= G_MINSHORT) && (x <= G_MAXSHORT) &&
+ (y >= G_MINSHORT) && (y <= G_MAXSHORT))
+ {
+ if (GTK_WIDGET_VISIBLE (child->widget) &&
+ GTK_WIDGET_MAPPED (layout) &&
+ !GTK_WIDGET_MAPPED (child->widget))
+ {
+ gtk_widget_map (child->widget);
+ 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->window)
+ gdk_window_hide (child->window);
+ else if (GTK_WIDGET_MAPPED (child->widget))
+ gtk_widget_unmap (child->widget);
+ }
+}
+
+static void
+gtk_layout_position_children (GtkLayout *layout)
+{
+ GList *tmp_list;
+
+ tmp_list = layout->children;
+ while (tmp_list)
+ {
+ gtk_layout_position_child (layout, tmp_list->data, FALSE);
+
+ tmp_list = tmp_list->next;
+ }
+}
+
+/* Callbacks */
+
+/* Send a synthetic expose event to the widget
+ */
+static void
+gtk_layout_expose_area (GtkLayout *layout,
+ gint x, gint y, gint width, gint height)
+{
+ if (layout->visibility == GDK_VISIBILITY_UNOBSCURED)
+ {
+ GdkEventExpose event;
+
+ event.type = GDK_EXPOSE;
+ event.send_event = TRUE;
+ event.window = layout->bin_window;
+ event.count = 0;
+
+ event.area.x = x;
+ event.area.y = y;
+ event.area.width = width;
+ event.area.height = height;
+
+ gdk_window_ref (event.window);
+ gtk_widget_event (GTK_WIDGET (layout), (GdkEvent *)&event);
+ gdk_window_unref (event.window);
+ }
+}
+
+/* This function is used to find events to process while scrolling
+ * Removing the GravityNotify events is a bit of a hack - currently
+ * GTK uses a lot of time processing them as GtkEventOther - a
+ * feature that is obsolete and will be removed. Until then...
+ */
+
+static Bool
+gtk_layout_expose_predicate (Display *display,
+ XEvent *xevent,
+ XPointer arg)
+{
+ if ((xevent->type == Expose) || (xevent->type == GravityNotify) ||
+ ((xevent->xany.window == *(Window *)arg) &&
+ (xevent->type == ConfigureNotify)))
+ return True;
+ else
+ return False;
+}
+
+/* This is the main routine to do the scrolling. Scrolling is
+ * done by "Guffaw" scrolling, as in the Mozilla XFE, with
+ * a few modifications.
+ *
+ * The main improvement is that we keep track of whether we
+ * are obscured or not. If not, we ignore the generated expose
+ * events and instead do the exposes ourself, without having
+ * to wait for a roundtrip to the server. This also provides
+ * a limited form of expose-event compression, since we do
+ * the affected area as one big chunk.
+ *
+ * Real expose event compression, as in the XFE, could be added
+ * here. It would help opaque drags over the region, and the
+ * obscured case.
+ *
+ * Code needs to be added here to do the scrolling on machines
+ * that don't have working WindowGravity. That could be done
+ *
+ * - XCopyArea and move the windows, and accept trailing the
+ * background color. (Since it is only a fallback method)
+ * - XmHTML style. As above, but turn off expose events when
+ * not obscured and do the exposures ourself.
+ * - gzilla-style. Move the window continuously, and reset
+ * every 32768 pixels
+ */
+
+static void
+gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
+ GtkLayout *layout)
+{
+ GtkWidget *widget;
+ XEvent xevent;
+
+ gint dx, dy;
+
+ widget = GTK_WIDGET (layout);
+
+ dx = (gint)layout->hadjustment->value - layout->xoffset;
+ dy = (gint)layout->vadjustment->value - layout->yoffset;
+
+ layout->xoffset = (gint)layout->hadjustment->value;
+ layout->yoffset = (gint)layout->vadjustment->value;
+
+ if (layout->frozen)
+ return;
+
+ gtk_layout_position_children (layout);
+
+ if (!GTK_WIDGET_MAPPED (layout))
+ return;
+
+ if (dx > 0)
+ {
+ if (gravity_works)
+ {
+ gdk_window_resize (layout->bin_window,
+ widget->allocation.width + dx,
+ widget->allocation.height);
+ gdk_window_move (layout->bin_window, -dx, 0);
+ gdk_window_move_resize (layout->bin_window,
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+ }
+ else
+ {
+ /* FIXME */
+ }
+
+ gtk_layout_expose_area (layout,
+ widget->allocation.width - dx,
+ 0,
+ dx,
+ widget->allocation.height);
+ }
+ else if (dx < 0)
+ {
+ if (gravity_works)
+ {
+ gdk_window_move_resize (layout->bin_window,
+ dx, 0,
+ widget->allocation.width - dx,
+ widget->allocation.height);
+ gdk_window_move (layout->bin_window, 0, 0);
+ gdk_window_resize (layout->bin_window,
+ widget->allocation.width,
+ widget->allocation.height);
+ }
+ else
+ {
+ /* FIXME */
+ }
+
+ gtk_layout_expose_area (layout,
+ 0,
+ 0,
+ -dx,
+ widget->allocation.height);
+ }
+
+ if (dy > 0)
+ {
+ if (gravity_works)
+ {
+ gdk_window_resize (layout->bin_window,
+ widget->allocation.width,
+ widget->allocation.height + dy);
+ gdk_window_move (layout->bin_window, 0, -dy);
+ gdk_window_move_resize (layout->bin_window,
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+ }
+ else
+ {
+ /* FIXME */
+ }
+
+ gtk_layout_expose_area (layout,
+ 0,
+ widget->allocation.height - dy,
+ widget->allocation.width,
+ dy);
+ }
+ else if (dy < 0)
+ {
+ if (gravity_works)
+ {
+ gdk_window_move_resize (layout->bin_window,
+ 0, dy,
+ widget->allocation.width,
+ widget->allocation.height - dy);
+ gdk_window_move (layout->bin_window, 0, 0);
+ gdk_window_resize (layout->bin_window,
+ widget->allocation.width,
+ widget->allocation.height);
+ }
+ else
+ {
+ /* FIXME */
+ }
+ gtk_layout_expose_area (layout,
+ 0,
+ 0,
+ widget->allocation.height,
+ -dy);
+ }
+
+ /* We have to make sure that all exposes from this scroll get
+ * processed before we scroll again, or the expose events will
+ * have invalid coordinates.
+ *
+ * We also do expose events for other windows, since otherwise
+ * their updating will fall behind the scrolling
+ *
+ * This also avoids a problem in pre-1.0 GTK where filters don't
+ * have access to configure events that were compressed.
+ */
+
+ gdk_flush();
+ while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (layout->bin_window),
+ &xevent,
+ gtk_layout_expose_predicate,
+ (XPointer)&GDK_WINDOW_XWINDOW (layout->bin_window)))
+ {
+ GdkEvent event;
+ GtkWidget *event_widget;
+
+ if ((xevent.xany.window == GDK_WINDOW_XWINDOW (layout->bin_window)) &&
+ (gtk_layout_filter (&xevent, &event, layout) == GDK_FILTER_REMOVE))
+ continue;
+
+ if (xevent.type == Expose)
+ {
+ event.expose.window = gdk_window_lookup (xevent.xany.window);
+ gdk_window_get_user_data (event.expose.window,
+ (gpointer *)&event_widget);
+
+ if (event_widget)
+ {
+ event.expose.type = GDK_EXPOSE;
+ event.expose.area.x = xevent.xexpose.x;
+ event.expose.area.y = xevent.xexpose.y;
+ event.expose.area.width = xevent.xexpose.width;
+ event.expose.area.height = xevent.xexpose.height;
+ event.expose.count = xevent.xexpose.count;
+
+ gdk_window_ref (event.expose.window);
+ gtk_widget_event (event_widget, &event);
+ gdk_window_unref (event.expose.window);
+ }
+ }
+ }
+}
+
+/* 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. But in case scrollbars
+ * are fixed up in some manner...
+ *
+ * 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.
+ */
+static GdkFilterReturn
+gtk_layout_filter (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ XEvent *xevent;
+ GtkLayout *layout;
+
+ xevent = (XEvent *)gdk_xevent;
+ layout = GTK_LAYOUT (data);
+
+ switch (xevent->type)
+ {
+ case Expose:
+ if (xevent->xexpose.serial == layout->configure_serial)
+ {
+ if (layout->visibility == GDK_VISIBILITY_UNOBSCURED)
+ return GDK_FILTER_REMOVE;
+ else
+ {
+ xevent->xexpose.x += layout->scroll_x;
+ xevent->xexpose.y += layout->scroll_y;
+
+ break;
+ }
+ }
+ break;
+
+ case ConfigureNotify:
+ if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0))
+ {
+ layout->configure_serial = xevent->xconfigure.serial;
+ layout->scroll_x = xevent->xconfigure.x;
+ layout->scroll_y = xevent->xconfigure.y;
+ }
+ 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
+ */
+static GdkFilterReturn
+gtk_layout_main_filter (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ XEvent *xevent;
+ GtkLayout *layout;
+
+ xevent = (XEvent *)gdk_xevent;
+ layout = GTK_LAYOUT (data);
+
+ if (xevent->type == VisibilityNotify)
+ {
+ switch (xevent->xvisibility.state)
+ {
+ case VisibilityFullyObscured:
+ layout->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
+ break;
+
+ case VisibilityPartiallyObscured:
+ layout->visibility = GDK_VISIBILITY_PARTIAL;
+ break;
+
+ case VisibilityUnobscured:
+ layout->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_layout_set_static_gravity (GdkWindow *win, gboolean on)
+{
+ XSetWindowAttributes xattributes;
+
+ xattributes.win_gravity = on ? StaticGravity : NorthWestGravity;
+ xattributes.bit_gravity = on ? StaticGravity : NorthWestGravity;
+
+ XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (win),
+ GDK_WINDOW_XWINDOW (win),
+ CWBitGravity | CWWinGravity,
+ &xattributes);
+}
+
+static gboolean
+gtk_layout_gravity_works (void)
+{
+ GdkWindowAttr attr;
+
+ GdkWindow *parent;
+ GdkWindow *child;
+ gint y;
+
+ /* This particular server apparently has a bug so that the test
+ * works but the actual code crashes it
+ */
+ if ((!strcmp (XServerVendor (GDK_DISPLAY()), "Sun Microsystems, Inc.")) &&
+ (VendorRelease (GDK_DISPLAY()) == 3400))
+ return FALSE;
+
+ attr.window_type = GDK_WINDOW_TEMP;
+ attr.wclass = GDK_INPUT_OUTPUT;
+ attr.x = 0;
+ attr.y = 0;
+ attr.width = 100;
+ attr.height = 100;
+ attr.event_mask = 0;
+
+ parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y);
+
+ attr.window_type = GDK_WINDOW_CHILD;
+ child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y);
+
+ gtk_layout_set_static_gravity (parent, TRUE);
+ gtk_layout_set_static_gravity (child, TRUE);
+
+ gdk_window_resize (parent, 100, 110);
+ gdk_window_move (parent, 0, -10);
+ gdk_window_move_resize (parent, 0, 0, 100, 100);
+
+ gdk_window_resize (parent, 100, 110);
+ gdk_window_move (parent, 0, -10);
+ gdk_window_move_resize (parent, 0, 0, 100, 100);
+
+ gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL);
+
+ gdk_window_destroy (parent);
+ gdk_window_destroy (child);
+
+ return (y == -20);
+}
+
diff --git a/gtk/gtklayout.h b/gtk/gtklayout.h
new file mode 100644
index 0000000000..3f60f0bc6a
--- /dev/null
+++ b/gtk/gtklayout.h
@@ -0,0 +1,104 @@
+/* Copyright Owen Taylor, 1998
+ *
+ * This file may be distributed under either the terms of the
+ * Netscape Public License, or the GNU Library General Public License
+ *
+ * Note: No GTK+ or Mozilla code should be added to this file.
+ * The coding style should be that of the the GTK core.
+ */
+
+#ifndef __GTK_LAYOUT_H
+#define __GTK_LAYOUT_H
+
+#include <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+#include <gtk/gtkadjustment.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GTK_LAYOUT(obj) GTK_CHECK_CAST (obj, gtk_layout_get_type (), GtkLayout)
+#define GTK_LAYOUT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_layout_get_type (), GtkLayoutClass)
+#define GTK_IS_LAYOUT(obj) GTK_CHECK_TYPE (obj, gtk_layout_get_type ())
+
+typedef struct _GtkLayout GtkLayout;
+typedef struct _GtkLayoutClass GtkLayoutClass;
+typedef struct _GtkLayoutChild GtkLayoutChild;
+
+struct _GtkLayoutChild {
+ GtkWidget *widget;
+ GdkWindow *window; /* For NO_WINDOW widgets */
+ gint x;
+ gint y;
+};
+
+struct _GtkLayout {
+ GtkContainer container;
+
+ GList *children;
+
+ guint width;
+ guint height;
+
+ guint xoffset;
+ guint yoffset;
+
+ GtkAdjustment *hadjustment;
+ GtkAdjustment *vadjustment;
+
+ GdkWindow *bin_window;
+
+ GdkVisibilityState visibility;
+ gulong configure_serial;
+ gint scroll_x;
+ gint scroll_y;
+
+ guint frozen : 1;
+};
+
+struct _GtkLayoutClass {
+ GtkContainerClass parent_class;
+
+ void (*scroll_adjustments) (GtkLayout *text,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
+};
+
+GtkWidget* gtk_layout_new (GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
+
+guint gtk_layout_get_type (void);
+void gtk_layout_put (GtkLayout *layout,
+ GtkWidget *widget,
+ gint x,
+ gint y);
+
+void gtk_layout_move (GtkLayout *layout,
+ GtkWidget *widget,
+ gint x,
+ gint y);
+
+void gtk_layout_set_size (GtkLayout *layout,
+ guint width,
+ guint height);
+
+/* These disable and enable moving and repainting the scrolling window of the GtkLayout,
+ * respectively. If you want to update the layout's offsets but do not want it to
+ * repaint itself, you should use these functions.
+ */
+void gtk_layout_freeze (GtkLayout *layout);
+void gtk_layout_thaw (GtkLayout *layout);
+
+GtkAdjustment* gtk_layout_get_hadjustment (GtkLayout *layout);
+GtkAdjustment* gtk_layout_get_vadjustment (GtkLayout *layout);
+void gtk_layout_set_hadjustment (GtkLayout *layout,
+ GtkAdjustment *adjustment);
+void gtk_layout_set_vadjustment (GtkLayout *layout,
+ GtkAdjustment *adjustment);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GTK_LAYOUT_H */
diff --git a/gtk/gtkplug.c b/gtk/gtkplug.c
new file mode 100644
index 0000000000..4e95bb1e96
--- /dev/null
+++ b/gtk/gtkplug.c
@@ -0,0 +1,409 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* By Owen Taylor <otaylor@gtk.org> 98/4/4 */
+
+#include "gdk/gdkx.h"
+#include "gdk/gdkkeysyms.h"
+#include "gtkplug.h"
+
+static void gtk_plug_class_init (GtkPlugClass *klass);
+static void gtk_plug_init (GtkPlug *plug);
+
+static void gtk_plug_realize (GtkWidget *widget);
+static gint gtk_plug_key_press_event (GtkWidget *widget,
+ GdkEventKey *event);
+static void gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event);
+static gint gtk_plug_focus_in_event (GtkWidget *widget, GdkEventFocus *event);
+static gint gtk_plug_focus_out_event (GtkWidget *widget, GdkEventFocus *event);
+static void gtk_plug_set_focus (GtkWindow *window,
+ GtkWidget *focus);
+
+/* From Tk */
+#define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
+
+guint
+gtk_plug_get_type ()
+{
+ static guint plug_type = 0;
+
+ if (!plug_type)
+ {
+ GtkTypeInfo plug_info =
+ {
+ "GtkPlug",
+ sizeof (GtkPlug),
+ sizeof (GtkPlugClass),
+ (GtkClassInitFunc) gtk_plug_class_init,
+ (GtkObjectInitFunc) gtk_plug_init,
+ (GtkArgSetFunc) NULL,
+ (GtkArgGetFunc) NULL
+ };
+
+ plug_type = gtk_type_unique (gtk_window_get_type (), &plug_info);
+ }
+
+ return plug_type;
+}
+
+static void
+gtk_plug_class_init (GtkPlugClass *class)
+{
+ GtkWidgetClass *widget_class;
+ GtkWindowClass *window_class;
+
+ widget_class = (GtkWidgetClass *)class;
+ window_class = (GtkWindowClass *)class;
+
+ widget_class->realize = gtk_plug_realize;
+ widget_class->key_press_event = gtk_plug_key_press_event;
+ widget_class->focus_in_event = gtk_plug_focus_in_event;
+ widget_class->focus_out_event = gtk_plug_focus_out_event;
+
+ window_class->set_focus = gtk_plug_set_focus;
+}
+
+static void
+gtk_plug_init (GtkPlug *plug)
+{
+ GtkWindow *window;
+
+ window = GTK_WINDOW (plug);
+
+ window->type = GTK_WINDOW_TOPLEVEL;
+ window->auto_shrink = TRUE;
+}
+void
+gtk_plug_construct (GtkPlug *plug, guint32 socket_id)
+{
+ plug->socket_window = gdk_window_lookup (socket_id);
+ plug->same_app = TRUE;
+
+ if (plug->socket_window == NULL)
+ {
+ plug->socket_window = gdk_window_foreign_new (socket_id);
+ plug->same_app = FALSE;
+ }
+}
+GtkWidget*
+gtk_plug_new (guint32 socket_id)
+{
+ GtkPlug *plug;
+
+ plug = GTK_PLUG (gtk_type_new (gtk_plug_get_type ()));
+ gtk_plug_construct (plug, socket_id);
+ return GTK_WIDGET (plug);
+}
+
+static void
+gtk_plug_realize (GtkWidget *widget)
+{
+ GtkWindow *window;
+ GtkPlug *plug;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_PLUG (widget));
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+ window = GTK_WINDOW (widget);
+ plug = GTK_PLUG (widget);
+
+ attributes.window_type = GDK_WINDOW_CHILD; /* XXX GDK_WINDOW_PLUG ? */
+ attributes.title = window->title;
+ attributes.wmclass_name = window->wmclass_name;
+ attributes.wmclass_class = window->wmclass_class;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+
+ /* this isn't right - we should match our parent's visual/colormap.
+ * though that will require handling "foreign" colormaps */
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.event_mask = gtk_widget_get_events (widget);
+ attributes.event_mask |= (GDK_EXPOSURE_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_FOCUS_CHANGE_MASK |
+ GDK_STRUCTURE_MASK);
+
+ attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
+ attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
+ attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
+
+ widget->window = gdk_window_new (plug->socket_window,
+ &attributes, attributes_mask);
+ ((GdkWindowPrivate *)widget->window)->window_type = GDK_WINDOW_TOPLEVEL;
+ gdk_window_set_user_data (widget->window, window);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+}
+
+static gint
+gtk_plug_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ GtkWindow *window;
+ GtkPlug *plug;
+ GtkDirectionType direction = 0;
+ gint return_val;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ window = GTK_WINDOW (widget);
+ plug = GTK_PLUG (widget);
+
+ if (!GTK_WIDGET_HAS_FOCUS(widget))
+ {
+ gtk_plug_forward_key_press (plug, event);
+ return TRUE;
+ }
+
+ return_val = FALSE;
+ if (window->focus_widget)
+ return_val = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
+
+#if 0
+ if (!return_val && gtk_window_check_accelerator (window, event->keyval, event->state))
+ return_val = TRUE;
+#endif
+
+ if (!return_val)
+ {
+ switch (event->keyval)
+ {
+ case GDK_space:
+ if (window->focus_widget)
+ {
+ gtk_widget_activate (window->focus_widget);
+ return_val = TRUE;
+ }
+ break;
+ case GDK_Return:
+ case GDK_KP_Enter:
+ if (window->default_widget)
+ {
+ gtk_widget_activate (window->default_widget);
+ return_val = TRUE;
+ }
+ else if (window->focus_widget)
+ {
+ gtk_widget_activate (window->focus_widget);
+ return_val = TRUE;
+ }
+ break;
+ case GDK_Up:
+ case GDK_Down:
+ case GDK_Left:
+ case GDK_Right:
+ case GDK_Tab:
+ switch (event->keyval)
+ {
+ case GDK_Up:
+ direction = GTK_DIR_UP;
+ break;
+ case GDK_Down:
+ direction = GTK_DIR_DOWN;
+ break;
+ case GDK_Left:
+ direction = GTK_DIR_LEFT;
+ break;
+ case GDK_Right:
+ direction = GTK_DIR_RIGHT;
+ break;
+ case GDK_Tab:
+ if (event->state & GDK_SHIFT_MASK)
+ direction = GTK_DIR_TAB_BACKWARD;
+ else
+ direction = GTK_DIR_TAB_FORWARD;
+ break;
+ default :
+ direction = GTK_DIR_UP; /* never reached, but makes compiler happy */
+ }
+
+ gtk_container_focus (GTK_CONTAINER (widget), direction);
+
+ if (!GTK_CONTAINER (window)->focus_child)
+ {
+ gtk_window_set_focus (GTK_WINDOW (widget), NULL);
+
+ XSetInputFocus (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (plug->socket_window),
+ RevertToParent, event->time);
+
+ gtk_plug_forward_key_press (plug, event);
+ }
+
+ return_val = TRUE;
+
+ break;
+ }
+ }
+
+ return return_val;
+}
+
+static void
+gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event)
+{
+ XEvent xevent;
+
+ xevent.xkey.type = KeyPress;
+ xevent.xkey.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
+ xevent.xkey.window = GDK_WINDOW_XWINDOW (plug->socket_window);
+ xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
+ xevent.xkey.time = event->time;
+ /* FIXME, the following might cause big problems for
+ * non-GTK apps */
+ xevent.xkey.x = 0;
+ xevent.xkey.y = 0;
+ xevent.xkey.x_root = 0;
+ xevent.xkey.y_root = 0;
+ xevent.xkey.state = event->state;
+ xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(),
+ event->keyval);
+ xevent.xkey.same_screen = TRUE; /* FIXME ? */
+
+ XSendEvent (gdk_display,
+ GDK_WINDOW_XWINDOW (plug->socket_window),
+ False, NoEventMask, &xevent);
+}
+
+/* Copied from Window, Ughh */
+
+static gint
+gtk_plug_focus_in_event (GtkWidget *widget,
+ GdkEventFocus *event)
+{
+ GtkWindow *window;
+ GdkEventFocus fevent;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ /* It appears spurious focus in events can occur when
+ * the window is hidden. So we'll just check to see if
+ * the window is visible before actually handling the
+ * event
+ */
+ if (GTK_WIDGET_VISIBLE (widget))
+ {
+ GTK_OBJECT_SET_FLAGS (widget, GTK_HAS_FOCUS);
+ window = GTK_WINDOW (widget);
+ if (window->focus_widget && !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
+ {
+ fevent.type = GDK_FOCUS_CHANGE;
+ fevent.window = window->focus_widget->window;
+ fevent.in = TRUE;
+
+ gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
+ }
+ }
+
+ return FALSE;
+}
+
+static gint
+gtk_plug_focus_out_event (GtkWidget *widget,
+ GdkEventFocus *event)
+{
+ GtkWindow *window;
+ GdkEventFocus fevent;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ GTK_OBJECT_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+
+ window = GTK_WINDOW (widget);
+
+ if (window->focus_widget && GTK_WIDGET_HAS_FOCUS (window->focus_widget))
+ {
+ fevent.type = GDK_FOCUS_CHANGE;
+ fevent.window = window->focus_widget->window;
+ fevent.in = FALSE;
+
+ gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_plug_set_focus (GtkWindow *window,
+ GtkWidget *focus)
+{
+ GtkPlug *plug;
+ GdkEventFocus event;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (GTK_IS_PLUG (window));
+
+ plug = GTK_PLUG (window);
+
+ if (focus && !GTK_WIDGET_CAN_FOCUS (focus))
+ return;
+
+ if (window->focus_widget != focus)
+ {
+ if (window->focus_widget)
+ {
+ event.type = GDK_FOCUS_CHANGE;
+ event.window = window->focus_widget->window;
+ event.in = FALSE;
+
+ gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
+ }
+
+ window->focus_widget = focus;
+
+ if (window->focus_widget)
+ {
+ event.type = GDK_FOCUS_CHANGE;
+ event.window = window->focus_widget->window;
+ event.in = TRUE;
+
+ gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
+ }
+ }
+
+ /* Ask for focus from parent */
+
+ if (focus && !GTK_WIDGET_HAS_FOCUS(window))
+ {
+ XEvent xevent;
+
+ xevent.xfocus.type = FocusIn;
+ xevent.xfocus.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
+ xevent.xfocus.window = GDK_WINDOW_XWINDOW (plug->socket_window);
+ xevent.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
+ xevent.xfocus.detail = FALSE; /* Don't force */
+
+ XSendEvent (gdk_display,
+ GDK_WINDOW_XWINDOW (plug->socket_window),
+ False, NoEventMask, &xevent);
+ }
+}
diff --git a/gtk/gtkplug.h b/gtk/gtkplug.h
new file mode 100644
index 0000000000..32d9836119
--- /dev/null
+++ b/gtk/gtkplug.h
@@ -0,0 +1,65 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __GTK_PLUG_H__
+#define __GTK_PLUG_H__
+
+
+#include <gdk/gdk.h>
+#include <gtk/gtkwindow.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GTK_PLUG(obj) GTK_CHECK_CAST (obj, gtk_plug_get_type (), GtkPlug)
+#define GTK_PLUG_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_plug_get_type (), GtkPlugClass)
+#define GTK_IS_PLUG(obj) GTK_CHECK_TYPE (obj, gtk_plug_get_type ())
+
+
+typedef struct _GtkPlug GtkPlug;
+typedef struct _GtkPlugClass GtkPlugClass;
+typedef struct _GtkPlugButton GtkPlugButton;
+
+
+struct _GtkPlug
+{
+ GtkWindow window;
+
+ GdkWindow *socket_window;
+ gint same_app;
+};
+
+struct _GtkPlugClass
+{
+ GtkWindowClass parent_class;
+};
+
+
+guint gtk_plug_get_type (void);
+void gtk_plug_construct (GtkPlug *plug, guint32 socket_id);
+GtkWidget* gtk_plug_new (guint32 socket_id);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GTK_PLUG_H__ */
diff --git a/gtk/gtksocket.c b/gtk/gtksocket.c
new file mode 100644
index 0000000000..dcf905c59f
--- /dev/null
+++ b/gtk/gtksocket.c
@@ -0,0 +1,688 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* By Owen Taylor <otaylor@gtk.org> 98/4/4 */
+
+#include "gdk/gdkx.h"
+#include "gdk/gdkkeysyms.h"
+#include "gtkwindow.h"
+#include "gtksignal.h"
+#include "gtksocket.h"
+#include "gtkdnd.h"
+
+/* Forward declararations */
+
+static void gtk_socket_class_init (GtkSocketClass *klass);
+static void gtk_socket_init (GtkSocket *socket);
+static void gtk_socket_realize (GtkWidget *widget);
+static void gtk_socket_unrealize (GtkWidget *widget);
+static void gtk_socket_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+static void gtk_socket_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static gint gtk_socket_focus_in_event (GtkWidget *widget,
+ GdkEventFocus *event);
+static void gtk_socket_claim_focus (GtkSocket *socket);
+static gint gtk_socket_focus_out_event (GtkWidget *widget,
+ GdkEventFocus *event);
+static void gtk_socket_send_configure_event (GtkSocket *socket);
+static gint gtk_socket_focus (GtkContainer *container,
+ GtkDirectionType direction);
+static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data);
+
+#ifdef DEBUG_PLUGSOCKET
+#define DPRINTF(arg) g_print arg
+#else
+#define DPRINTF(arg)
+#endif
+
+/* From Tk */
+#define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
+
+/* Local data */
+
+static GtkWidgetClass *parent_class = NULL;
+
+guint
+gtk_socket_get_type ()
+{
+ static guint socket_type = 0;
+
+ if (!socket_type)
+ {
+ GtkTypeInfo socket_info =
+ {
+ "GtkSocket",
+ sizeof (GtkSocket),
+ sizeof (GtkSocketClass),
+ (GtkClassInitFunc) gtk_socket_class_init,
+ (GtkObjectInitFunc) gtk_socket_init,
+ (GtkArgSetFunc) NULL,
+ (GtkArgGetFunc) NULL
+ };
+
+ socket_type = gtk_type_unique (gtk_container_get_type (), &socket_info);
+ }
+
+ return socket_type;
+}
+
+static void
+gtk_socket_class_init (GtkSocketClass *class)
+{
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkContainerClass *container_class;
+
+ object_class = (GtkObjectClass*) class;
+ widget_class = (GtkWidgetClass*) class;
+ container_class = (GtkContainerClass*) class;
+
+ parent_class = gtk_type_class (gtk_widget_get_type ());
+
+ widget_class->realize = gtk_socket_realize;
+ widget_class->unrealize = gtk_socket_unrealize;
+ widget_class->size_request = gtk_socket_size_request;
+ widget_class->size_allocate = gtk_socket_size_allocate;
+ widget_class->focus_in_event = gtk_socket_focus_in_event;
+ widget_class->focus_out_event = gtk_socket_focus_out_event;
+
+ container_class->focus = gtk_socket_focus;
+}
+
+static void
+gtk_socket_init (GtkSocket *socket)
+{
+ socket->request_width = 0;
+ socket->request_height = 0;
+ socket->current_width = 0;
+ socket->current_height = 0;
+
+ socket->plug_window = NULL;
+ socket->same_app = FALSE;
+ socket->focus_in = FALSE;
+ socket->have_size = FALSE;
+ socket->need_map = FALSE;
+}
+
+GtkWidget*
+gtk_socket_new ()
+{
+ GtkSocket *socket;
+
+ socket = gtk_type_new (gtk_socket_get_type ());
+
+ return GTK_WIDGET (socket);
+}
+
+void
+gtk_socket_steal (GtkSocket *socket, guint32 id)
+{
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (socket);
+
+ socket->plug_window = gdk_window_lookup (id);
+
+ if (socket->plug_window && socket->plug_window->user_data)
+ {
+ GtkWidget *child_widget = GTK_WIDGET (socket->plug_window->user_data);
+
+ g_warning("Stealing from same app not yet implemented");
+
+ socket->same_app = TRUE;
+ }
+ else
+ {
+ socket->plug_window = gdk_window_foreign_new (id);
+ socket->same_app = FALSE;
+ socket->have_size = FALSE;
+
+ XSelectInput (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW(socket->plug_window),
+ StructureNotifyMask | PropertyChangeMask);
+
+ gtk_widget_queue_resize (widget);
+ }
+
+ gdk_window_hide (socket->plug_window);
+ gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
+ socket->need_map = TRUE;
+}
+
+static void
+gtk_socket_realize (GtkWidget *widget)
+{
+ GtkSocket *socket;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+ XWindowAttributes xattrs;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_SOCKET (widget));
+
+ socket = GTK_SOCKET (widget);
+ GTK_WIDGET_SET_FLAGS (widget, 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_FOCUS_CHANGE_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, socket);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+
+ XGetWindowAttributes (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (widget->window),
+ &xattrs);
+
+ XSelectInput (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW(widget->window),
+ xattrs.your_event_mask |
+ SubstructureNotifyMask | SubstructureRedirectMask);
+
+ gdk_window_add_filter (widget->window, gtk_socket_filter_func, widget);
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ /* We sync here so that we make sure that if the XID for
+ * our window is passed to another application, SubstructureRedirectMask
+ * will be set by the time the other app creates its window.
+ */
+ gdk_flush();
+}
+
+static void
+gtk_socket_unrealize (GtkWidget *widget)
+{
+ GtkSocket *socket;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_SOCKET (widget));
+
+ socket = GTK_SOCKET (widget);
+
+ if (socket->plug_window)
+ {
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
+ if (toplevel && GTK_IS_WINDOW (toplevel))
+ gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel),
+ GDK_WINDOW_XWINDOW (socket->plug_window));
+ }
+
+ if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+ (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void
+gtk_socket_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GtkSocket *socket;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_SOCKET (widget));
+ g_return_if_fail (requisition != NULL);
+
+ socket = GTK_SOCKET (widget);
+
+ if (!socket->have_size && socket->plug_window)
+ {
+ XSizeHints hints;
+ long supplied;
+
+ if (XGetWMNormalHints (GDK_DISPLAY(),
+ GDK_WINDOW_XWINDOW (socket->plug_window),
+ &hints, &supplied))
+ {
+ /* This is obsolete, according the X docs, but many programs
+ * still use it */
+ if (hints.flags & (PSize | USSize))
+ {
+ socket->request_width = hints.width;
+ socket->request_height = hints.height;
+ }
+ else if (hints.flags & PMinSize)
+ {
+ socket->request_width = hints.min_width;
+ socket->request_height = hints.min_height;
+ }
+ else if (hints.flags & PBaseSize)
+ {
+ socket->request_width = hints.base_width;
+ socket->request_height = hints.base_height;
+ }
+ }
+ socket->have_size = TRUE; /* don't check again? */
+ }
+
+ requisition->width = socket->request_width;
+ requisition->height = socket->request_height;
+}
+
+static void
+gtk_socket_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkSocket *socket;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_SOCKET (widget));
+ g_return_if_fail (allocation != NULL);
+
+ socket = GTK_SOCKET (widget);
+
+ widget->allocation = *allocation;
+ if (GTK_WIDGET_REALIZED (widget))
+ {
+ gdk_window_move_resize (widget->window,
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
+
+ if (socket->plug_window)
+ {
+ if (!socket->need_map &&
+ (allocation->width == socket->current_width) &&
+ (allocation->height == socket->current_height))
+ {
+ gtk_socket_send_configure_event (socket);
+ DPRINTF(( "No change: %d %d\n",
+ allocation->width, allocation->height));
+ }
+ else
+ {
+ gdk_window_move_resize (socket->plug_window,
+ 0, 0,
+ allocation->width, allocation->height);
+ DPRINTF(("configuring: %d %d\n",
+ allocation->width, allocation->height));
+ socket->current_width = allocation->width;
+ socket->current_height = allocation->height;
+ }
+
+ if (socket->need_map)
+ {
+ gdk_window_show (socket->plug_window);
+ socket->need_map = FALSE;
+ }
+
+ }
+ }
+}
+
+static gint
+gtk_socket_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
+{
+ GtkSocket *socket;
+ g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
+ socket = GTK_SOCKET (widget);
+
+ DPRINTF (( "Got focus\n"));
+
+ if (socket->focus_in && socket->plug_window)
+ XSetInputFocus (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (socket->plug_window),
+ RevertToParent, GDK_CURRENT_TIME);
+
+ return TRUE;
+}
+
+static gint
+gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
+{
+ GtkWidget *toplevel;
+ GtkSocket *socket;
+
+ g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
+ socket = GTK_SOCKET (widget);
+
+ toplevel = gtk_widget_get_ancestor (widget, gtk_window_get_type());
+
+ if (toplevel)
+ {
+ XSetInputFocus (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (toplevel->window),
+ RevertToParent, CurrentTime); /* FIXME? */
+ }
+
+ socket->focus_in = FALSE;
+
+ return TRUE;
+}
+
+static void
+gtk_socket_claim_focus (GtkSocket *socket)
+{
+
+ socket->focus_in = TRUE;
+
+ /* Oh, the trickery... */
+
+ GTK_WIDGET_SET_FLAGS (socket, GTK_CAN_FOCUS);
+ gtk_widget_grab_focus (GTK_WIDGET (socket));
+ GTK_WIDGET_UNSET_FLAGS (socket, GTK_CAN_FOCUS);
+
+ /* FIXME: we might grab the focus even if we don't have
+ * it as an app... (and see _focus_in ()) */
+ if (socket->plug_window)
+ XSetInputFocus (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (socket->plug_window),
+ RevertToParent, GDK_CURRENT_TIME);
+}
+
+static gint
+gtk_socket_focus (GtkContainer *container, GtkDirectionType direction)
+{
+ GtkSocket *socket;
+
+ g_return_val_if_fail (GTK_IS_SOCKET (container), FALSE);
+
+ socket = GTK_SOCKET (container);
+
+ if (!socket->focus_in && socket->plug_window)
+ {
+ XEvent xevent;
+
+ gtk_socket_claim_focus (socket);
+
+ xevent.xkey.type = KeyPress;
+ xevent.xkey.display = GDK_DISPLAY ();
+ xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
+ xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
+ xevent.xkey.time = GDK_CURRENT_TIME; /* FIXME */
+ /* FIXME, the following might cause big problems for
+ * non-GTK apps */
+ xevent.xkey.x = 0;
+ xevent.xkey.y = 0;
+ xevent.xkey.x_root = 0;
+ xevent.xkey.y_root = 0;
+ xevent.xkey.state = 0;
+ xevent.xkey.same_screen = TRUE; /* FIXME ? */
+
+ switch (direction)
+ {
+ case GTK_DIR_UP:
+ xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Up);
+ break;
+ case GTK_DIR_DOWN:
+ xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Down);
+ break;
+ case GTK_DIR_LEFT:
+ xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Left);
+ break;
+ case GTK_DIR_RIGHT:
+ xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Right);
+ break;
+ case GTK_DIR_TAB_FORWARD:
+ xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
+ break;
+ case GTK_DIR_TAB_BACKWARD:
+ xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
+ xevent.xkey.state = ShiftMask;
+ break;
+ }
+
+
+ XSendEvent (gdk_display,
+ GDK_WINDOW_XWINDOW (socket->plug_window),
+ False, NoEventMask, &xevent);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static void
+gtk_socket_send_configure_event (GtkSocket *socket)
+{
+ XEvent event;
+
+ g_return_if_fail (socket->plug_window != NULL);
+
+ event.xconfigure.type = ConfigureNotify;
+ event.xconfigure.display = gdk_display;
+
+ event.xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
+ event.xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
+
+ event.xconfigure.x = 0;
+ event.xconfigure.y = 0;
+ event.xconfigure.width = GTK_WIDGET(socket)->allocation.width;
+ event.xconfigure.height = GTK_WIDGET(socket)->allocation.height;
+
+ event.xconfigure.border_width = 0;
+ event.xconfigure.above = None;
+ event.xconfigure.override_redirect = False;
+
+ XSendEvent (gdk_display,
+ GDK_WINDOW_XWINDOW (socket->plug_window),
+ False, NoEventMask, &event);
+}
+
+static void
+gtk_socket_add_window (GtkSocket *socket, guint32 xid)
+{
+ socket->plug_window = gdk_window_lookup (xid);
+ socket->same_app = TRUE;
+
+ if (!socket->plug_window)
+ {
+ GtkWidget *toplevel;
+ GdkDragProtocol protocol;
+
+ socket->plug_window = gdk_window_foreign_new (xid);
+ socket->same_app = FALSE;
+
+ XSelectInput (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW(socket->plug_window),
+ StructureNotifyMask | PropertyChangeMask);
+
+ if (gdk_drag_get_protocol (xid, &protocol))
+ gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window,
+ protocol, TRUE);
+
+ gdk_window_add_filter (socket->plug_window,
+ gtk_socket_filter_func, socket);
+
+ /* Add a pointer to the socket on our toplevel window */
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
+ if (toplevel && GTK_IS_WINDOW (toplevel))
+ {
+ gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
+ }
+ }
+}
+
+static GdkFilterReturn
+gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
+{
+ GtkSocket *socket;
+ GtkWidget *widget;
+ XEvent *xevent;
+
+ GdkFilterReturn return_val;
+
+ socket = GTK_SOCKET (data);
+ widget = GTK_WIDGET (socket);
+ xevent = (XEvent *)gdk_xevent;
+
+ return_val = GDK_FILTER_CONTINUE;
+
+ switch (xevent->type)
+ {
+ case CreateNotify:
+ {
+ XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
+
+ if (!socket->plug_window)
+ {
+ g_print("Here!\n");
+
+ gtk_socket_add_window (socket, xcwe->window);
+
+ gdk_window_move_resize(socket->plug_window,
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+
+ socket->request_width = xcwe->width;
+ socket->request_height = xcwe->height;
+ socket->have_size = TRUE;
+
+ DPRINTF(("Window created with size: %d %d\n",
+ socket->request_width,
+ socket->request_height));
+
+ gtk_widget_queue_resize (widget);
+ }
+
+ return_val = GDK_FILTER_REMOVE;
+
+ break;
+ }
+
+ case ConfigureRequest:
+ {
+ XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
+
+ if (!socket->plug_window)
+ gtk_socket_add_window (socket, xcre->window);
+
+ if (xcre->window == GDK_WINDOW_XWINDOW (socket->plug_window))
+ {
+ if (xcre->value_mask & (CWWidth | CWHeight))
+ {
+ socket->request_width = xcre->width;
+ socket->request_height = xcre->height;
+ socket->have_size = TRUE;
+
+ DPRINTF(("Configure request: %d %d\n",
+ socket->request_width,
+ socket->request_height));
+
+ gtk_widget_queue_resize (widget);
+ }
+ else if (xcre->value_mask & (CWX | CWY))
+ {
+ gtk_socket_send_configure_event (socket);
+ }
+ /* Ignore stacking requests. */
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
+ }
+
+ case DestroyNotify:
+ {
+ XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
+
+ if (socket->plug_window &&
+ (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
+ {
+ GtkWidget *toplevel;
+
+ DPRINTF(("Destroy Notify\n"));
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
+ if (toplevel && GTK_IS_WINDOW (toplevel))
+ gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel), xdwe->window);
+ gtk_widget_destroy (widget);
+ gdk_window_destroy_notify (socket->plug_window);
+
+ socket->plug_window = NULL;
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
+ }
+
+ case FocusIn:
+ if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
+ {
+ gtk_socket_claim_focus (socket);
+ }
+ else if (xevent->xfocus.detail == NotifyInferior)
+ {
+#if 0
+ GtkWidget *toplevel;
+ toplevel = gtk_widget_get_ancestor (widget, gtk_window_get_type());
+
+ if (toplevel)
+ {
+ XSetInputFocus (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (toplevel->window),
+ RevertToParent, CurrentTime); /* FIXME? */
+ }
+#endif
+ }
+ return_val = GDK_FILTER_REMOVE;
+ break;
+ case FocusOut:
+ return_val = GDK_FILTER_REMOVE;
+ break;
+ case MapRequest:
+ if (!socket->plug_window)
+ gtk_socket_add_window (socket, xevent->xmaprequest.window);
+
+ if (xevent->xmaprequest.window ==
+ GDK_WINDOW_XWINDOW (socket->plug_window))
+ {
+ DPRINTF(("Map Request\n"));
+
+ gdk_window_show (socket->plug_window);
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
+ case PropertyNotify:
+ if (xevent->xproperty.window ==
+ GDK_WINDOW_XWINDOW (socket->plug_window))
+ {
+ GdkDragProtocol protocol;
+
+ if ((xevent->xproperty.atom == gdk_atom_intern ("XdndAware", FALSE)) ||
+ (xevent->xproperty.atom == gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE)))
+ {
+ if (gdk_drag_get_protocol (xevent->xproperty.window, &protocol))
+ gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
+ socket->plug_window,
+ protocol, TRUE);
+ }
+ return_val = GDK_FILTER_REMOVE;
+ }
+ }
+
+ return return_val;
+}
diff --git a/gtk/gtksocket.h b/gtk/gtksocket.h
new file mode 100644
index 0000000000..c1c9d3a325
--- /dev/null
+++ b/gtk/gtksocket.h
@@ -0,0 +1,68 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __GTK_SOCKET_H__
+#define __GTK_SOCKET_H__
+
+#include <gtk/gtkcontainer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GTK_SOCKET(obj) GTK_CHECK_CAST (obj, gtk_socket_get_type (), GtkSocket)
+#define GTK_SOCKET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_socket_get_type (), GtkSocketClass)
+#define GTK_IS_SOCKET(obj) GTK_CHECK_TYPE (obj, gtk_socket_get_type ())
+
+
+typedef struct _GtkSocket GtkSocket;
+typedef struct _GtkSocketClass GtkSocketClass;
+
+struct _GtkSocket
+{
+ GtkContainer container;
+
+ guint16 request_width;
+ guint16 request_height;
+ guint16 current_width;
+ guint16 current_height;
+
+ GdkWindow *plug_window;
+ guint same_app : 1;
+ guint focus_in : 1;
+ guint have_size : 1;
+ guint need_map : 1;
+};
+
+struct _GtkSocketClass
+{
+ GtkContainerClass parent_class;
+};
+
+
+GtkWidget* gtk_socket_new (void);
+guint gtk_socket_get_type (void );
+void gtk_socket_steal (GtkSocket *socket,
+ guint32 wid);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GTK_SOCKET_H__ */
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 9f7c65b5b2..c8accc44e9 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -464,6 +464,58 @@ gtk_window_set_modal (GtkWindow *window, gboolean modal)
window->modal = modal;
}
+void
+gtk_window_add_embedded_xid (GtkWindow *window, guint xid)
+{
+ GList *embedded_windows;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ g_print ("add %#x\n", xid);
+
+ embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
+ if (embedded_windows)
+ gtk_object_remove_no_notify_by_id (GTK_OBJECT (window),
+ g_quark_from_static_string ("gtk-embedded"));
+ embedded_windows = g_list_prepend (embedded_windows,
+ GUINT_TO_POINTER (xid));
+
+ gtk_object_set_data_full (GTK_OBJECT (window), "gtk-embedded",
+ embedded_windows,
+ embedded_windows ?
+ (GtkDestroyNotify) g_list_free : NULL);
+}
+
+void
+gtk_window_remove_embedded_xid (GtkWindow *window, guint xid)
+{
+ GList *embedded_windows;
+ GList *node;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ g_print ("remove %#x\n", xid);
+
+ embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
+ if (embedded_windows)
+ gtk_object_remove_no_notify_by_id (GTK_OBJECT (window),
+ g_quark_from_static_string ("gtk-embedded"));
+
+ node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid));
+ if (node)
+ {
+ embedded_windows = g_list_remove_link (embedded_windows, node);
+ g_list_free_1 (node);
+ }
+
+ gtk_object_set_data_full (GTK_OBJECT (window),
+ "gtk-embedded", embedded_windows,
+ embedded_windows ?
+ (GtkDestroyNotify) g_list_free : NULL);
+}
+
static void
gtk_window_shutdown (GtkObject *object)
{
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index 33dea2e753..7f0b616d39 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -100,6 +100,9 @@ gint gtk_window_activate_default (GtkWindow *window);
void gtk_window_set_modal (GtkWindow *window,
gboolean modal);
+void gtk_window_remove_embedded_xid (GtkWindow *window, guint xid);
+void gtk_window_add_embedded_xid (GtkWindow *window, guint xid);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/gtk/testgtk.c b/gtk/testgtk.c
index 4b550881c1..ec5cfdf5d5 100644
--- a/gtk/testgtk.c
+++ b/gtk/testgtk.c
@@ -7940,6 +7940,94 @@ create_mainloop (void)
gtk_widget_destroy (window);
}
+gint
+layout_expose_handler (GtkWidget *widget, GdkEventExpose *event)
+{
+ GtkLayout *layout;
+
+ gint i,j;
+ gint imin, imax, jmin, jmax;
+
+ layout = GTK_LAYOUT (widget);
+
+ imin = (layout->xoffset + event->area.x) / 10;
+ imax = (layout->xoffset + event->area.x + event->area.width + 9) / 10;
+
+ jmin = (layout->yoffset + event->area.y) / 10;
+ jmax = (layout->yoffset + event->area.y + event->area.height + 9) / 10;
+
+ gdk_window_clear_area (widget->window,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ for (i=imin; i<imax; i++)
+ for (j=jmin; j<jmax; j++)
+ if ((i+j) % 2)
+ gdk_draw_rectangle (layout->bin_window,
+ widget->style->black_gc,
+ TRUE,
+ 10*i - layout->xoffset, 10*j - layout->yoffset,
+ 1+i%10, 1+j%10);
+
+ return TRUE;
+}
+
+void create_layout (void)
+{
+ static GtkWidget *window = NULL;
+ GtkWidget *layout;
+ GtkWidget *scrolledwindow;
+ GtkWidget *button;
+
+ if (!window)
+ {
+ gchar buf[16];
+
+ gint i, j;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &window);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Layout");
+ gtk_widget_set_usize (window, 200, 200);
+
+ scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwindow);
+
+ gtk_container_add (GTK_CONTAINER (window), scrolledwindow);
+
+ layout = gtk_layout_new (NULL, NULL);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow), layout);
+
+ gtk_widget_set_events (layout, GDK_EXPOSURE_MASK);
+ gtk_signal_connect (GTK_OBJECT (layout), "expose_event",
+ GTK_SIGNAL_FUNC (layout_expose_handler), NULL);
+
+ gtk_layout_set_size (GTK_LAYOUT (layout), 1600, 1600);
+ gtk_widget_show (layout);
+
+ for (i=0 ; i < 16 ; i++)
+ for (j=0 ; j < 16 ; j++)
+ {
+ sprintf(buf, "Button %d, %d", i, j);
+ if ((i + j) % 2)
+ button = gtk_button_new_with_label (buf);
+ else
+ button = gtk_label_new (buf);
+ gtk_layout_put (GTK_LAYOUT (layout), button,
+ j*100, i*100);
+ gtk_widget_show (button);
+ }
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show (window);
+ else
+ gtk_widget_destroy (window);
+}
+
/*
* Main Window and Exit
*/
@@ -7974,6 +8062,7 @@ create_main_window (void)
{ "gamma curve", create_gamma_curve },
{ "handle box", create_handle_box },
{ "item factory", create_item_factory },
+ { "layout", create_layout },
{ "list", create_list },
{ "menus", create_menus },
{ "modal window", create_modal_window },
diff --git a/tests/testgtk.c b/tests/testgtk.c
index 4b550881c1..ec5cfdf5d5 100644
--- a/tests/testgtk.c
+++ b/tests/testgtk.c
@@ -7940,6 +7940,94 @@ create_mainloop (void)
gtk_widget_destroy (window);
}
+gint
+layout_expose_handler (GtkWidget *widget, GdkEventExpose *event)
+{
+ GtkLayout *layout;
+
+ gint i,j;
+ gint imin, imax, jmin, jmax;
+
+ layout = GTK_LAYOUT (widget);
+
+ imin = (layout->xoffset + event->area.x) / 10;
+ imax = (layout->xoffset + event->area.x + event->area.width + 9) / 10;
+
+ jmin = (layout->yoffset + event->area.y) / 10;
+ jmax = (layout->yoffset + event->area.y + event->area.height + 9) / 10;
+
+ gdk_window_clear_area (widget->window,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ for (i=imin; i<imax; i++)
+ for (j=jmin; j<jmax; j++)
+ if ((i+j) % 2)
+ gdk_draw_rectangle (layout->bin_window,
+ widget->style->black_gc,
+ TRUE,
+ 10*i - layout->xoffset, 10*j - layout->yoffset,
+ 1+i%10, 1+j%10);
+
+ return TRUE;
+}
+
+void create_layout (void)
+{
+ static GtkWidget *window = NULL;
+ GtkWidget *layout;
+ GtkWidget *scrolledwindow;
+ GtkWidget *button;
+
+ if (!window)
+ {
+ gchar buf[16];
+
+ gint i, j;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &window);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Layout");
+ gtk_widget_set_usize (window, 200, 200);
+
+ scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwindow);
+
+ gtk_container_add (GTK_CONTAINER (window), scrolledwindow);
+
+ layout = gtk_layout_new (NULL, NULL);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow), layout);
+
+ gtk_widget_set_events (layout, GDK_EXPOSURE_MASK);
+ gtk_signal_connect (GTK_OBJECT (layout), "expose_event",
+ GTK_SIGNAL_FUNC (layout_expose_handler), NULL);
+
+ gtk_layout_set_size (GTK_LAYOUT (layout), 1600, 1600);
+ gtk_widget_show (layout);
+
+ for (i=0 ; i < 16 ; i++)
+ for (j=0 ; j < 16 ; j++)
+ {
+ sprintf(buf, "Button %d, %d", i, j);
+ if ((i + j) % 2)
+ button = gtk_button_new_with_label (buf);
+ else
+ button = gtk_label_new (buf);
+ gtk_layout_put (GTK_LAYOUT (layout), button,
+ j*100, i*100);
+ gtk_widget_show (button);
+ }
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show (window);
+ else
+ gtk_widget_destroy (window);
+}
+
/*
* Main Window and Exit
*/
@@ -7974,6 +8062,7 @@ create_main_window (void)
{ "gamma curve", create_gamma_curve },
{ "handle box", create_handle_box },
{ "item factory", create_item_factory },
+ { "layout", create_layout },
{ "list", create_list },
{ "menus", create_menus },
{ "modal window", create_modal_window },