diff options
Diffstat (limited to 'gtk')
-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 |
8 files changed, 648 insertions, 199 deletions
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) |