summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>1998-11-24 04:45:29 +0000
committerOwen Taylor <otaylor@src.gnome.org>1998-11-24 04:45:29 +0000
commitee1d43929c3395fabd43e6b1d6a718363cbe198e (patch)
treef605372598f5668f17924ac8fbc8aa5ae8d38bbd /gtk
parent42faec1736c32cfbe1c44ac0ca0d81445c32fd0d (diff)
downloadgtk+-ee1d43929c3395fabd43e6b1d6a718363cbe198e.tar.gz
Added layout widget for scrolling arbitrarily big areas. Added plug/socket
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.
Diffstat (limited to 'gtk')
-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
11 files changed, 2694 insertions, 0 deletions
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 },