diff options
author | Owen Taylor <otaylor@redhat.com> | 2001-07-03 14:14:30 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2001-07-03 14:14:30 +0000 |
commit | f409cd9b7f6513acf816e5b3335231bc733f29a6 (patch) | |
tree | 1df2a5203199c8007960dacf78154650698f0a97 /gtk/gtkplug.c | |
parent | b6cc525fa098f0cade116e0dc29e5614237d48ab (diff) | |
download | gtk+-f409cd9b7f6513acf816e5b3335231bc733f29a6.tar.gz |
For XEMBED embedding add a _XEMBED_INFO property to the client with
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.
Diffstat (limited to 'gtk/gtkplug.c')
-rw-r--r-- | gtk/gtkplug.c | 276 |
1 files changed, 246 insertions, 30 deletions
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, |