diff options
-rw-r--r-- | ChangeLog | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 48 | ||||
-rw-r--r-- | gdk/gdkwindow.c | 2 | ||||
-rw-r--r-- | gdk/x11/gdkinput-x11.c | 2 | ||||
-rw-r--r-- | gdk/x11/gdkinput.c | 14 | ||||
-rw-r--r-- | gtk/gtkentry.c | 12 | ||||
-rw-r--r-- | gtk/gtkmain.c | 9 | ||||
-rw-r--r-- | gtk/gtkplug.c | 276 | ||||
-rw-r--r-- | gtk/gtkplug.h | 6 | ||||
-rw-r--r-- | gtk/gtksocket.c | 520 | ||||
-rw-r--r-- | gtk/gtksocket.h | 4 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 17 | ||||
-rw-r--r-- | gtk/xembed.h | 3 | ||||
-rw-r--r-- | tests/Makefile.am | 8 | ||||
-rw-r--r-- | tests/testsocket.c | 134 | ||||
-rw-r--r-- | tests/testsocket_child.c | 84 |
21 files changed, 1140 insertions, 287 deletions
@@ -1,3 +1,51 @@ +Mon Jul 2 16:53:25 2001 Owen Taylor <otaylor@redhat.com> + + * gtk/xembed.h gtk/gtkplug.c gtk/gtksocket.c: For + XEMBED embedding add a _XEMBED_INFO property to the + client with version number and a "mapped" flags. + Use the mapped flag instead of the racy MapRequestEvent + + * gtk/gtksocket.c: Clean up the gtk_socket_steal() + code to reliably set things (when the child is a passive + embedder participating in the XEMBED protocol) intead + of just being a hack for embedding non-participating + programs. Fix various bugs and race conditions. + + * gtk/gtksocket.[ch] gtk/gtkplug.[ch]: Make local embedding + work by simply making the GtkSocket the gtk parent + of the GtkPlug. Set a flag in this case and make + the GtkPlug work like a normal container by overriding + methods such as check_resize and "chaining past" GtkWindow + to GtkBin. + + * gtk/gtkentry.c (gtk_entry_real_activate) + gtk/gtkmain.c (gtk_propagate_event): + Eliminate use of gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW). + + * gtk/gtkwidget.c (gtk_widget_get_toplevel, + gtk_widget_get_ancestor): + Explain why gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) + might not give the expected result and recommend + an alternative. + + * tests/testsocket.c tests/testsocket_child.c + tests/testsocket_common.c tests/Makefile.am: Extended + to test different type of adding plugs to sockets + (local,active,passive), and to test mapping/unmapping + the plug. + + * gdk/gdkwindow.c (_gdk_window_destroy_hierarchy): Don't + mark the window as destroyed until after we + called _gdk_windowing_window_destroy(). + (_gdk_windowing_window_destroy() may use GDK functions + on the window.) + + * gdk/x11/gdkinput.c: Remove the check for finalization - + devices can be finalized under some circumnstances. + + * gdk/x11/gdkinput-x11.c (gdk_input_device_new): Fix + small problem with GDK_TYPE_DEVICE. + 2001-07-02 Havoc Pennington <hp@pobox.com> * gdk/x11/gdkwindow-x11.c (gdk_wmspec_change_state): fix to diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index aadd7bd5b3..3f9308e8dd 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,51 @@ +Mon Jul 2 16:53:25 2001 Owen Taylor <otaylor@redhat.com> + + * gtk/xembed.h gtk/gtkplug.c gtk/gtksocket.c: For + XEMBED embedding add a _XEMBED_INFO property to the + client with version number and a "mapped" flags. + Use the mapped flag instead of the racy MapRequestEvent + + * gtk/gtksocket.c: Clean up the gtk_socket_steal() + code to reliably set things (when the child is a passive + embedder participating in the XEMBED protocol) intead + of just being a hack for embedding non-participating + programs. Fix various bugs and race conditions. + + * gtk/gtksocket.[ch] gtk/gtkplug.[ch]: Make local embedding + work by simply making the GtkSocket the gtk parent + of the GtkPlug. Set a flag in this case and make + the GtkPlug work like a normal container by overriding + methods such as check_resize and "chaining past" GtkWindow + to GtkBin. + + * gtk/gtkentry.c (gtk_entry_real_activate) + gtk/gtkmain.c (gtk_propagate_event): + Eliminate use of gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW). + + * gtk/gtkwidget.c (gtk_widget_get_toplevel, + gtk_widget_get_ancestor): + Explain why gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) + might not give the expected result and recommend + an alternative. + + * tests/testsocket.c tests/testsocket_child.c + tests/testsocket_common.c tests/Makefile.am: Extended + to test different type of adding plugs to sockets + (local,active,passive), and to test mapping/unmapping + the plug. + + * gdk/gdkwindow.c (_gdk_window_destroy_hierarchy): Don't + mark the window as destroyed until after we + called _gdk_windowing_window_destroy(). + (_gdk_windowing_window_destroy() may use GDK functions + on the window.) + + * gdk/x11/gdkinput.c: Remove the check for finalization - + devices can be finalized under some circumnstances. + + * gdk/x11/gdkinput-x11.c (gdk_input_device_new): Fix + small problem with GDK_TYPE_DEVICE. + 2001-07-02 Havoc Pennington <hp@pobox.com> * gdk/x11/gdkwindow-x11.c (gdk_wmspec_change_state): fix to diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index aadd7bd5b3..3f9308e8dd 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,51 @@ +Mon Jul 2 16:53:25 2001 Owen Taylor <otaylor@redhat.com> + + * gtk/xembed.h gtk/gtkplug.c gtk/gtksocket.c: For + XEMBED embedding add a _XEMBED_INFO property to the + client with version number and a "mapped" flags. + Use the mapped flag instead of the racy MapRequestEvent + + * gtk/gtksocket.c: Clean up the gtk_socket_steal() + code to reliably set things (when the child is a passive + embedder participating in the XEMBED protocol) intead + of just being a hack for embedding non-participating + programs. Fix various bugs and race conditions. + + * gtk/gtksocket.[ch] gtk/gtkplug.[ch]: Make local embedding + work by simply making the GtkSocket the gtk parent + of the GtkPlug. Set a flag in this case and make + the GtkPlug work like a normal container by overriding + methods such as check_resize and "chaining past" GtkWindow + to GtkBin. + + * gtk/gtkentry.c (gtk_entry_real_activate) + gtk/gtkmain.c (gtk_propagate_event): + Eliminate use of gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW). + + * gtk/gtkwidget.c (gtk_widget_get_toplevel, + gtk_widget_get_ancestor): + Explain why gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) + might not give the expected result and recommend + an alternative. + + * tests/testsocket.c tests/testsocket_child.c + tests/testsocket_common.c tests/Makefile.am: Extended + to test different type of adding plugs to sockets + (local,active,passive), and to test mapping/unmapping + the plug. + + * gdk/gdkwindow.c (_gdk_window_destroy_hierarchy): Don't + mark the window as destroyed until after we + called _gdk_windowing_window_destroy(). + (_gdk_windowing_window_destroy() may use GDK functions + on the window.) + + * gdk/x11/gdkinput.c: Remove the check for finalization - + devices can be finalized under some circumnstances. + + * gdk/x11/gdkinput-x11.c (gdk_input_device_new): Fix + small problem with GDK_TYPE_DEVICE. + 2001-07-02 Havoc Pennington <hp@pobox.com> * gdk/x11/gdkwindow-x11.c (gdk_wmspec_change_state): fix to diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index aadd7bd5b3..3f9308e8dd 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,51 @@ +Mon Jul 2 16:53:25 2001 Owen Taylor <otaylor@redhat.com> + + * gtk/xembed.h gtk/gtkplug.c gtk/gtksocket.c: For + XEMBED embedding add a _XEMBED_INFO property to the + client with version number and a "mapped" flags. + Use the mapped flag instead of the racy MapRequestEvent + + * gtk/gtksocket.c: Clean up the gtk_socket_steal() + code to reliably set things (when the child is a passive + embedder participating in the XEMBED protocol) intead + of just being a hack for embedding non-participating + programs. Fix various bugs and race conditions. + + * gtk/gtksocket.[ch] gtk/gtkplug.[ch]: Make local embedding + work by simply making the GtkSocket the gtk parent + of the GtkPlug. Set a flag in this case and make + the GtkPlug work like a normal container by overriding + methods such as check_resize and "chaining past" GtkWindow + to GtkBin. + + * gtk/gtkentry.c (gtk_entry_real_activate) + gtk/gtkmain.c (gtk_propagate_event): + Eliminate use of gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW). + + * gtk/gtkwidget.c (gtk_widget_get_toplevel, + gtk_widget_get_ancestor): + Explain why gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) + might not give the expected result and recommend + an alternative. + + * tests/testsocket.c tests/testsocket_child.c + tests/testsocket_common.c tests/Makefile.am: Extended + to test different type of adding plugs to sockets + (local,active,passive), and to test mapping/unmapping + the plug. + + * gdk/gdkwindow.c (_gdk_window_destroy_hierarchy): Don't + mark the window as destroyed until after we + called _gdk_windowing_window_destroy(). + (_gdk_windowing_window_destroy() may use GDK functions + on the window.) + + * gdk/x11/gdkinput.c: Remove the check for finalization - + devices can be finalized under some circumnstances. + + * gdk/x11/gdkinput-x11.c (gdk_input_device_new): Fix + small problem with GDK_TYPE_DEVICE. + 2001-07-02 Havoc Pennington <hp@pobox.com> * gdk/x11/gdkwindow-x11.c (gdk_wmspec_change_state): fix to diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index aadd7bd5b3..3f9308e8dd 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,51 @@ +Mon Jul 2 16:53:25 2001 Owen Taylor <otaylor@redhat.com> + + * gtk/xembed.h gtk/gtkplug.c gtk/gtksocket.c: For + XEMBED embedding add a _XEMBED_INFO property to the + client with version number and a "mapped" flags. + Use the mapped flag instead of the racy MapRequestEvent + + * gtk/gtksocket.c: Clean up the gtk_socket_steal() + code to reliably set things (when the child is a passive + embedder participating in the XEMBED protocol) intead + of just being a hack for embedding non-participating + programs. Fix various bugs and race conditions. + + * gtk/gtksocket.[ch] gtk/gtkplug.[ch]: Make local embedding + work by simply making the GtkSocket the gtk parent + of the GtkPlug. Set a flag in this case and make + the GtkPlug work like a normal container by overriding + methods such as check_resize and "chaining past" GtkWindow + to GtkBin. + + * gtk/gtkentry.c (gtk_entry_real_activate) + gtk/gtkmain.c (gtk_propagate_event): + Eliminate use of gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW). + + * gtk/gtkwidget.c (gtk_widget_get_toplevel, + gtk_widget_get_ancestor): + Explain why gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) + might not give the expected result and recommend + an alternative. + + * tests/testsocket.c tests/testsocket_child.c + tests/testsocket_common.c tests/Makefile.am: Extended + to test different type of adding plugs to sockets + (local,active,passive), and to test mapping/unmapping + the plug. + + * gdk/gdkwindow.c (_gdk_window_destroy_hierarchy): Don't + mark the window as destroyed until after we + called _gdk_windowing_window_destroy(). + (_gdk_windowing_window_destroy() may use GDK functions + on the window.) + + * gdk/x11/gdkinput.c: Remove the check for finalization - + devices can be finalized under some circumnstances. + + * gdk/x11/gdkinput-x11.c (gdk_input_device_new): Fix + small problem with GDK_TYPE_DEVICE. + 2001-07-02 Havoc Pennington <hp@pobox.com> * gdk/x11/gdkwindow-x11.c (gdk_wmspec_change_state): fix to diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index aadd7bd5b3..3f9308e8dd 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,51 @@ +Mon Jul 2 16:53:25 2001 Owen Taylor <otaylor@redhat.com> + + * gtk/xembed.h gtk/gtkplug.c gtk/gtksocket.c: For + XEMBED embedding add a _XEMBED_INFO property to the + client with version number and a "mapped" flags. + Use the mapped flag instead of the racy MapRequestEvent + + * gtk/gtksocket.c: Clean up the gtk_socket_steal() + code to reliably set things (when the child is a passive + embedder participating in the XEMBED protocol) intead + of just being a hack for embedding non-participating + programs. Fix various bugs and race conditions. + + * gtk/gtksocket.[ch] gtk/gtkplug.[ch]: Make local embedding + work by simply making the GtkSocket the gtk parent + of the GtkPlug. Set a flag in this case and make + the GtkPlug work like a normal container by overriding + methods such as check_resize and "chaining past" GtkWindow + to GtkBin. + + * gtk/gtkentry.c (gtk_entry_real_activate) + gtk/gtkmain.c (gtk_propagate_event): + Eliminate use of gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW). + + * gtk/gtkwidget.c (gtk_widget_get_toplevel, + gtk_widget_get_ancestor): + Explain why gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) + might not give the expected result and recommend + an alternative. + + * tests/testsocket.c tests/testsocket_child.c + tests/testsocket_common.c tests/Makefile.am: Extended + to test different type of adding plugs to sockets + (local,active,passive), and to test mapping/unmapping + the plug. + + * gdk/gdkwindow.c (_gdk_window_destroy_hierarchy): Don't + mark the window as destroyed until after we + called _gdk_windowing_window_destroy(). + (_gdk_windowing_window_destroy() may use GDK functions + on the window.) + + * gdk/x11/gdkinput.c: Remove the check for finalization - + devices can be finalized under some circumnstances. + + * gdk/x11/gdkinput-x11.c (gdk_input_device_new): Fix + small problem with GDK_TYPE_DEVICE. + 2001-07-02 Havoc Pennington <hp@pobox.com> * gdk/x11/gdkwindow-x11.c (gdk_wmspec_change_state): fix to diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index aadd7bd5b3..3f9308e8dd 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,51 @@ +Mon Jul 2 16:53:25 2001 Owen Taylor <otaylor@redhat.com> + + * gtk/xembed.h gtk/gtkplug.c gtk/gtksocket.c: For + XEMBED embedding add a _XEMBED_INFO property to the + client with version number and a "mapped" flags. + Use the mapped flag instead of the racy MapRequestEvent + + * gtk/gtksocket.c: Clean up the gtk_socket_steal() + code to reliably set things (when the child is a passive + embedder participating in the XEMBED protocol) intead + of just being a hack for embedding non-participating + programs. Fix various bugs and race conditions. + + * gtk/gtksocket.[ch] gtk/gtkplug.[ch]: Make local embedding + work by simply making the GtkSocket the gtk parent + of the GtkPlug. Set a flag in this case and make + the GtkPlug work like a normal container by overriding + methods such as check_resize and "chaining past" GtkWindow + to GtkBin. + + * gtk/gtkentry.c (gtk_entry_real_activate) + gtk/gtkmain.c (gtk_propagate_event): + Eliminate use of gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW). + + * gtk/gtkwidget.c (gtk_widget_get_toplevel, + gtk_widget_get_ancestor): + Explain why gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) + might not give the expected result and recommend + an alternative. + + * tests/testsocket.c tests/testsocket_child.c + tests/testsocket_common.c tests/Makefile.am: Extended + to test different type of adding plugs to sockets + (local,active,passive), and to test mapping/unmapping + the plug. + + * gdk/gdkwindow.c (_gdk_window_destroy_hierarchy): Don't + mark the window as destroyed until after we + called _gdk_windowing_window_destroy(). + (_gdk_windowing_window_destroy() may use GDK functions + on the window.) + + * gdk/x11/gdkinput.c: Remove the check for finalization - + devices can be finalized under some circumnstances. + + * gdk/x11/gdkinput-x11.c (gdk_input_device_new): Fix + small problem with GDK_TYPE_DEVICE. + 2001-07-02 Havoc Pennington <hp@pobox.com> * gdk/x11/gdkwindow-x11.c (gdk_wmspec_change_state): fix to diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 94d2a39467..81c919bab1 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -293,7 +293,6 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, if (!GDK_WINDOW_DESTROYED (window)) { private->state |= GDK_WINDOW_STATE_WITHDRAWN; - private->destroyed = TRUE; if (private->parent) { @@ -332,6 +331,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, } _gdk_windowing_window_destroy (window, recursing, foreign_destroy); + private->destroyed = TRUE; if (private->filters) { diff --git a/gdk/x11/gdkinput-x11.c b/gdk/x11/gdkinput-x11.c index 1dd32e4a37..dfdae3d949 100644 --- a/gdk/x11/gdkinput-x11.c +++ b/gdk/x11/gdkinput-x11.c @@ -96,7 +96,7 @@ gdk_input_device_new (XDeviceInfo *device, gint include_core) XAnyClassPtr class; gint i,j; - gdkdev = g_object_new (GDK_TYPE_DEVICE_PRIVATE, 1); + gdkdev = g_object_new (GDK_TYPE_DEVICE, NULL); gdkdev->deviceid = device->id; if (device->name[0]) diff --git a/gdk/x11/gdkinput.c b/gdk/x11/gdkinput.c index 2232f584d4..7e952c4492 100644 --- a/gdk/x11/gdkinput.c +++ b/gdk/x11/gdkinput.c @@ -66,18 +66,6 @@ _gdk_init_input_core (void) gdk_core_pointer->keys = NULL; } -static void -gdk_device_finalize (GObject *object) -{ - g_error ("A GdkDevice object was finalized. This should not happen"); -} - -static void -gdk_device_class_init (GObjectClass *class) -{ - class->finalize = gdk_device_finalize; -} - GType gdk_device_get_type (void) { @@ -90,7 +78,7 @@ gdk_device_get_type (void) sizeof (GdkDeviceClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, - (GClassInitFunc) gdk_device_class_init, + (GClassInitFunc) NULL, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GdkDevicePrivate), diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 9eb7fc1280..58c910c961 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -2022,17 +2022,21 @@ static void gtk_entry_real_activate (GtkEntry *entry) { GtkWindow *window; + GtkWidget *toplevel; GtkWidget *widget; widget = GTK_WIDGET (entry); if (entry->activates_default) { - window = (GtkWindow *) gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); + toplevel = gtk_widget_get_toplevel (widget); + if (toplevel && GTK_IS_WINDOW (toplevel)) + { + window = GTK_WINDOW (toplevel); - if (window && - window->default_widget != widget) - gtk_window_activate_default (window); + if (window && window->default_widget != widget) + gtk_window_activate_default (window); + } } } diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 6c7bcd3a1f..a8a6928041 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -1627,9 +1627,8 @@ gtk_propagate_event (GtkWidget *widget, */ GtkWidget *window; - window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); - - if (window) + window = gtk_widget_get_toplevel (widget); + if (window && GTK_IS_WINDOW (window)) { /* If there is a grab within the window, give the grab widget * a first crack at the key event @@ -1639,8 +1638,8 @@ gtk_propagate_event (GtkWidget *widget, if (!handled_event) { - window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); - if (window) + window = gtk_widget_get_toplevel (widget); + if (window && GTK_IS_WINDOW (window)) { if (GTK_WIDGET_IS_SENSITIVE (window)) gtk_widget_event (window, event); diff --git a/gtk/gtkplug.c b/gtk/gtkplug.c index fa2b37c9f2..03d7e22f06 100644 --- a/gtk/gtkplug.c +++ b/gtk/gtkplug.c @@ -27,6 +27,7 @@ #include "gtkmain.h" #include "gtkplug.h" +#include "gtkprivate.h" #include "gdk/gdkkeysyms.h" #include "x11/gdkx.h" @@ -37,6 +38,12 @@ static void gtk_plug_class_init (GtkPlugClass *klass); static void gtk_plug_init (GtkPlug *plug); static void gtk_plug_realize (GtkWidget *widget); static void gtk_plug_unrealize (GtkWidget *widget); +static void gtk_plug_show (GtkWidget *widget); +static void gtk_plug_hide (GtkWidget *widget); +static void gtk_plug_map (GtkWidget *widget); +static void gtk_plug_unmap (GtkWidget *widget); +static void gtk_plug_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); static gboolean gtk_plug_key_press_event (GtkWidget *widget, GdkEventKey *event); static void gtk_plug_forward_key_press (GtkPlug *plug, @@ -45,24 +52,28 @@ static void gtk_plug_set_focus (GtkWindow *window, GtkWidget *focus); static gboolean gtk_plug_focus (GtkWidget *widget, GtkDirectionType direction); +static void gtk_plug_check_resize (GtkContainer *container); static void gtk_plug_accel_entries_changed (GtkWindow *window); static GdkFilterReturn gtk_plug_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data); -static void gtk_plug_free_grabbed_keys (GHashTable *key_table); -static void handle_modality_off (GtkPlug *plug); -static void send_xembed_message (GtkPlug *plug, - glong message, - glong detail, - glong data1, - glong data2, - guint32 time); +static void gtk_plug_free_grabbed_keys (GHashTable *key_table); +static void handle_modality_off (GtkPlug *plug); +static void send_xembed_message (GtkPlug *plug, + glong message, + glong detail, + glong data1, + glong data2, + guint32 time); +static void xembed_set_info (GdkWindow *window, + unsigned long flags); /* From Tk */ #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20 static GtkWindowClass *parent_class = NULL; +static GtkBinClass *bin_class = NULL; GtkType gtk_plug_get_type () @@ -95,14 +106,24 @@ gtk_plug_class_init (GtkPlugClass *class) { GtkWidgetClass *widget_class = (GtkWidgetClass *)class; GtkWindowClass *window_class = (GtkWindowClass *)class; + GtkContainerClass *container_class = (GtkContainerClass *)class; parent_class = gtk_type_class (GTK_TYPE_WINDOW); + bin_class = gtk_type_class (GTK_TYPE_BIN); widget_class->realize = gtk_plug_realize; widget_class->unrealize = gtk_plug_unrealize; widget_class->key_press_event = gtk_plug_key_press_event; - widget_class->focus = gtk_plug_focus; + widget_class->show = gtk_plug_show; + widget_class->hide = gtk_plug_hide; + widget_class->map = gtk_plug_map; + widget_class->unmap = gtk_plug_unmap; + widget_class->size_allocate = gtk_plug_size_allocate; + + widget_class->focus = gtk_plug_focus; + + container_class->check_resize = gtk_plug_check_resize; window_class->set_focus = gtk_plug_set_focus; #if 0 @@ -121,18 +142,79 @@ gtk_plug_init (GtkPlug *plug) window->auto_shrink = TRUE; } +static void +gtk_plug_set_is_child (GtkPlug *plug, + gboolean is_child) +{ + if (is_child) + { + GTK_WIDGET_UNSET_FLAGS (plug, GTK_TOPLEVEL); + GTK_PRIVATE_UNSET_FLAG (plug, GTK_ANCHORED); + gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_PARENT); + } +} + +/** + * _gtk_plug_add_to_socket: + * @plug: a #GtkPlug + * @socket: a #GtkSocket + * + * Add a plug to a socket within the same application. + **/ void -gtk_plug_construct (GtkPlug *plug, GdkNativeWindow socket_id) +_gtk_plug_add_to_socket (GtkPlug *plug, + GtkSocket *socket) +{ + GtkWidget *widget = GTK_WIDGET (plug); + + g_return_if_fail (GTK_IS_PLUG (plug)); + g_return_if_fail (GTK_IS_SOCKET (socket)); + g_return_if_fail (GTK_WIDGET_REALIZED (socket)); + + gtk_plug_set_is_child (plug, TRUE); + plug->same_app = TRUE; + socket->plug_widget = widget; + + gtk_widget_set_parent (widget, GTK_WIDGET (socket)); + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_reparent (widget->window, plug->socket_window, 0, 0); + else + gtk_widget_realize (widget); + + if (GTK_WIDGET_VISIBLE (socket) && GTK_WIDGET_VISIBLE (widget)) + { + if (GTK_WIDGET_MAPPED (socket)) + gtk_widget_map (widget); + + gtk_widget_queue_resize (widget); + } +} + +void +gtk_plug_construct (GtkPlug *plug, + GdkNativeWindow socket_id) { if (socket_id) { + gpointer user_data = NULL; + plug->socket_window = gdk_window_lookup (socket_id); - plug->same_app = TRUE; - if (plug->socket_window == NULL) + if (plug->socket_window) + gdk_window_get_user_data (plug->socket_window, &user_data); + else + plug->socket_window = gdk_window_foreign_new (socket_id); + + if (user_data) { - plug->socket_window = gdk_window_foreign_new (socket_id); - plug->same_app = FALSE; + if (GTK_IS_SOCKET (user_data)) + _gtk_plug_add_to_socket (plug, user_data); + else + { + g_warning (G_STRLOC "Can't create GtkPlug as child of non-GtkSocket"); + plug->socket_window = NULL; + } } } } @@ -164,11 +246,14 @@ gtk_plug_unrealize (GtkWidget *widget) plug->socket_window = NULL; } - if (plug->modality_window) - handle_modality_off (plug); + if (!plug->same_app) + { + if (plug->modality_window) + handle_modality_off (plug); - gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug)); - g_object_unref (plug->modality_group); + gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug)); + g_object_unref (plug->modality_group); + } if (GTK_WIDGET_CLASS (parent_class)->unrealize) (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); @@ -213,29 +298,132 @@ gtk_plug_realize (GtkWidget *widget) attributes_mask |= (window->title ? GDK_WA_TITLE : 0); attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0); - gdk_error_trap_push (); - widget->window = gdk_window_new (plug->socket_window, - &attributes, attributes_mask); - gdk_flush (); - if (gdk_error_trap_pop ()) /* Uh-oh */ + if (GTK_WIDGET_TOPLEVEL (widget)) { gdk_error_trap_push (); - gdk_window_destroy (widget->window); + widget->window = gdk_window_new (plug->socket_window, + &attributes, attributes_mask); gdk_flush (); - gdk_error_trap_pop (); - widget->window = gdk_window_new (NULL, &attributes, attributes_mask); + if (gdk_error_trap_pop ()) /* Uh-oh */ + { + gdk_error_trap_push (); + gdk_window_destroy (widget->window); + gdk_flush (); + gdk_error_trap_pop (); + widget->window = gdk_window_new (NULL, &attributes, attributes_mask); + } + + GDK_WINDOW_TYPE (widget->window) = GDK_WINDOW_TOPLEVEL; + gdk_window_add_filter (widget->window, gtk_plug_filter_func, widget); + + plug->modality_group = gtk_window_group_new (); + gtk_window_group_add_window (plug->modality_group, window); + + xembed_set_info (widget->window, 0); } + else + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - GDK_WINDOW_TYPE (widget->window) = 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 void +gtk_plug_show (GtkWidget *widget) +{ + if (GTK_WIDGET_TOPLEVEL (widget)) + GTK_WIDGET_CLASS (parent_class)->show (widget); + else + GTK_WIDGET_CLASS (bin_class)->show (widget); +} + +static void +gtk_plug_hide (GtkWidget *widget) +{ + if (GTK_WIDGET_TOPLEVEL (widget)) + GTK_WIDGET_CLASS (parent_class)->hide (widget); + else + GTK_WIDGET_CLASS (bin_class)->hide (widget); +} + +/* From gdkinternals.h */ +void gdk_synthesize_window_state (GdkWindow *window, + GdkWindowState unset_flags, + GdkWindowState set_flags); + +static void +gtk_plug_map (GtkWidget *widget) +{ + if (GTK_WIDGET_TOPLEVEL (widget)) + { + GtkBin *bin = GTK_BIN (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + !GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_map (bin->child); + + xembed_set_info (widget->window, XEMBED_MAPPED); + + gdk_synthesize_window_state (widget->window, + GDK_WINDOW_STATE_WITHDRAWN, + 0); + } + else + GTK_WIDGET_CLASS (bin_class)->map (widget); +} + +static void +gtk_plug_unmap (GtkWidget *widget) +{ + if (GTK_WIDGET_TOPLEVEL (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + gdk_window_hide (widget->window); + xembed_set_info (widget->window, 0); + + gdk_synthesize_window_state (widget->window, + 0, + GDK_WINDOW_STATE_WITHDRAWN); + } + else + GTK_WIDGET_CLASS (bin_class)->unmap (widget); +} - gdk_window_add_filter (widget->window, gtk_plug_filter_func, widget); +static void +gtk_plug_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + if (GTK_WIDGET_TOPLEVEL (widget)) + GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation); + else + { + GtkBin *bin = GTK_BIN (widget); + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); - plug->modality_group = gtk_window_group_new (); - gtk_window_group_add_window (plug->modality_group, window); + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + GtkAllocation child_allocation; + + child_allocation.x = child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.width = + MAX (1, (gint)allocation->width - child_allocation.x * 2); + child_allocation.height = + MAX (1, (gint)allocation->height - child_allocation.y * 2); + + gtk_widget_size_allocate (bin->child, &child_allocation); + } + + } } static gboolean @@ -519,6 +707,15 @@ gtk_plug_focus (GtkWidget *widget, } static void +gtk_plug_check_resize (GtkContainer *container) +{ + if (GTK_WIDGET_TOPLEVEL (container)) + GTK_CONTAINER_CLASS (parent_class)->check_resize (container); + else + GTK_CONTAINER_CLASS (bin_class)->check_resize (container); +} + +static void send_xembed_message (GtkPlug *plug, glong message, glong detail, @@ -593,6 +790,25 @@ handle_modality_off (GtkPlug *plug) } static void +xembed_set_info (GdkWindow *gdk_window, + unsigned long flags) +{ + Display *display = GDK_WINDOW_XDISPLAY (gdk_window); + Window window = GDK_WINDOW_XWINDOW (gdk_window); + unsigned long buffer[2]; + + Atom xembed_info_atom = gdk_atom_intern ("_XEMBED_INFO", FALSE); + + buffer[1] = 0; /* Protocol version */ + buffer[1] = flags; + + XChangeProperty (display, window, + xembed_info_atom, xembed_info_atom, 32, + PropModeReplace, + (unsigned char *)buffer, 2); +} + +static void handle_xembed_message (GtkPlug *plug, glong message, glong detail, diff --git a/gtk/gtkplug.h b/gtk/gtkplug.h index 37907574da..d3274c50b4 100644 --- a/gtk/gtkplug.h +++ b/gtk/gtkplug.h @@ -28,6 +28,7 @@ #include <gdk/gdk.h> +#include <gtk/gtksocket.h> #include <gtk/gtkwindow.h> @@ -55,7 +56,7 @@ struct _GtkPlug GdkWindow *socket_window; GtkWidget *modality_window; GtkWindowGroup *modality_group; - gboolean same_app; + guint same_app : 1; }; struct _GtkPlugClass @@ -69,6 +70,9 @@ void gtk_plug_construct (GtkPlug *plug, GdkNativeWindow socket_id); GtkWidget* gtk_plug_new (GdkNativeWindow socket_id); +void _gtk_plug_add_to_socket (GtkPlug *plug, + GtkSocket *socket); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtksocket.c b/gtk/gtksocket.c index f28310bccc..a8e76850b1 100644 --- a/gtk/gtksocket.c +++ b/gtk/gtksocket.c @@ -28,6 +28,7 @@ #include "gdk/gdkkeysyms.h" #include "gtkmain.h" #include "gtkwindow.h" +#include "gtkplug.h" #include "gtksignal.h" #include "gtksocket.h" #include "gtkdnd.h" @@ -38,38 +39,52 @@ /* 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 void gtk_socket_hierarchy_changed (GtkWidget *widget, - GtkWidget *old_toplevel); -static void gtk_socket_grab_notify (GtkWidget *widget, - gboolean was_grabbed); -static gboolean gtk_socket_key_press_event (GtkWidget *widget, - GdkEventKey *event); -static gboolean gtk_socket_focus_in_event (GtkWidget *widget, - GdkEventFocus *event); -static void gtk_socket_claim_focus (GtkSocket *socket); -static gboolean gtk_socket_focus_out_event (GtkWidget *widget, - GdkEventFocus *event); -static void gtk_socket_send_configure_event (GtkSocket *socket); -static gboolean gtk_socket_focus (GtkWidget *widget, - GtkDirectionType direction); -static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent, - GdkEvent *event, - gpointer data); - -static void send_xembed_message (GtkSocket *socket, - glong message, - glong detail, - glong data1, - glong data2, - guint32 time); +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 void gtk_socket_hierarchy_changed (GtkWidget *widget, + GtkWidget *old_toplevel); +static void gtk_socket_grab_notify (GtkWidget *widget, + gboolean was_grabbed); +static gboolean gtk_socket_key_press_event (GtkWidget *widget, + GdkEventKey *event); +static gboolean gtk_socket_focus_in_event (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_socket_claim_focus (GtkSocket *socket); +static gboolean gtk_socket_focus_out_event (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_socket_send_configure_event (GtkSocket *socket); +static gboolean gtk_socket_focus (GtkWidget *widget, + GtkDirectionType direction); +static void gtk_socket_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_socket_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); + + +static void gtk_socket_add_window (GtkSocket *socket, + GdkNativeWindow xid, + gboolean need_reparent); +static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent, + GdkEvent *event, + gpointer data); + +static void send_xembed_message (GtkSocket *socket, + glong message, + glong detail, + glong data1, + glong data2, + guint32 time); +static gboolean xembed_get_info (GdkWindow *gdk_window, + unsigned long *version, + unsigned long *flags); /* From Tk */ #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20 @@ -124,8 +139,10 @@ gtk_socket_class_init (GtkSocketClass *class) widget_class->key_press_event = gtk_socket_key_press_event; widget_class->focus_in_event = gtk_socket_focus_in_event; widget_class->focus_out_event = gtk_socket_focus_out_event; - widget_class->focus = gtk_socket_focus; + + container_class->remove = gtk_socket_remove; + container_class->forall = gtk_socket_forall; } static void @@ -137,7 +154,7 @@ gtk_socket_init (GtkSocket *socket) socket->current_height = 0; socket->plug_window = NULL; - socket->same_app = FALSE; + socket->plug_widget = NULL; socket->focus_in = FALSE; socket->have_size = FALSE; socket->need_map = FALSE; @@ -156,57 +173,7 @@ gtk_socket_new (void) void gtk_socket_steal (GtkSocket *socket, GdkNativeWindow id) { - GtkWidget *widget; - gpointer user_data = NULL; - - widget = GTK_WIDGET (socket); - - socket->plug_window = gdk_window_lookup (id); - - gdk_error_trap_push (); - - if (socket->plug_window) - gdk_window_get_user_data (socket->plug_window, - &user_data); - - if (user_data) - { - /* - GtkWidget *child_widget; - - 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); - if (!socket->plug_window) /* was deleted before we could get it */ - { - gdk_error_trap_pop (); - return; - } - - 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); - - gdk_flush (); - gdk_error_trap_pop (); - - socket->need_map = TRUE; + gtk_socket_add_window (socket, id, TRUE); } static void @@ -307,42 +274,57 @@ gtk_socket_size_request (GtkWidget *widget, socket = GTK_SOCKET (widget); - if (!socket->have_size && socket->plug_window) + if (socket->plug_widget) { - XSizeHints hints; - long supplied; - - gdk_error_trap_push (); - - if (XGetWMNormalHints (GDK_DISPLAY(), - GDK_WINDOW_XWINDOW (socket->plug_window), - &hints, &supplied)) + gtk_widget_size_request (socket->plug_widget, requisition); + } + else + { + if (socket->is_mapped && !socket->have_size && socket->plug_window) { - /* 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) + XSizeHints hints; + long supplied; + + gdk_error_trap_push (); + + if (XGetWMNormalHints (GDK_DISPLAY(), + GDK_WINDOW_XWINDOW (socket->plug_window), + &hints, &supplied)) { - socket->request_width = hints.base_width; - socket->request_height = hints.base_height; + /* 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? */ + + gdk_error_trap_pop (); } - socket->have_size = TRUE; /* don't check again? */ - gdk_error_trap_pop (); + if (socket->is_mapped && socket->have_size) + { + requisition->width = MAX (socket->request_width, 1); + requisition->height = MAX (socket->request_height, 1); + } + else + { + requisition->width = 1; + requisition->height = 1; + } } - - requisition->width = MAX (socket->request_width, 1); - requisition->height = MAX (socket->request_height, 1); } static void @@ -364,7 +346,18 @@ gtk_socket_size_allocate (GtkWidget *widget, allocation->x, allocation->y, allocation->width, allocation->height); - if (socket->plug_window) + if (socket->plug_widget) + { + GtkAllocation child_allocation; + + child_allocation.x = 0; + child_allocation.y = 0; + child_allocation.width = allocation->width; + child_allocation.height = allocation->height; + + gtk_widget_size_allocate (socket->plug_widget, &child_allocation); + } + else if (socket->plug_window) { gdk_error_trap_push (); @@ -652,9 +645,9 @@ gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event) #if 0 GtkWidget *toplevel; - toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); + toplevel = gtk_widget_get_toplevel (widget); - if (toplevel) + if (toplevel && GTK_IS_WINDOW (toplevel)) { XSetInputFocus (GDK_DISPLAY (), GDK_WINDOW_XWINDOW (toplevel->window), @@ -711,6 +704,9 @@ gtk_socket_focus (GtkWidget *widget, GtkDirectionType direction) socket = GTK_SOCKET (widget); + if (socket->plug_widget) + return gtk_widget_child_focus (socket->plug_widget, direction); + if (!GTK_WIDGET_HAS_FOCUS (widget)) { switch (direction) @@ -800,6 +796,39 @@ gtk_socket_focus (GtkWidget *widget, GtkDirectionType direction) } static void +gtk_socket_remove (GtkContainer *container, + GtkWidget *child) +{ + GtkSocket *socket = GTK_SOCKET (container); + gboolean widget_was_visible; + + g_return_if_fail (child == socket->plug_widget); + + widget_was_visible = GTK_WIDGET_VISIBLE (child); + + gtk_widget_unparent (child); + socket->plug_widget = NULL; + + /* queue resize regardless of GTK_WIDGET_VISIBLE (container), + * since that's what is needed by toplevels, which derive from GtkBin. + */ + if (widget_was_visible) + gtk_widget_queue_resize (GTK_WIDGET (container)); +} + +static void +gtk_socket_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GtkSocket *socket = GTK_SOCKET (container); + + if (socket->plug_widget) + (* callback) (socket->plug_widget, callback_data); +} + +static void gtk_socket_send_configure_event (GtkSocket *socket) { XEvent event; @@ -830,30 +859,98 @@ gtk_socket_send_configure_event (GtkSocket *socket) } static void -gtk_socket_add_window (GtkSocket *socket, GdkNativeWindow xid) +gtk_socket_add_window (GtkSocket *socket, + GdkNativeWindow xid, + gboolean need_reparent) { + + GtkWidget *widget = GTK_WIDGET (socket); + gpointer user_data = NULL; + socket->plug_window = gdk_window_lookup (xid); - socket->same_app = TRUE; - if (!socket->plug_window) + if (socket->plug_window) + { + g_object_ref (socket->plug_window); + gdk_window_get_user_data (socket->plug_window, &user_data); + } + + if (user_data) /* A widget's window in this process */ + { + GtkWidget *child_widget = user_data; + + if (!GTK_IS_PLUG (child_widget)) + { + g_warning (G_STRLOC "Can't add non-GtkPlug to GtkSocket"); + socket->plug_window = NULL; + gdk_error_trap_pop (); + + return; + } + + _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket); + } + else /* A foreign window */ { GtkWidget *toplevel; GdkDragProtocol protocol; - - socket->plug_window = gdk_window_foreign_new (xid); - if (!socket->plug_window) /* Already gone */ - return; - - socket->same_app = FALSE; + unsigned long version; + unsigned long flags; gdk_error_trap_push (); + + if (!socket->plug_window) + { + socket->plug_window = gdk_window_foreign_new (xid); + if (!socket->plug_window) /* was deleted before we could get it */ + { + gdk_error_trap_pop (); + return; + } + } + XSelectInput (GDK_DISPLAY (), GDK_WINDOW_XWINDOW(socket->plug_window), StructureNotifyMask | PropertyChangeMask); + if (gdk_error_trap_pop ()) + { + gdk_window_unref (socket->plug_window); + socket->plug_window = NULL; + return; + } + + /* OK, we now will reliably get destroy notification on socket->plug_window */ + + gdk_error_trap_push (); + + if (need_reparent) + { + gdk_window_hide (socket->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */ + gdk_window_reparent (socket->plug_window, widget->window, 0, 0); + } + + socket->have_size = FALSE; + + socket->xembed_version = -1; + if (xembed_get_info (socket->plug_window, &version, &flags)) + { + socket->xembed_version = version; + socket->is_mapped = (flags & XEMBED_MAPPED) != 0; + } + else + { + /* FIXME, we should probably actually check the state before we started */ + + socket->is_mapped = need_reparent ? TRUE : FALSE; + } + + socket->need_map = socket->is_mapped; + if (gdk_drag_get_protocol (xid, &protocol)) gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window, protocol, TRUE); + gdk_flush (); gdk_error_trap_pop (); @@ -864,9 +961,7 @@ gtk_socket_add_window (GtkSocket *socket, GdkNativeWindow xid) toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket)); if (toplevel && GTK_IS_WINDOW (toplevel)) - { - gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid); - } + gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid); gtk_widget_queue_resize (GTK_WIDGET (socket)); } @@ -907,6 +1002,58 @@ send_xembed_message (GtkSocket *socket, } } +static gboolean +xembed_get_info (GdkWindow *gdk_window, + unsigned long *version, + unsigned long *flags) +{ + Display *display = GDK_WINDOW_XDISPLAY (gdk_window); + Window window = GDK_WINDOW_XWINDOW (gdk_window); + Atom xembed_info_atom = gdk_atom_intern ("_XEMBED_INFO", FALSE); + Atom type; + int format; + unsigned long nitems, bytes_after; + unsigned char *data; + unsigned long *data_long; + int status; + + gdk_error_trap_push(); + status = XGetWindowProperty (display, window, + xembed_info_atom, + 0, 2, False, + xembed_info_atom, &type, &format, + &nitems, &bytes_after, &data); + gdk_error_trap_pop(); + + if (status != Success) + return FALSE; /* Window vanished? */ + + if (type == None) /* No info property */ + return FALSE; + + if (type != xembed_info_atom) + { + g_warning ("_XEMBED_INFO property has wrong type\n"); + return FALSE; + } + + if (nitems < 2) + { + g_warning ("_XEMBED_INFO too short\n"); + XFree (data); + return FALSE; + } + + data_long = (unsigned long *)data; + if (version) + *version = data_long[0]; + if (flags) + *flags = data_long[1] & XEMBED_MAPPED; + + XFree (data); + return TRUE; +} + static void handle_xembed_message (GtkSocket *socket, glong message, @@ -962,6 +1109,28 @@ handle_xembed_message (GtkSocket *socket, } } +static void +map_request (GtkSocket *socket) +{ + if (!socket->is_mapped) + { + socket->is_mapped = TRUE; + socket->need_map = TRUE; + + gtk_widget_queue_resize (GTK_WIDGET (socket)); + } +} + +static void +unmap_notify (GtkSocket *socket) +{ + if (socket->is_mapped) + { + socket->is_mapped = FALSE; + gtk_widget_queue_resize (GTK_WIDGET (socket)); + } +} + static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { @@ -977,16 +1146,35 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) return_val = GDK_FILTER_CONTINUE; + if (socket->plug_widget) + return return_val; + switch (xevent->type) { + case ClientMessage: + if (xevent->xclient.message_type == gdk_atom_intern ("_XEMBED", FALSE)) + { + handle_xembed_message (socket, + xevent->xclient.data.l[1], + xevent->xclient.data.l[2], + xevent->xclient.data.l[3], + xevent->xclient.data.l[4], + xevent->xclient.data.l[0]); + + + return_val = GDK_FILTER_REMOVE; + } + break; + case CreateNotify: { XCreateWindowEvent *xcwe = &xevent->xcreatewindow; if (!socket->plug_window) - { - gtk_socket_add_window (socket, xcwe->window); + gtk_socket_add_window (socket, xcwe->window, FALSE); + if (socket->plug_window) + { gdk_error_trap_push (); gdk_window_move_resize(socket->plug_window, 0, 0, @@ -1015,9 +1203,9 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) XConfigureRequestEvent *xcre = &xevent->xconfigurerequest; if (!socket->plug_window) - gtk_socket_add_window (socket, xcre->window); + gtk_socket_add_window (socket, xcre->window, FALSE); - if (xcre->window == GDK_WINDOW_XWINDOW (socket->plug_window)) + if (socket->plug_window) { if (xcre->value_mask & (CWWidth | CWHeight)) { @@ -1047,8 +1235,7 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { XDestroyWindowEvent *xdwe = &xevent->xdestroywindow; - if (socket->plug_window && - (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window))) + if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window))) { GtkWidget *toplevel; @@ -1078,9 +1265,9 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { #if 0 GtkWidget *toplevel; - toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); + toplevel = gtk_widget_get_toplevel (widget); - if (toplevel) + if (toplevel && GTK_IS_WINDOW (topelevel)) { XSetInputFocus (GDK_DISPLAY (), GDK_WINDOW_XWINDOW (toplevel->window), @@ -1095,25 +1282,20 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) break; case MapRequest: if (!socket->plug_window) - gtk_socket_add_window (socket, xevent->xmaprequest.window); + gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE); - if (xevent->xmaprequest.window == - GDK_WINDOW_XWINDOW (socket->plug_window)) + if (socket->plug_window) { GTK_NOTE(PLUGSOCKET, g_message ("GtkSocket - Map Request")); - - gdk_error_trap_push (); - gdk_window_show (socket->plug_window); - gdk_flush (); - gdk_error_trap_pop (); + map_request (socket); return_val = GDK_FILTER_REMOVE; } break; case PropertyNotify: - if (xevent->xproperty.window == - GDK_WINDOW_XWINDOW (socket->plug_window)) + if (socket->plug_window && + xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window)) { GdkDragProtocol protocol; @@ -1128,23 +1310,47 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) gdk_flush (); gdk_error_trap_pop (); } + else if (xevent->xproperty.atom == gdk_atom_intern ("_XEMBED_INFO", FALSE)) + { + unsigned long flags; + + if (xembed_get_info (socket->plug_window, NULL, &flags)) + { + gboolean was_mapped = socket->is_mapped; + gboolean is_mapped = (flags & XEMBED_MAPPED) != 0; + + if (was_mapped != is_mapped) + { + if (is_mapped) + map_request (socket); + else + { + gdk_error_trap_push (); + gdk_window_show (socket->plug_window); + gdk_flush (); + gdk_error_trap_pop (); + + unmap_notify (socket); + } + } + } + } + return_val = GDK_FILTER_REMOVE; } break; - case ClientMessage: - if (xevent->xclient.message_type == gdk_atom_intern ("_XEMBED", FALSE)) + case UnmapNotify: + if (socket->plug_window && + xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window)) { - handle_xembed_message (socket, - xevent->xclient.data.l[1], - xevent->xclient.data.l[2], - xevent->xclient.data.l[3], - xevent->xclient.data.l[4], - xevent->xclient.data.l[0]); - - + GTK_NOTE(PLUGSOCKET, + g_message ("GtkSocket - Unmap notify")); + + unmap_notify (socket); return_val = GDK_FILTER_REMOVE; } break; + } return return_val; diff --git a/gtk/gtksocket.h b/gtk/gtksocket.h index d6dc92d710..18a762bbe9 100644 --- a/gtk/gtksocket.h +++ b/gtk/gtksocket.h @@ -54,10 +54,14 @@ struct _GtkSocket guint16 current_height; GdkWindow *plug_window; + GtkWidget *plug_widget; + + gshort xembed_version; /* -1 == not xembed */ guint same_app : 1; guint focus_in : 1; guint have_size : 1; guint need_map : 1; + guint is_mapped : 1; GHashTable *grabbed_keys; GtkWidget *toplevel; diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 3a2848b521..295855b89f 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -4550,7 +4550,19 @@ gtk_widget_set_extension_events (GtkWidget *widget, * * Note the difference in behavior vs. gtk_widget_get_ancestor(); * gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) would return - * %NULL if @widget wasn't inside a toplevel window. + * %NULL if @widget wasn't inside a toplevel window, and if the + * window was inside a GtkWindow-derived widget which was in turn + * inside the toplevel GtkWindow. While the second case may + * seem unlikely, it actually happens when a GtkPlug is embedded + * inside a GtkSocket within the same application + * + * To reliably find for the toplevel GtkWindow, use + * + * GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + * if (GTK_IS_WINDOW (toplevel)) + * { + * /* Perform action on toplevel. + * } * * Return value: the topmost ancestor of @widget, or @widget itself if there's no ancestor **/ @@ -4574,7 +4586,8 @@ gtk_widget_get_toplevel (GtkWidget *widget) * Gets the first ancestor of @widget with type @widget_type. For example, * gtk_widget_get_ancestor (widget, GTK_TYPE_BOX) gets the first #GtkBox that's * an ancestor of @widget. No reference will be added to the returned widget; - * it should not be unreferenced. + * it should not be unreferenced. See note about checking for a toplevel + * GtkWindow in the docs for gtk_widget_get_toplevel(). * * Return value: the ancestor widget, or %NULL if not found **/ diff --git a/gtk/xembed.h b/gtk/xembed.h index 5c4e35d774..d6de700f2a 100644 --- a/gtk/xembed.h +++ b/gtk/xembed.h @@ -17,3 +17,6 @@ #define XEMBED_FOCUS_FIRST 1 #define XEMBED_FOCUS_LAST 2 + +/* Flags for _XEMBED_INFO */ +#define XEMBED_MAPPED (1 << 0) diff --git a/tests/Makefile.am b/tests/Makefile.am index 061f07133e..47ac8b8096 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -87,6 +87,14 @@ testtext_SOURCES = \ prop-editor.c \ testtext.c +testsocket_SOURCES = \ + testsocket.c \ + testsocket_common.c + +testsocket_child_SOURCES = \ + testsocket_child.c \ + testsocket_common.c + EXTRA_DIST += @STRIP_BEGIN@ \ prop-editor.h \ testgtk.1 \ diff --git a/tests/testsocket.c b/tests/testsocket.c index a775eefd38..ab71501f1e 100644 --- a/tests/testsocket.c +++ b/tests/testsocket.c @@ -10,11 +10,17 @@ #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <unistd.h> + +int n_children = 0; GtkWidget *window; GtkWidget *vbox; GtkWidget *lastsocket = NULL; +extern guint32 create_child_plug (guint32 xid, + gboolean local); + static void quit_cb (gpointer callback_data, guint callback_action, @@ -64,17 +70,66 @@ steal (GtkWidget *window, GtkEntry *entry) void remove_child (GtkWidget *window) { - if(lastsocket) + if (lastsocket) gtk_widget_destroy (lastsocket); lastsocket = NULL; } +static gboolean +child_read_watch (GIOChannel *channel, GIOCondition cond, gpointer data) +{ + GIOStatus status; + GError *error = NULL; + char *line; + gsize term; + int xid; + + status = g_io_channel_read_line (channel, &line, NULL, &term, &error); + switch (status) + { + case G_IO_STATUS_NORMAL: + line[term] = '\0'; + xid = strtol (line, NULL, 0); + if (xid == 0) + { + fprintf (stderr, "Invalid window id '%s'\n", line); + } + else + { + GtkWidget *socket = gtk_socket_new (); + gtk_box_pack_start (GTK_BOX (vbox), socket, TRUE, TRUE, 0); + gtk_widget_show (socket); + + gtk_socket_steal (GTK_SOCKET (socket), xid); + } + g_free (line); + return TRUE; + case G_IO_STATUS_AGAIN: + return TRUE; + case G_IO_STATUS_EOF: + n_children--; + g_io_channel_close (channel); + return FALSE; + case G_IO_STATUS_ERROR: + fprintf (stderr, "Error reading fd from child: %s\n", error->message); + exit (1); + return FALSE; + default: + g_assert_not_reached (); + return FALSE; + } + +} + void -add_child (GtkWidget *window) +add_child (GtkWidget *window, + gboolean active) { GtkWidget *socket; char *argv[3] = { "./testsocket_child", NULL, NULL }; char buffer[20]; + int out_fd; + GIOChannel *channel; GError *error = NULL; socket = gtk_socket_new (); @@ -83,20 +138,61 @@ add_child (GtkWidget *window) lastsocket = socket; - sprintf(buffer, "%#lx", GDK_WINDOW_XWINDOW (socket->window)); - argv[1] = buffer; + if (active) + { + sprintf(buffer, "%#lx", GDK_WINDOW_XWINDOW (socket->window)); + argv[1] = buffer; + } #if 1 - if (!g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error)) + if (!g_spawn_async_with_pipes (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL, &out_fd, NULL, &error)) { fprintf (stderr, "Can't exec testsocket_child: %s\n", error->message); exit (1); } + + n_children++; + channel = g_io_channel_unix_new (out_fd); + g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, &error); + if (error) + { + fprintf (stderr, "Error making channel non-blocking: %s\n", error->message); + exit (1); + } + + g_io_add_watch (channel, G_IO_IN | G_IO_HUP, child_read_watch, NULL); + #else fprintf(stderr,"%s\n", buffer); #endif } +void +add_active_child (GtkWidget *window) +{ + add_child (window, TRUE); +} + +void +add_passive_child (GtkWidget *window) +{ + add_child (window, FALSE); +} + +void +add_local_child (GtkWidget *window) +{ + GtkWidget *socket; + + socket = gtk_socket_new (); + gtk_box_pack_start (GTK_BOX (vbox), socket, TRUE, TRUE, 0); + gtk_widget_show (socket); + + lastsocket = socket; + + create_child_plug (GDK_WINDOW_XWINDOW (socket->window), TRUE); +} + int main (int argc, char *argv[]) { @@ -131,11 +227,25 @@ main (int argc, char *argv[]) gtk_item_factory_get_widget (item_factory, "<main>"), FALSE, FALSE, 0); - button = gtk_button_new_with_label ("Add Child"); + button = gtk_button_new_with_label ("Add Active Child"); gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 0); gtk_signal_connect_object (GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(add_child), + GTK_SIGNAL_FUNC(add_active_child), + GTK_OBJECT(vbox)); + + button = gtk_button_new_with_label ("Add Passive Child"); + gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 0); + + gtk_signal_connect_object (GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(add_passive_child), + GTK_OBJECT(vbox)); + + button = gtk_button_new_with_label ("Add Local Child"); + gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 0); + + gtk_signal_connect_object (GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(add_local_child), GTK_OBJECT(vbox)); button = gtk_button_new_with_label ("Remove Last Child"); @@ -162,7 +272,13 @@ main (int argc, char *argv[]) gtk_main (); - return 0; -} + if (n_children) + { + g_print ("Waiting for children to exit\n"); + while (n_children) + g_main_iteration (TRUE); + } + return 0; +} diff --git a/tests/testsocket_child.c b/tests/testsocket_child.c index 084e71a917..ae24efd892 100644 --- a/tests/testsocket_child.c +++ b/tests/testsocket_child.c @@ -3,84 +3,40 @@ #include <gtk/gtk.h> -void -remove_buttons (GtkWidget *widget, GtkWidget *other_button) -{ - gtk_widget_destroy (other_button); - gtk_widget_destroy (widget); -} - -void -add_buttons (GtkWidget *widget, GtkWidget *box) -{ - GtkWidget *add_button; - GtkWidget *remove_button; - - add_button = gtk_button_new_with_mnemonic ("_Add"); - gtk_box_pack_start (GTK_BOX (box), add_button, TRUE, TRUE, 0); - gtk_widget_show (add_button); - - gtk_signal_connect (GTK_OBJECT (add_button), "clicked", - GTK_SIGNAL_FUNC (add_buttons), - box); - - remove_button = gtk_button_new_with_mnemonic ("_Remove"); - gtk_box_pack_start (GTK_BOX (box), remove_button, TRUE, TRUE, 0); - gtk_widget_show (remove_button); - - gtk_signal_connect (GTK_OBJECT (remove_button), "clicked", - GTK_SIGNAL_FUNC (remove_buttons), - add_button); -} +extern guint32 create_child_plug (guint32 xid, + gboolean local); int main (int argc, char *argv[]) { guint32 xid; + guint32 plug_xid; - GtkWidget *window; - GtkWidget *hbox; - GtkWidget *entry; - GtkWidget *button; gtk_init (&argc, &argv); - if (argc < 2) + if (argc != 1 && argc != 2) { - fprintf (stderr, "Usage: testsocket_child WINDOW_ID\n"); + fprintf (stderr, "Usage: testsocket_child [WINDOW_ID]\n"); exit (1); } - xid = strtol (argv[1], NULL, 0); - if (xid == 0) + if (argc == 2) { - fprintf (stderr, "Invalid window id '%s'\n", argv[1]); - exit (1); + xid = strtol (argv[1], NULL, 0); + if (xid == 0) + { + fprintf (stderr, "Invalid window id '%s'\n", argv[1]); + exit (1); + } + + create_child_plug (xid, FALSE); + } + else + { + plug_xid = create_child_plug (0, FALSE); + printf ("%d\n", plug_xid); + fflush (stdout); } - - window = gtk_plug_new (xid); - gtk_signal_connect (GTK_OBJECT (window), "destroy", - (GtkSignalFunc) gtk_exit, NULL); - gtk_container_set_border_width (GTK_CONTAINER (window), 0); - - hbox = gtk_hbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (window), hbox); - gtk_widget_show (hbox); - - entry = gtk_entry_new (); - gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); - gtk_widget_show (entry); - - button = gtk_button_new_with_mnemonic ("_Close"); - gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); - gtk_widget_show (button); - - gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - GTK_OBJECT (window)); - - add_buttons (NULL, hbox); - - gtk_widget_show (window); gtk_main (); |